chatroom-cli 1.49.2 → 1.50.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/dist/index.js CHANGED
@@ -82750,6 +82750,24 @@ class TempFileOutputStore {
82750
82750
  totalBytes: this.state.totalBytes
82751
82751
  };
82752
82752
  }
82753
+ async getLastNLines(maxLines) {
82754
+ let source;
82755
+ try {
82756
+ source = await readFile8(this.state.filePath, "utf-8");
82757
+ } catch {
82758
+ source = this.state.inMemory;
82759
+ }
82760
+ const lines = source.split(`
82761
+ `);
82762
+ const slice = lines.length > maxLines ? lines.slice(-maxLines) : lines;
82763
+ const content = slice.join(`
82764
+ `);
82765
+ return {
82766
+ content,
82767
+ totalBytes: Buffer.byteLength(content, "utf-8"),
82768
+ lineCount: slice.length
82769
+ };
82770
+ }
82753
82771
  async getFullOutput() {
82754
82772
  try {
82755
82773
  return await readFile8(this.state.filePath, "utf-8");
@@ -82778,39 +82796,96 @@ async function cleanOrphanTempFiles() {
82778
82796
  await rm(TEMP_DIR, { recursive: true, force: true });
82779
82797
  } catch {}
82780
82798
  }
82781
- var TAIL_WINDOW_BYTES, TEMP_DIR, RUN_ID_RE;
82799
+ var TAIL_WINDOW_BYTES, TEMP_DIR, RUN_ID_RE, MAX_TAIL_LINES_V2 = 50;
82782
82800
  var init_output_store = __esm(() => {
82783
82801
  TAIL_WINDOW_BYTES = 32 * 1024;
82784
82802
  TEMP_DIR = join17(tmpdir(), "chatroom-cli", "runs");
82785
82803
  RUN_ID_RE = /^[a-z0-9]+$/i;
82786
82804
  });
82787
82805
 
82806
+ // src/commands/machine/daemon-start/handlers/process/log-observer-sync.ts
82807
+ function isRunLogObserved(runId) {
82808
+ return observedRunIds.has(runId);
82809
+ }
82810
+ function consumePendingFullSync(runId) {
82811
+ if (!pendingFullSyncRunIds.has(runId))
82812
+ return false;
82813
+ pendingFullSyncRunIds.delete(runId);
82814
+ return true;
82815
+ }
82816
+ function startLogObserverPoll(ctx) {
82817
+ let stopped = false;
82818
+ const poll4 = async () => {
82819
+ if (stopped)
82820
+ return;
82821
+ try {
82822
+ const runs = await ctx.deps.backend.query(api.commands.listRunsWithLogObservers, {
82823
+ sessionId: ctx.sessionId,
82824
+ machineId: ctx.machineId
82825
+ });
82826
+ observedRunIds.clear();
82827
+ pendingFullSyncRunIds.clear();
82828
+ for (const run3 of runs) {
82829
+ observedRunIds.add(run3._id);
82830
+ if (run3.pendingFullOutputSync) {
82831
+ pendingFullSyncRunIds.add(run3._id);
82832
+ }
82833
+ }
82834
+ } catch (err) {
82835
+ console.warn(`[${formatTimestamp()}] ⚠️ Log-observer poll failed: ${getErrorMessage(err)}`);
82836
+ }
82837
+ };
82838
+ poll4();
82839
+ const handle = setInterval(() => {
82840
+ poll4();
82841
+ }, OUTPUT_FLUSH_INTERVAL_MS);
82842
+ handle.unref?.();
82843
+ return {
82844
+ stop: () => {
82845
+ stopped = true;
82846
+ clearInterval(handle);
82847
+ observedRunIds.clear();
82848
+ pendingFullSyncRunIds.clear();
82849
+ }
82850
+ };
82851
+ }
82852
+ var observedRunIds, pendingFullSyncRunIds;
82853
+ var init_log_observer_sync = __esm(() => {
82854
+ init_api3();
82855
+ init_convex_error();
82856
+ init_state2();
82857
+ observedRunIds = new Set;
82858
+ pendingFullSyncRunIds = new Set;
82859
+ });
82860
+
82788
82861
  // src/commands/machine/daemon-start/handlers/process/spawner.ts
82789
82862
  import { spawn as spawn4 } from "node:child_process";
82790
- async function flushTail(ctx, tracked) {
82791
- const tail = tracked.store.getTail();
82863
+ async function flushTailV2(ctx, tracked) {
82864
+ if (!isRunLogObserved(tracked.runId))
82865
+ return;
82866
+ const tail = await tracked.store.getLastNLines(MAX_TAIL_LINES_V2);
82792
82867
  if (tail.content.length === 0)
82793
82868
  return;
82794
82869
  const compressed = encodeOutput(tail.content);
82795
82870
  try {
82796
- await ctx.deps.backend.mutation(api.commands.updateRunTail, {
82871
+ await ctx.deps.backend.mutation(api.commands.updateRunTailV2, {
82797
82872
  sessionId: ctx.sessionId,
82798
82873
  machineId: ctx.machineId,
82799
82874
  runId: tracked.runId,
82800
82875
  tailOutput: {
82801
82876
  compression: compressed.compression,
82802
82877
  content: compressed.content,
82803
- byteLength: tail.content.length,
82878
+ byteLength: tail.totalBytes,
82804
82879
  totalBytesWritten: tail.totalBytes,
82805
- updatedAt: Date.now()
82880
+ updatedAt: Date.now(),
82881
+ lineCount: tail.lineCount
82806
82882
  }
82807
82883
  });
82808
82884
  } catch (err) {
82809
82885
  console.warn(`[${formatTimestamp()}] ⚠️ Failed to flush tail for run ${tracked.runId}: ${getErrorMessage(err)}`);
82810
82886
  }
82811
82887
  }
82812
- async function flushFinalChunks(ctx, tracked, runId) {
82813
- await flushTail(ctx, tracked);
82888
+ async function appendFullOutputChunks(ctx, tracked, runId) {
82814
82889
  let fullOutput;
82815
82890
  try {
82816
82891
  fullOutput = await tracked.store.getFullOutput();
@@ -82834,11 +82909,31 @@ async function flushFinalChunks(ctx, tracked, runId) {
82834
82909
  });
82835
82910
  chunkIndex++;
82836
82911
  } catch (err) {
82837
- console.error(`[${formatTimestamp()}] ❌ Failed to flush final chunk ${chunkIndex} for run ${tracked.runId}: ${getErrorMessage(err)}`);
82912
+ console.error(`[${formatTimestamp()}] ❌ Failed to flush chunk ${chunkIndex} for run ${tracked.runId}: ${getErrorMessage(err)}`);
82838
82913
  return;
82839
82914
  }
82840
82915
  }
82841
82916
  }
82917
+ async function flushFinalChunks(ctx, tracked, runId) {
82918
+ await flushTailV2(ctx, tracked);
82919
+ if (consumePendingFullSync(tracked.runId)) {
82920
+ await appendFullOutputChunks(ctx, tracked, runId);
82921
+ }
82922
+ }
82923
+ async function syncFullOutputOnRequest(ctx, tracked, runId) {
82924
+ if (!consumePendingFullSync(tracked.runId))
82925
+ return;
82926
+ await appendFullOutputChunks(ctx, tracked, runId);
82927
+ try {
82928
+ await ctx.deps.backend.mutation(api.commands.clearPendingFullOutputSync, {
82929
+ sessionId: ctx.sessionId,
82930
+ machineId: ctx.machineId,
82931
+ runId
82932
+ });
82933
+ } catch (err) {
82934
+ console.warn(`[${formatTimestamp()}] ⚠️ Failed to clear pending full sync for ${tracked.runId}: ${getErrorMessage(err)}`);
82935
+ }
82936
+ }
82842
82937
  async function spawnCommandProcess(ctx, event, commandKey) {
82843
82938
  const { workingDir, commandName, script, runId } = event;
82844
82939
  const runIdStr = runId.toString();
@@ -82860,7 +82955,8 @@ async function spawnCommandProcess(ctx, event, commandKey) {
82860
82955
  store,
82861
82956
  startedAt: Date.now(),
82862
82957
  flushTimer: setInterval(() => {
82863
- flushTail(ctx, tracked).catch(() => {});
82958
+ flushTailV2(ctx, tracked).catch(() => {});
82959
+ syncFullOutputOnRequest(ctx, tracked, runId).catch(() => {});
82864
82960
  }, OUTPUT_FLUSH_INTERVAL_MS),
82865
82961
  softTimeoutTimer: null,
82866
82962
  terminationIntent: null
@@ -82927,7 +83023,7 @@ async function spawnCommandProcess(ctx, event, commandKey) {
82927
83023
  }
82928
83024
  };
82929
83025
  child.on("exit", (code2, signal) => {
82930
- console.log(`[${formatTimestamp()}] \uD83C\uDFC1 Command exited: ${commandName} (code=${code2}, signal=${signal})`);
83026
+ console.log(`[${formatTimestamp()}] \uD83D\uDCCB Command exited: ${commandName} (code=${code2}, signal=${signal})`);
82931
83027
  finalize(code2, signal).catch(() => {});
82932
83028
  });
82933
83029
  child.on("error", async (err) => {
@@ -82946,6 +83042,7 @@ var init_spawner = __esm(() => {
82946
83042
  init_manager();
82947
83043
  init_killer();
82948
83044
  init_output_store();
83045
+ init_log_observer_sync();
82949
83046
  });
82950
83047
 
82951
83048
  // src/commands/machine/daemon-start/handlers/command-runner.ts
@@ -85277,6 +85374,7 @@ async function startCommandLoop(ctx) {
85277
85374
  let fileContentSubscriptionHandle = null;
85278
85375
  let fileTreeSubscriptionHandle = null;
85279
85376
  let observedSyncSubscriptionHandle = null;
85377
+ let logObserverPollHandle = null;
85280
85378
  let pendingPromptSubscriptionHandle = null;
85281
85379
  let pendingHarnessSessionSubscriptionHandle = null;
85282
85380
  let commandSubscriptionHandle = null;
@@ -85302,6 +85400,8 @@ async function startCommandLoop(ctx) {
85302
85400
  fileTreeSubscriptionHandle.stop();
85303
85401
  if (observedSyncSubscriptionHandle)
85304
85402
  observedSyncSubscriptionHandle.stop();
85403
+ if (logObserverPollHandle)
85404
+ logObserverPollHandle.stop();
85305
85405
  if (pendingPromptSubscriptionHandle)
85306
85406
  pendingPromptSubscriptionHandle.stop();
85307
85407
  if (pendingHarnessSessionSubscriptionHandle)
@@ -85330,6 +85430,7 @@ async function startCommandLoop(ctx) {
85330
85430
  if (ctx.observedSyncEnabled) {
85331
85431
  observedSyncSubscriptionHandle = startObservedSyncSubscription(ctx, wsClient2);
85332
85432
  }
85433
+ logObserverPollHandle = startLogObserverPoll(ctx);
85333
85434
  if (featureFlags.directHarnessWorkers) {
85334
85435
  const sessionRepository = new ConvexSessionRepository({
85335
85436
  backend: ctx.deps.backend,
@@ -85418,6 +85519,7 @@ var init_command_loop = __esm(() => {
85418
85519
  init_command_runner();
85419
85520
  init_manager();
85420
85521
  init_init2();
85522
+ init_log_observer_sync();
85421
85523
  init_observed_sync();
85422
85524
  init_api3();
85423
85525
  init_client2();
@@ -86597,4 +86699,4 @@ program2.hook("preAction", async (_thisCommand, actionCommand) => {
86597
86699
  });
86598
86700
  program2.parse();
86599
86701
 
86600
- //# debugId=4BF4F3B3AF6C84CB64756E2164756E21
86702
+ //# debugId=3E031CCB2CBFFA9464756E2164756E21