@phenx-inc/ctlsurf 0.3.6 → 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.
@@ -6271,55 +6271,68 @@ var TimeTracker = class {
6271
6271
  if (this.sessions.has(tabId)) {
6272
6272
  await this.endSession(tabId);
6273
6273
  }
6274
- try {
6275
- const blockId = await this.ensureDatastore(cwd);
6276
- if (!blockId) {
6277
- log2(`No "${AGENT_DATASTORE_PAGE_TITLE}" page found for ${cwd} \u2014 tracking disabled for this session`);
6278
- 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);
6279
6299
  }
6280
- const startedAt = Date.now();
6281
- 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;
6282
6315
  const row = await this.api.addRow(blockId, {
6283
- Started: formatStarted(startedAt),
6284
- "Active Time": 0,
6285
- "Last Updated": new Date(startedAt).toISOString(),
6286
- 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,
6287
6320
  Worker: os2.hostname(),
6288
- Session: sessionUuid,
6321
+ Session: s.sessionUuid,
6289
6322
  Notes: ""
6290
6323
  });
6291
6324
  const rowId = row?.id;
6292
6325
  if (!rowId) {
6293
- log2("addRow returned no id; aborting tracking", row);
6294
- return;
6326
+ log2(`addRow returned no id for tab=${tabId}; will retry on next checkpoint`);
6327
+ return false;
6295
6328
  }
6296
- const state = {
6297
- blockId,
6298
- rowId,
6299
- cwd,
6300
- agentName,
6301
- idleTimeoutMin,
6302
- startedAt,
6303
- lastActivity: startedAt,
6304
- activeMs: 0,
6305
- idleTimeoutMs: Math.max(1, idleTimeoutMin) * 60 * 1e3,
6306
- firstCheckpointTimer: null,
6307
- checkpointTimer: null,
6308
- ended: false
6309
- };
6310
- state.firstCheckpointTimer = setTimeout(() => {
6311
- void this.checkpoint(tabId);
6312
- const live = this.sessions.get(tabId);
6313
- if (live && !live.ended) {
6314
- live.checkpointTimer = setInterval(() => {
6315
- void this.checkpoint(tabId);
6316
- }, CHECKPOINT_INTERVAL_MS);
6317
- }
6318
- }, FIRST_CHECKPOINT_DELAY_MS);
6319
- this.sessions.set(tabId, state);
6320
- 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;
6321
6333
  } catch (err) {
6322
- log2(`startSession failed: ${err?.message || err}`);
6334
+ log2(`tryResolve failed for tab=${tabId}: ${err?.message || err}`);
6335
+ return false;
6323
6336
  }
6324
6337
  }
6325
6338
  isTracking(tabId) {
@@ -6359,14 +6372,21 @@ var TimeTracker = class {
6359
6372
  async endSession(tabId) {
6360
6373
  const s = this.sessions.get(tabId);
6361
6374
  if (!s || s.ended) return;
6362
- s.ended = true;
6363
6375
  if (s.firstCheckpointTimer) clearTimeout(s.firstCheckpointTimer);
6364
6376
  if (s.checkpointTimer) clearInterval(s.checkpointTimer);
6365
6377
  try {
6366
- 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
+ }
6367
6386
  } catch (err) {
6368
6387
  log2(`endSession write failed: ${err?.message || err}`);
6369
6388
  }
6389
+ s.ended = true;
6370
6390
  this.sessions.delete(tabId);
6371
6391
  }
6372
6392
  async endAll() {
@@ -6376,13 +6396,16 @@ var TimeTracker = class {
6376
6396
  async checkpoint(tabId) {
6377
6397
  const s = this.sessions.get(tabId);
6378
6398
  if (!s || s.ended) return;
6399
+ if (!s.blockId || !s.rowId) {
6400
+ if (!await this.tryResolve(tabId)) return;
6401
+ }
6379
6402
  try {
6380
6403
  await this.writeRow(s, Date.now());
6381
6404
  } catch (err) {
6382
6405
  log2(`checkpoint failed: ${err?.message || err}; retrying in 2s`);
6383
6406
  setTimeout(() => {
6384
6407
  const live = this.sessions.get(tabId);
6385
- if (!live || live.ended) return;
6408
+ if (!live || live.ended || !live.blockId || !live.rowId) return;
6386
6409
  this.writeRow(live, Date.now()).catch((err2) => {
6387
6410
  log2(`checkpoint retry failed: ${err2?.message || err2}`);
6388
6411
  });
@@ -6390,6 +6413,7 @@ var TimeTracker = class {
6390
6413
  }
6391
6414
  }
6392
6415
  async writeRow(s, _endTimeMs) {
6416
+ if (!s.blockId || !s.rowId) return;
6393
6417
  const activeMin = Math.round(s.activeMs / 6e4);
6394
6418
  await this.api.updateRow(s.blockId, s.rowId, {
6395
6419
  "Active Time": activeMin,