@qodalis/cli 2.3.0 → 2.4.1

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/public-api.js CHANGED
@@ -519,7 +519,7 @@ var CliKeyValueStore_TOKEN = cliCore.createCliToken("cli-key-value-store");
519
519
  var SyntaxHighlighterRegistry_TOKEN = cliCore.createCliToken("syntax-highlighter-registry");
520
520
 
521
521
  // src/lib/version.ts
522
- var LIBRARY_VERSION = "2.3.0";
522
+ var LIBRARY_VERSION = "2.4.1";
523
523
  var API_VERSION = 2;
524
524
  var ANONYMOUS = "\0anonymous";
525
525
  function aliasOwner(context2) {
@@ -11188,7 +11188,78 @@ var CliServicesCommandProcessor = class {
11188
11188
  );
11189
11189
  }
11190
11190
  };
11191
+ var CLI_EVENT_HISTORY_SIZE = 200;
11192
+ function matchesEventPattern(type, pattern) {
11193
+ if (pattern === "*") return true;
11194
+ if (pattern.endsWith(":*")) {
11195
+ return type.startsWith(pattern.slice(0, -1));
11196
+ }
11197
+ return type === pattern;
11198
+ }
11199
+ var CliEventBus = class {
11200
+ constructor(onHandlerError = (error) => console.error("[CLI] Event handler failed:", error), historySize = CLI_EVENT_HISTORY_SIZE) {
11201
+ this.onHandlerError = onHandlerError;
11202
+ this.historySize = historySize;
11203
+ this.subject = new rxjs.Subject();
11204
+ this.recent = [];
11205
+ this.disposed = false;
11206
+ }
11207
+ emit(type, data, options) {
11208
+ if (this.disposed) return;
11209
+ const event = {
11210
+ type,
11211
+ data,
11212
+ source: options?.source,
11213
+ timestamp: Date.now()
11214
+ };
11215
+ this.recent.push(event);
11216
+ if (this.recent.length > this.historySize) {
11217
+ this.recent.shift();
11218
+ }
11219
+ this.subject.next(event);
11220
+ }
11221
+ on(pattern, handler) {
11222
+ const subscription = this.events$(pattern).subscribe((event) => {
11223
+ try {
11224
+ handler(event);
11225
+ } catch (error) {
11226
+ this.onHandlerError(error, event);
11227
+ }
11228
+ });
11229
+ return () => subscription.unsubscribe();
11230
+ }
11231
+ once(pattern, handler) {
11232
+ let done = false;
11233
+ const unsubscribe = this.on(pattern, (event) => {
11234
+ if (done) return;
11235
+ done = true;
11236
+ unsubscribe();
11237
+ handler(event);
11238
+ });
11239
+ return unsubscribe;
11240
+ }
11241
+ events$(pattern = "*") {
11242
+ return this.subject.asObservable().pipe(operators.filter((event) => matchesEventPattern(event.type, pattern)));
11243
+ }
11244
+ history(pattern = "*", limit) {
11245
+ const matching = this.recent.filter(
11246
+ (event) => matchesEventPattern(event.type, pattern)
11247
+ );
11248
+ return limit !== void 0 ? matching.slice(-limit) : matching;
11249
+ }
11250
+ /** Stop delivering events and complete all observables. */
11251
+ dispose() {
11252
+ if (this.disposed) return;
11253
+ this.disposed = true;
11254
+ this.subject.complete();
11255
+ this.recent.length = 0;
11256
+ }
11257
+ };
11258
+
11259
+ // src/lib/processors/system/cli-events-command-processor.ts
11191
11260
  var DATA_PREVIEW_LENGTH = 120;
11261
+ var SERVER_EVENT = "server:event";
11262
+ var SERVER_ENVELOPE_FIELDS = /* @__PURE__ */ new Set(["type", "timestamp"]);
11192
11263
  var RESERVED_NAMESPACES = [
11193
11264
  "boot",
11194
11265
  "command",
@@ -11200,26 +11271,83 @@ var RESERVED_NAMESPACES = [
11200
11271
  "session",
11201
11272
  "user"
11202
11273
  ];
11274
+ function serverEventOf(event) {
11275
+ return event.type === SERVER_EVENT ? event.data : void 0;
11276
+ }
11277
+ function matchesFilter(event, filter2) {
11278
+ const remote = serverEventOf(event);
11279
+ if (!remote) {
11280
+ return !filter2.server && matchesEventPattern(event.type, filter2.pattern);
11281
+ }
11282
+ if (filter2.local) return false;
11283
+ if (filter2.server && remote.server.toLowerCase() !== filter2.server.toLowerCase()) return false;
11284
+ return matchesEventPattern(remote.type, filter2.pattern) || matchesEventPattern(SERVER_EVENT, filter2.pattern);
11285
+ }
11203
11286
  function canSee(event, context2) {
11204
11287
  return !event.type.startsWith("user:") || cliCore.cliAuthorize(context2, cliCore.CliUsersPermissions.AuditRead);
11205
11288
  }
11289
+ function formatServerEventFields(data) {
11290
+ if (!data || typeof data !== "object") return "";
11291
+ const parts = [];
11292
+ for (const [key, value] of Object.entries(data)) {
11293
+ if (SERVER_ENVELOPE_FIELDS.has(key) || value === void 0 || value === null) continue;
11294
+ const text = typeof value === "string" ? value : JSON.stringify(value);
11295
+ parts.push(`${key}=${/\s/.test(text) ? JSON.stringify(text) : text}`);
11296
+ }
11297
+ return shorten(parts.join(" "));
11298
+ }
11299
+ function shorten(text) {
11300
+ return text.length > DATA_PREVIEW_LENGTH ? `${text.slice(0, DATA_PREVIEW_LENGTH - 1)}\u2026` : text;
11301
+ }
11206
11302
  function formatEvent(event, context2) {
11207
11303
  const { writer } = context2;
11208
- const time = new Date(event.timestamp).toISOString().slice(11, 23);
11209
- const source = event.source ? ` ${writer.wrapInColor(`[${event.source}]`, cliCore.CliForegroundColor.Blue)}` : "";
11304
+ const remote = serverEventOf(event);
11305
+ let time = event.timestamp;
11306
+ let type = event.type;
11307
+ let source = event.source;
11210
11308
  let data = "";
11211
- if (event.data !== void 0) {
11309
+ if (remote) {
11310
+ const sent = remote.data?.timestamp;
11311
+ if (typeof sent === "string" && !isNaN(Date.parse(sent))) time = sent;
11312
+ type = remote.type;
11313
+ source = remote.server;
11314
+ data = formatServerEventFields(remote.data);
11315
+ } else if (event.data !== void 0) {
11212
11316
  try {
11213
11317
  data = JSON.stringify(event.data) ?? "";
11214
11318
  } catch {
11215
11319
  data = String(event.data);
11216
11320
  }
11217
- if (data.length > DATA_PREVIEW_LENGTH) {
11218
- data = `${data.slice(0, DATA_PREVIEW_LENGTH - 1)}\u2026`;
11219
- }
11321
+ data = shorten(data);
11220
11322
  }
11221
- return `${writer.wrapInColor(time, cliCore.CliForegroundColor.Yellow)} ${writer.wrapInColor(event.type, cliCore.CliForegroundColor.Cyan)}${source}${data ? ` ${data}` : ""}`;
11323
+ const when = new Date(time).toISOString().slice(11, 23);
11324
+ const from = source ? ` ${writer.wrapInColor(`[${source}]`, remote ? cliCore.CliForegroundColor.Magenta : cliCore.CliForegroundColor.Blue)}` : "";
11325
+ return `${writer.wrapInColor(when, cliCore.CliForegroundColor.Yellow)} ${writer.wrapInColor(type, cliCore.CliForegroundColor.Cyan)}${from}${data ? ` ${data}` : ""}`;
11222
11326
  }
11327
+ function filterOf(command2) {
11328
+ const server = command2.args["server"] ?? command2.args["s"];
11329
+ return {
11330
+ pattern: cliCore.joinShellWords(command2.value ?? "") || "*",
11331
+ server: server === void 0 || server === true ? void 0 : String(server),
11332
+ local: !!(command2.args["local"] || command2.args["l"])
11333
+ };
11334
+ }
11335
+ var FILTER_PARAMETERS = [
11336
+ {
11337
+ name: "server",
11338
+ aliases: ["s"],
11339
+ type: "string",
11340
+ description: "Only the events of this server",
11341
+ required: false
11342
+ },
11343
+ {
11344
+ name: "local",
11345
+ aliases: ["l"],
11346
+ type: "boolean",
11347
+ description: "Only the terminal's own events",
11348
+ required: false
11349
+ }
11350
+ ];
11223
11351
  function busOf(context2) {
11224
11352
  if (!context2.events) {
11225
11353
  context2.writer.writeError(
@@ -11231,7 +11359,7 @@ function busOf(context2) {
11231
11359
  var CliEventsCommandProcessor = class {
11232
11360
  constructor() {
11233
11361
  this.command = "events";
11234
- this.description = "Watch, list and emit events on the event bus";
11362
+ this.description = "Watch, list and emit events of the terminal and the connected servers";
11235
11363
  this.author = cliCore.DefaultLibraryAuthor;
11236
11364
  this.version = "1.0.0";
11237
11365
  this.metadata = {
@@ -11244,16 +11372,17 @@ var CliEventsCommandProcessor = class {
11244
11372
  command: "watch",
11245
11373
  description: "Print events as they happen (Ctrl+C to stop)",
11246
11374
  acceptsRawInput: true,
11375
+ parameters: FILTER_PARAMETERS,
11247
11376
  processCommand: async (command2, context2) => {
11248
11377
  const bus = busOf(context2);
11249
11378
  if (!bus) return;
11250
- const pattern = cliCore.joinShellWords(command2.value ?? "") || "*";
11379
+ const filter2 = filterOf(command2);
11251
11380
  context2.writer.writeInfo(
11252
- `Watching ${context2.writer.wrapInColor(pattern, cliCore.CliForegroundColor.Cyan)} \u2014 press Ctrl+C to stop`
11381
+ `Watching ${context2.writer.wrapInColor(filter2.pattern, cliCore.CliForegroundColor.Cyan)} \u2014 press Ctrl+C to stop`
11253
11382
  );
11254
11383
  await new Promise((resolve) => {
11255
- const off = bus.on(pattern, (event) => {
11256
- if (canSee(event, context2)) {
11384
+ const off = bus.on("*", (event) => {
11385
+ if (matchesFilter(event, filter2) && canSee(event, context2)) {
11257
11386
  context2.writer.writeln(formatEvent(event, context2));
11258
11387
  }
11259
11388
  });
@@ -11279,6 +11408,12 @@ var CliEventsCommandProcessor = class {
11279
11408
  context2.writer.writeln(
11280
11409
  ` events watch boot:completed ${t.t("cli.events.watch.help.one_type", "One type")}`
11281
11410
  );
11411
+ context2.writer.writeln(
11412
+ ` events watch job:* -s node ${t.t("cli.events.watch.help.server_jobs", "Job events of the server node")}`
11413
+ );
11414
+ context2.writer.writeln(
11415
+ ` events watch --local ${t.t("cli.events.watch.help.local_only", "Only the terminal's own events")}`
11416
+ );
11282
11417
  }
11283
11418
  },
11284
11419
  {
@@ -11287,6 +11422,7 @@ var CliEventsCommandProcessor = class {
11287
11422
  description: "Show recent events (kept in memory, not persisted)",
11288
11423
  acceptsRawInput: true,
11289
11424
  parameters: [
11425
+ ...FILTER_PARAMETERS,
11290
11426
  {
11291
11427
  name: "limit",
11292
11428
  aliases: ["n"],
@@ -11298,13 +11434,13 @@ var CliEventsCommandProcessor = class {
11298
11434
  processCommand: async (command2, context2) => {
11299
11435
  const bus = busOf(context2);
11300
11436
  if (!bus) return;
11301
- const pattern = cliCore.joinShellWords(command2.value ?? "") || "*";
11437
+ const filter2 = filterOf(command2);
11302
11438
  const limit = Number(
11303
11439
  command2.args["limit"] ?? command2.args["n"] ?? 20
11304
11440
  );
11305
- const events = bus.history(pattern).filter((event) => canSee(event, context2)).slice(-(limit > 0 ? limit : 20));
11441
+ const events = bus.history("*").filter((event) => matchesFilter(event, filter2) && canSee(event, context2)).slice(-(limit > 0 ? limit : 20));
11306
11442
  if (events.length === 0) {
11307
- context2.writer.writeInfo(`No events matching ${pattern}`);
11443
+ context2.writer.writeInfo(`No events matching ${filter2.pattern}`);
11308
11444
  return;
11309
11445
  }
11310
11446
  for (const event of events) {
@@ -11323,6 +11459,9 @@ var CliEventsCommandProcessor = class {
11323
11459
  context2.writer.writeln(
11324
11460
  ` events log server:* -n 50 ${t.t("cli.events.log.help.last_50_server", "Last 50 server events")}`
11325
11461
  );
11462
+ context2.writer.writeln(
11463
+ ` events log job:failed ${t.t("cli.events.log.help.failed_jobs", "Recent failed job runs, on every server")}`
11464
+ );
11326
11465
  }
11327
11466
  },
11328
11467
  {
@@ -11394,6 +11533,9 @@ var CliEventsCommandProcessor = class {
11394
11533
  writer.writeln(
11395
11534
  t.t("cli.events.help.patterns", "Patterns: an exact type (package:installed), a namespace (package:*) or * for all.")
11396
11535
  );
11536
+ writer.writeln(
11537
+ t.t("cli.events.help.servers", "Events of the connected servers (job runs, user, token and file changes, ...) are shown with the server name; each server sends only the events you may see. Filter with --server <name>, or --local for the terminal's own events.")
11538
+ );
11397
11539
  writer.writeln(
11398
11540
  t.t("cli.events.help.in_memory", "Events are kept in memory for this terminal only; nothing is persisted.")
11399
11541
  );
@@ -14701,6 +14843,7 @@ var CliTerminalSpinner = class {
14701
14843
  }, 80);
14702
14844
  }
14703
14845
  hide() {
14846
+ if (!this.isRunning) return;
14704
14847
  this.isRunning = false;
14705
14848
  if (this.spinnerInterval) {
14706
14849
  clearInterval(this.spinnerInterval);
@@ -20063,8 +20206,8 @@ var CliBootLog = class {
20063
20206
  if (this.problems.length > 0) {
20064
20207
  this.terminal.write("\r\n");
20065
20208
  }
20066
- if (this.captured.length > 0) {
20067
- const output2 = this.captured.join("").replace(/(?:\s|\x1b\[[0-9;?]*[A-Za-z])+$/, "");
20209
+ const output2 = this.captured.join("").replace(/(?:\s|\x1b\[[0-9;?]*[A-Za-z])+$/, "");
20210
+ if (output2) {
20068
20211
  this.terminal.write(output2 + RESET4 + "\r\n\r\n");
20069
20212
  }
20070
20213
  }
@@ -21999,73 +22142,6 @@ function createServerModule() {
21999
22142
  services: []
22000
22143
  };
22001
22144
  }
22002
- var CLI_EVENT_HISTORY_SIZE = 200;
22003
- function matchesEventPattern(type, pattern) {
22004
- if (pattern === "*") return true;
22005
- if (pattern.endsWith(":*")) {
22006
- return type.startsWith(pattern.slice(0, -1));
22007
- }
22008
- return type === pattern;
22009
- }
22010
- var CliEventBus = class {
22011
- constructor(onHandlerError = (error) => console.error("[CLI] Event handler failed:", error), historySize = CLI_EVENT_HISTORY_SIZE) {
22012
- this.onHandlerError = onHandlerError;
22013
- this.historySize = historySize;
22014
- this.subject = new rxjs.Subject();
22015
- this.recent = [];
22016
- this.disposed = false;
22017
- }
22018
- emit(type, data, options) {
22019
- if (this.disposed) return;
22020
- const event = {
22021
- type,
22022
- data,
22023
- source: options?.source,
22024
- timestamp: Date.now()
22025
- };
22026
- this.recent.push(event);
22027
- if (this.recent.length > this.historySize) {
22028
- this.recent.shift();
22029
- }
22030
- this.subject.next(event);
22031
- }
22032
- on(pattern, handler) {
22033
- const subscription = this.events$(pattern).subscribe((event) => {
22034
- try {
22035
- handler(event);
22036
- } catch (error) {
22037
- this.onHandlerError(error, event);
22038
- }
22039
- });
22040
- return () => subscription.unsubscribe();
22041
- }
22042
- once(pattern, handler) {
22043
- let done = false;
22044
- const unsubscribe = this.on(pattern, (event) => {
22045
- if (done) return;
22046
- done = true;
22047
- unsubscribe();
22048
- handler(event);
22049
- });
22050
- return unsubscribe;
22051
- }
22052
- events$(pattern = "*") {
22053
- return this.subject.asObservable().pipe(operators.filter((event) => matchesEventPattern(event.type, pattern)));
22054
- }
22055
- history(pattern = "*", limit) {
22056
- const matching = this.recent.filter(
22057
- (event) => matchesEventPattern(event.type, pattern)
22058
- );
22059
- return limit !== void 0 ? matching.slice(-limit) : matching;
22060
- }
22061
- /** Stop delivering events and complete all observables. */
22062
- dispose() {
22063
- if (this.disposed) return;
22064
- this.disposed = true;
22065
- this.subject.complete();
22066
- this.recent.length = 0;
22067
- }
22068
- };
22069
22145
 
22070
22146
  // src/lib/editor/syntax/registry.ts
22071
22147
  var SyntaxHighlighterRegistry = class {
@@ -23867,6 +23943,7 @@ function computeGlobalStatus(engine, now = Date.now()) {
23867
23943
  total: services.length
23868
23944
  };
23869
23945
  serviceDetails = services.map((s) => ({
23946
+ pid: s.pid,
23870
23947
  name: s.name,
23871
23948
  status: s.status,
23872
23949
  description: s.description
@@ -23913,6 +23990,15 @@ function computeGlobalStatus(engine, now = Date.now()) {
23913
23990
  const uptime = engine.startedAt ? now - engine.startedAt : 0;
23914
23991
  return { serviceCount, serviceDetails, serverState, serverDetails, uptime };
23915
23992
  }
23993
+ function killProcess(engine, pid) {
23994
+ const context2 = engine?.getContext();
23995
+ let registry;
23996
+ try {
23997
+ registry = context2?.services?.get?.(CliProcessRegistry_TOKEN);
23998
+ } catch {
23999
+ }
24000
+ return registry?.kill(pid) ?? false;
24001
+ }
23916
24002
  var CliPanelStatusTracker = class {
23917
24003
  constructor(listener) {
23918
24004
  this.listener = listener;
@@ -23977,6 +24063,11 @@ var CliPanelStatusTracker = class {
23977
24063
  this.activeTabId = tabId;
23978
24064
  this.refreshGlobal();
23979
24065
  }
24066
+ /** The engine the global status (services, servers) is computed from: the first pane of the active tab. */
24067
+ get globalEngine() {
24068
+ const entry = this.activeTabId != null ? this.tabs.get(this.activeTabId) : void 0;
24069
+ return entry?.engines.values().next().value;
24070
+ }
23980
24071
  /** Recompute everything now. */
23981
24072
  refresh() {
23982
24073
  for (const tabId of this.tabs.keys()) this.refreshTab(tabId);
@@ -24013,9 +24104,7 @@ var CliPanelStatusTracker = class {
24013
24104
  this.listener.onTabStatus(tabId, next);
24014
24105
  }
24015
24106
  refreshGlobal() {
24016
- const entry = this.activeTabId != null ? this.tabs.get(this.activeTabId) : void 0;
24017
- const engine = entry?.engines.values().next().value;
24018
- const next = computeGlobalStatus(engine);
24107
+ const next = computeGlobalStatus(this.globalEngine);
24019
24108
  if (sameJson(next, this.globalStatus)) return;
24020
24109
  this.globalStatus = next;
24021
24110
  this.listener.onGlobalStatus(next);
@@ -24497,6 +24586,16 @@ var CliPanelController = class {
24497
24586
  serversDropdownOpen: false
24498
24587
  });
24499
24588
  }
24589
+ /**
24590
+ * Stop a running background service listed in the services dropdown, as
24591
+ * `kill <pid>` does; the list refreshes. False when nothing was running
24592
+ * under that pid.
24593
+ */
24594
+ killProcess(pid) {
24595
+ const killed = killProcess(this.tracker.globalEngine, pid);
24596
+ if (killed) this.tracker.refresh();
24597
+ return killed;
24598
+ }
24500
24599
  /** `anchor` is the clicked status item; the dropdown is placed next to it. */
24501
24600
  toggleServicesDropdown(anchor) {
24502
24601
  const open = !this.snapshot.servicesDropdownOpen;
@@ -24925,6 +25024,7 @@ var PANEL_LABELS = {
24925
25024
  closePane: "Close pane",
24926
25025
  servicesHeader: "Background Services",
24927
25026
  servicesEmpty: "No services registered",
25027
+ stopService: "Stop",
24928
25028
  serversHeader: "Server Connections",
24929
25029
  serversEmpty: "No servers configured"
24930
25030
  };
@@ -25105,7 +25205,8 @@ function openStatusDropdown(s) {
25105
25205
  name: svc.name,
25106
25206
  description: svc.description,
25107
25207
  status: svc.status,
25108
- meta: []
25208
+ meta: [],
25209
+ stop: svc.status === "running" && svc.pid !== void 0 ? { pid: svc.pid, label: PANEL_LABELS.stopService, title: `${PANEL_LABELS.stopService} ${svc.name} (kill ${svc.pid})` } : void 0
25109
25210
  }))
25110
25211
  };
25111
25212
  }
@@ -25315,6 +25416,7 @@ exports.initializeTerminal = initializeTerminal;
25315
25416
  exports.isHorizontalPosition = isHorizontalPosition;
25316
25417
  exports.isWasmAccelerated = isWasmAccelerated;
25317
25418
  exports.joinClasses = joinClasses;
25419
+ exports.killProcess = killProcess;
25318
25420
  exports.matchGlob = matchGlob;
25319
25421
  exports.mergeCliOptions = mergeCliOptions;
25320
25422
  exports.miscProcessors = miscProcessors;