labgate 0.5.42 → 0.5.43

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/dist/lib/ui.js CHANGED
@@ -63,6 +63,7 @@ const explorer_eval_js_1 = require("./explorer-eval.js");
63
63
  const explorer_store_js_1 = require("./explorer-store.js");
64
64
  const feedback_js_1 = require("./feedback.js");
65
65
  const automation_engine_js_1 = require("./automation-engine.js");
66
+ const update_check_js_1 = require("./update-check.js");
66
67
  const log = __importStar(require("./log.js"));
67
68
  const execFileAsync = (0, util_1.promisify)(child_process_1.execFile);
68
69
  const HTML_PATH = (0, path_1.resolve)(__dirname, '..', 'lib', 'ui.html');
@@ -86,7 +87,6 @@ const PODMAN_SETUP_MAX_BUFFER = 16 * 1024 * 1024;
86
87
  const EXPLORER_TSP_TEMPLATE_DIR = (0, path_1.resolve)(__dirname, '..', '..', 'templates', 'tsp-lab');
87
88
  const EXPLORER_TSP_TEMPLATE_SOURCE_REPO = (0, path_1.join)((0, config_js_1.getExplorerRootDir)(), 'templates', 'tsp-lab-source');
88
89
  const EXPLORER_ARTIFACT_READ_MAX_BYTES = 2 * 1024 * 1024;
89
- const UI_VERSION_NPM_PACKAGE = 'labgate';
90
90
  const UI_VERSION_CHECK_TIMEOUT_MS = 8_000;
91
91
  const UI_VERSION_CHECK_MAX_BUFFER = 256 * 1024;
92
92
  const UI_VERSION_CACHE_TTL_MS = 5 * 60 * 1000;
@@ -261,29 +261,6 @@ function readPackageVersion() {
261
261
  return '0.0.0';
262
262
  }
263
263
  }
264
- function stripVersionPrefix(raw) {
265
- return String(raw || '').trim().replace(/^v/i, '');
266
- }
267
- function parseSemverTriplet(version) {
268
- const normalized = stripVersionPrefix(version).split('-', 1)[0];
269
- const match = normalized.match(/^(\d+)\.(\d+)\.(\d+)$/);
270
- if (!match)
271
- return null;
272
- return [Number(match[1]), Number(match[2]), Number(match[3])];
273
- }
274
- function compareSemverStrings(a, b) {
275
- const left = parseSemverTriplet(a);
276
- const right = parseSemverTriplet(b);
277
- if (!left || !right)
278
- return null;
279
- for (let i = 0; i < 3; i += 1) {
280
- if (left[i] > right[i])
281
- return 1;
282
- if (left[i] < right[i])
283
- return -1;
284
- }
285
- return 0;
286
- }
287
264
  function getUiBuildId() {
288
265
  try {
289
266
  const st = (0, fs_1.statSync)(HTML_PATH);
@@ -293,77 +270,11 @@ function getUiBuildId() {
293
270
  return `${LABGATE_UI_VERSION}:unknown`;
294
271
  }
295
272
  }
296
- function normalizeNpmVersionValue(raw) {
297
- if (typeof raw === 'string') {
298
- const cleaned = stripVersionPrefix(raw).trim();
299
- return cleaned || null;
300
- }
301
- if (Array.isArray(raw)) {
302
- const versions = raw
303
- .map((entry) => normalizeNpmVersionValue(entry))
304
- .filter((entry) => !!entry);
305
- if (versions.length === 0)
306
- return null;
307
- const sorted = [...versions].sort((a, b) => {
308
- const cmp = compareSemverStrings(a, b);
309
- if (cmp !== null)
310
- return cmp;
311
- return a.localeCompare(b);
312
- });
313
- return sorted[sorted.length - 1] || null;
314
- }
315
- return null;
316
- }
317
- function parseNpmVersionOutput(rawOutput) {
318
- const text = String(rawOutput || '').trim();
319
- if (!text)
320
- return null;
321
- try {
322
- return normalizeNpmVersionValue(JSON.parse(text));
323
- }
324
- catch {
325
- const cleaned = stripVersionPrefix(text.replace(/^"+|"+$/g, '').trim());
326
- return cleaned || null;
327
- }
328
- }
329
- function summarizeCommandError(err) {
330
- const detail = commandErrorDetail(err);
331
- const firstLine = detail
332
- .split('\n')
333
- .map((line) => line.trim())
334
- .find((line) => line.length > 0);
335
- if (!firstLine)
336
- return 'Could not reach npm registry.';
337
- return firstLine.length > 180 ? `${firstLine.slice(0, 177)}...` : firstLine;
338
- }
339
273
  async function fetchPublishedUiVersion() {
340
- const checkedAt = new Date().toISOString();
341
- try {
342
- const result = await execFileAsync('npm', ['view', UI_VERSION_NPM_PACKAGE, 'version', '--json'], {
343
- timeout: UI_VERSION_CHECK_TIMEOUT_MS,
344
- maxBuffer: UI_VERSION_CHECK_MAX_BUFFER,
345
- });
346
- const latestVersion = parseNpmVersionOutput(String(result?.stdout || ''));
347
- if (!latestVersion) {
348
- return {
349
- latestVersion: null,
350
- checkedAt,
351
- error: 'npm returned an unreadable version.',
352
- };
353
- }
354
- return {
355
- latestVersion,
356
- checkedAt,
357
- error: null,
358
- };
359
- }
360
- catch (err) {
361
- return {
362
- latestVersion: null,
363
- checkedAt,
364
- error: summarizeCommandError(err),
365
- };
366
- }
274
+ return (0, update_check_js_1.fetchPublishedNpmVersion)(update_check_js_1.LABGATE_NPM_PACKAGE, {
275
+ timeoutMs: UI_VERSION_CHECK_TIMEOUT_MS,
276
+ maxBuffer: UI_VERSION_CHECK_MAX_BUFFER,
277
+ });
367
278
  }
368
279
  async function getPublishedUiVersionCached(force = false) {
369
280
  const now = Date.now();
@@ -467,13 +378,13 @@ function runUiSelfUpdate() {
467
378
  status: 'running',
468
379
  startedAt,
469
380
  finishedAt: null,
470
- message: `Installing ${UI_VERSION_NPM_PACKAGE}@latest...`,
381
+ message: `Installing ${update_check_js_1.LABGATE_NPM_PACKAGE}@latest...`,
471
382
  error: null,
472
383
  latestVersion: null,
473
384
  };
474
385
  uiSelfUpdatePromise = (async () => {
475
386
  try {
476
- await execFileAsync('npm', ['install', '-g', `${UI_VERSION_NPM_PACKAGE}@latest`], {
387
+ await execFileAsync('npm', ['install', '-g', `${update_check_js_1.LABGATE_NPM_PACKAGE}@latest`], {
477
388
  timeout: UI_SELF_UPDATE_TIMEOUT_MS,
478
389
  maxBuffer: UI_SELF_UPDATE_MAX_BUFFER,
479
390
  });
@@ -493,7 +404,7 @@ function runUiSelfUpdate() {
493
404
  startedAt,
494
405
  finishedAt: new Date().toISOString(),
495
406
  message: 'Update failed.',
496
- error: summarizeCommandError(err),
407
+ error: (0, update_check_js_1.summarizeCommandError)(err),
497
408
  latestVersion: null,
498
409
  };
499
410
  }
@@ -1959,6 +1870,18 @@ async function ensureWebTerminalBridge(record) {
1959
1870
  bridge.stopRequested = false;
1960
1871
  bridge.pty = ptyProcess;
1961
1872
  webTerminalBridges.set(record.id, bridge);
1873
+ if (!existing && bridge.history.length === 0) {
1874
+ try {
1875
+ const { stdout } = await execFileAsync(tmuxBin, ['capture-pane', '-p', '-S', WEB_TERMINAL_STARTUP_CAPTURE_LINES, '-t', record.tmuxSession], { timeout: 2_000, maxBuffer: WEB_TERMINAL_STARTUP_READY_BUFFER_LIMIT });
1876
+ const snapshot = String(stdout || '');
1877
+ if (snapshot) {
1878
+ appendWebTerminalBuffer(bridge, snapshot);
1879
+ }
1880
+ }
1881
+ catch {
1882
+ // Best effort only; live bridge output continues to stream after attach.
1883
+ }
1884
+ }
1962
1885
  ptyProcess.onData((data) => {
1963
1886
  const appended = appendWebTerminalBuffer(bridge, data);
1964
1887
  for (const chunk of appended) {
@@ -2648,13 +2571,7 @@ async function handleGetUiVersion(reqUrl, res) {
2648
2571
  const published = await getPublishedUiVersionCached(forceRefresh);
2649
2572
  const runningVersion = LABGATE_UI_VERSION;
2650
2573
  const latestVersion = published.latestVersion;
2651
- let updateAvailable = false;
2652
- if (latestVersion) {
2653
- const cmp = compareSemverStrings(latestVersion, runningVersion);
2654
- updateAvailable = cmp === null
2655
- ? stripVersionPrefix(latestVersion) !== stripVersionPrefix(runningVersion)
2656
- : cmp > 0;
2657
- }
2574
+ const updateAvailable = (0, update_check_js_1.isVersionNewer)(latestVersion, runningVersion);
2658
2575
  json(res, {
2659
2576
  ok: true,
2660
2577
  runningVersion,
@@ -2662,7 +2579,7 @@ async function handleGetUiVersion(reqUrl, res) {
2662
2579
  latestVersion,
2663
2580
  latestCheckedAt: published.checkedAt,
2664
2581
  updateAvailable,
2665
- updateCommand: `npm install -g ${UI_VERSION_NPM_PACKAGE}@latest`,
2582
+ updateCommand: (0, update_check_js_1.getUpdateCommand)(update_check_js_1.LABGATE_NPM_PACKAGE),
2666
2583
  restartCommand: 'labgate ui',
2667
2584
  checkError: published.error,
2668
2585
  });
@@ -5821,12 +5738,24 @@ async function handleGetWebTerminalHistory(reqUrl, res) {
5821
5738
  limit = Math.max(1, Math.min(WEB_TERMINAL_HISTORY_PAGE_MAX, Math.floor(parsedLimit)));
5822
5739
  }
5823
5740
  const bridge = await ensureWebTerminalBridge(record);
5741
+ const currentCommand = await getTmuxSessionForegroundCommand(record.tmuxSession);
5824
5742
  if (!bridge) {
5825
- json(res, { ok: false, error: 'Could not open terminal bridge' }, 500);
5743
+ json(res, {
5744
+ ok: true,
5745
+ id: record.id,
5746
+ currentCommand: currentCommand || null,
5747
+ history: {
5748
+ chunks: [],
5749
+ hasMore: false,
5750
+ nextBefore: null,
5751
+ oldestSeq: null,
5752
+ latestSeq: null,
5753
+ limit,
5754
+ },
5755
+ });
5826
5756
  return;
5827
5757
  }
5828
5758
  const page = getWebTerminalHistoryPage(bridge, { beforeSeq, limit });
5829
- const currentCommand = await getTmuxSessionForegroundCommand(record.tmuxSession);
5830
5759
  json(res, {
5831
5760
  ok: true,
5832
5761
  id: record.id,