@phenx-inc/ctlsurf 0.3.5 → 0.3.7

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.
@@ -6056,12 +6056,6 @@ var WorkerWsClient = class {
6056
6056
  this.send({ type: "terminal_resize", cols, rows });
6057
6057
  }
6058
6058
  sendChatLog(entry) {
6059
- log("[worker-ws] chat_log DEBUG", {
6060
- type: entry.type,
6061
- chars: entry.content.length,
6062
- lines: entry.content.split("\n").length,
6063
- preview: entry.content.slice(0, 500)
6064
- });
6065
6059
  this.send({ type: "chat_log", entry });
6066
6060
  }
6067
6061
  doConnect() {
@@ -6277,55 +6271,68 @@ var TimeTracker = class {
6277
6271
  if (this.sessions.has(tabId)) {
6278
6272
  await this.endSession(tabId);
6279
6273
  }
6280
- try {
6281
- const blockId = await this.ensureDatastore(cwd);
6282
- if (!blockId) {
6283
- log2(`No "${AGENT_DATASTORE_PAGE_TITLE}" page found for ${cwd} \u2014 tracking disabled for this session`);
6284
- return;
6274
+ const startedAt = Date.now();
6275
+ const state = {
6276
+ blockId: null,
6277
+ rowId: null,
6278
+ sessionUuid: randomUUID(),
6279
+ cwd,
6280
+ agentName,
6281
+ idleTimeoutMin,
6282
+ startedAt,
6283
+ lastActivity: startedAt,
6284
+ activeMs: 0,
6285
+ idleTimeoutMs: Math.max(1, idleTimeoutMin) * 60 * 1e3,
6286
+ firstCheckpointTimer: null,
6287
+ checkpointTimer: null,
6288
+ ended: false
6289
+ };
6290
+ this.sessions.set(tabId, state);
6291
+ await this.tryResolve(tabId);
6292
+ state.firstCheckpointTimer = setTimeout(() => {
6293
+ void this.checkpoint(tabId);
6294
+ const live = this.sessions.get(tabId);
6295
+ if (live && !live.ended) {
6296
+ live.checkpointTimer = setInterval(() => {
6297
+ void this.checkpoint(tabId);
6298
+ }, CHECKPOINT_INTERVAL_MS);
6285
6299
  }
6286
- const startedAt = Date.now();
6287
- const sessionUuid = randomUUID();
6300
+ }, FIRST_CHECKPOINT_DELAY_MS);
6301
+ const pending = !state.blockId || !state.rowId;
6302
+ log2(`Started tracking tab=${tabId} agent="${agentName}" cwd=${cwd}${pending ? " (pending datastore \u2014 will retry on each checkpoint)" : ""}`);
6303
+ }
6304
+ /** Attempts to locate (or create) the datastore + add the session row.
6305
+ * Returns true once the session is resolved (blockId + rowId set).
6306
+ * Safe to call repeatedly: re-running while pending will keep retrying;
6307
+ * once resolved it's a no-op. */
6308
+ async tryResolve(tabId) {
6309
+ const s = this.sessions.get(tabId);
6310
+ if (!s) return false;
6311
+ if (s.blockId && s.rowId) return true;
6312
+ try {
6313
+ const blockId = await this.ensureDatastore(s.cwd);
6314
+ if (!blockId) return false;
6288
6315
  const row = await this.api.addRow(blockId, {
6289
- Started: formatStarted(startedAt),
6290
- "Active Time": 0,
6291
- "Last Updated": new Date(startedAt).toISOString(),
6292
- Agent: agentName,
6316
+ Started: formatStarted(s.startedAt),
6317
+ "Active Time": Math.round(s.activeMs / 6e4),
6318
+ "Last Updated": (/* @__PURE__ */ new Date()).toISOString(),
6319
+ Agent: s.agentName,
6293
6320
  Worker: os2.hostname(),
6294
- Session: sessionUuid,
6321
+ Session: s.sessionUuid,
6295
6322
  Notes: ""
6296
6323
  });
6297
6324
  const rowId = row?.id;
6298
6325
  if (!rowId) {
6299
- log2("addRow returned no id; aborting tracking", row);
6300
- return;
6326
+ log2(`addRow returned no id for tab=${tabId}; will retry on next checkpoint`);
6327
+ return false;
6301
6328
  }
6302
- const state = {
6303
- blockId,
6304
- rowId,
6305
- cwd,
6306
- agentName,
6307
- idleTimeoutMin,
6308
- startedAt,
6309
- lastActivity: startedAt,
6310
- activeMs: 0,
6311
- idleTimeoutMs: Math.max(1, idleTimeoutMin) * 60 * 1e3,
6312
- firstCheckpointTimer: null,
6313
- checkpointTimer: null,
6314
- ended: false
6315
- };
6316
- state.firstCheckpointTimer = setTimeout(() => {
6317
- void this.checkpoint(tabId);
6318
- const live = this.sessions.get(tabId);
6319
- if (live && !live.ended) {
6320
- live.checkpointTimer = setInterval(() => {
6321
- void this.checkpoint(tabId);
6322
- }, CHECKPOINT_INTERVAL_MS);
6323
- }
6324
- }, FIRST_CHECKPOINT_DELAY_MS);
6325
- this.sessions.set(tabId, state);
6326
- log2(`Started tracking tab=${tabId} agent="${agentName}" cwd=${cwd}`);
6329
+ s.blockId = blockId;
6330
+ s.rowId = rowId;
6331
+ log2(`Resolved datastore for tab=${tabId} (cwd=${s.cwd})`);
6332
+ return true;
6327
6333
  } catch (err) {
6328
- log2(`startSession failed: ${err?.message || err}`);
6334
+ log2(`tryResolve failed for tab=${tabId}: ${err?.message || err}`);
6335
+ return false;
6329
6336
  }
6330
6337
  }
6331
6338
  isTracking(tabId) {
@@ -6365,14 +6372,21 @@ var TimeTracker = class {
6365
6372
  async endSession(tabId) {
6366
6373
  const s = this.sessions.get(tabId);
6367
6374
  if (!s || s.ended) return;
6368
- s.ended = true;
6369
6375
  if (s.firstCheckpointTimer) clearTimeout(s.firstCheckpointTimer);
6370
6376
  if (s.checkpointTimer) clearInterval(s.checkpointTimer);
6371
6377
  try {
6372
- await this.writeRow(s, Date.now());
6378
+ if (!s.blockId || !s.rowId) {
6379
+ await this.tryResolve(tabId);
6380
+ }
6381
+ if (s.blockId && s.rowId) {
6382
+ await this.writeRow(s, Date.now());
6383
+ } else {
6384
+ log2(`endSession for tab=${tabId}: never resolved datastore; ${Math.round(s.activeMs / 6e4)}min not recorded`);
6385
+ }
6373
6386
  } catch (err) {
6374
6387
  log2(`endSession write failed: ${err?.message || err}`);
6375
6388
  }
6389
+ s.ended = true;
6376
6390
  this.sessions.delete(tabId);
6377
6391
  }
6378
6392
  async endAll() {
@@ -6382,13 +6396,16 @@ var TimeTracker = class {
6382
6396
  async checkpoint(tabId) {
6383
6397
  const s = this.sessions.get(tabId);
6384
6398
  if (!s || s.ended) return;
6399
+ if (!s.blockId || !s.rowId) {
6400
+ if (!await this.tryResolve(tabId)) return;
6401
+ }
6385
6402
  try {
6386
6403
  await this.writeRow(s, Date.now());
6387
6404
  } catch (err) {
6388
6405
  log2(`checkpoint failed: ${err?.message || err}; retrying in 2s`);
6389
6406
  setTimeout(() => {
6390
6407
  const live = this.sessions.get(tabId);
6391
- if (!live || live.ended) return;
6408
+ if (!live || live.ended || !live.blockId || !live.rowId) return;
6392
6409
  this.writeRow(live, Date.now()).catch((err2) => {
6393
6410
  log2(`checkpoint retry failed: ${err2?.message || err2}`);
6394
6411
  });
@@ -6396,6 +6413,7 @@ var TimeTracker = class {
6396
6413
  }
6397
6414
  }
6398
6415
  async writeRow(s, _endTimeMs) {
6416
+ if (!s.blockId || !s.rowId) return;
6399
6417
  const activeMin = Math.round(s.activeMs / 6e4);
6400
6418
  await this.api.updateRow(s.blockId, s.rowId, {
6401
6419
  "Active Time": activeMin,