@volter/supercode-teams 0.3.94 → 0.3.95

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/live-sessions.mjs CHANGED
@@ -440,6 +440,9 @@ export class LiveSessions extends EventEmitter {
440
440
  if (had) this.#changed();
441
441
  }
442
442
 
443
+ /** A new index subscription's first answer replaces the Codex rows the last one held (its rows follow this). */
444
+ codexRowsReplaced() { this.codexRows.clear(); }
445
+
443
446
  /** The session index's first answer is read: its Codex sessions' activity is followed next (even when it has none). */
444
447
  codexIndexed() {
445
448
  if (!this.codexIndexRead) this.codexIndexedAt = Date.now();
@@ -211,6 +211,15 @@ export class RecordHolder {
211
211
  if (forgot) this.save();
212
212
  for (const [machine, held] of this.held) if (!linked.has(machine) && held.state !== 'unlinked') this.let(machine, 'offline: not linked to the team\'s server');
213
213
  for (const machine of linked) { const held = this.held.get(machine); if (!held || held.state === 'unlinked' || ((held.state === 'closed' || held.state === 'too-old') && !held.retry)) this.subscribe(machine); }
214
+ // a machine too old to serve records whose link changed since (it linked again: an update restarts its daemon) is
215
+ // asked again now, not at its ten-minute re-ask
216
+ const changedAt = new Map((items ?? []).filter((item) => item.linked).map((item) => [normal(item.name), item.changed_at ?? null]));
217
+ for (const [machine, held] of this.held) {
218
+ const at = changedAt.get(machine);
219
+ if (at == null) continue;
220
+ if (held.state === 'too-old' && held.linkChangedAt != null && at !== held.linkChangedAt) { held.linkChangedAt = at; this.subscribe(machine); continue; }
221
+ held.linkChangedAt = at;
222
+ }
214
223
  }
215
224
  let(machine, why) {
216
225
  const held = this.held.get(machine); if (!held) return;
package/machine.mjs CHANGED
@@ -617,8 +617,33 @@ export class TeamsMachine extends MachineCore {
617
617
  this.on('internal-notification', (message) => {
618
618
  const params = message.params ?? {};
619
619
  if (params.subscription && params.subscription === this.liveActivity) this.live.codexActivity(params.activities);
620
+ else if (params.subscription && params.subscription === this.codexIndex) {
621
+ for (const change of params.changes ?? []) {
622
+ if (change.kind === 'removed' && change.key?.harness === 'codex') this.live.codexIndex({ removed: change.key.session_id });
623
+ else if (change.descriptor) this.live.codexIndex({ descriptor: change.descriptor });
624
+ }
625
+ }
626
+ });
627
+ // The Codex sessions' own index (Codex rollouts only): the live map knows them from its first answer, never waiting on
628
+ // the whole index of every harness, which the machine records keep (on yuerans that took 25.6 s to answer: grok's
629
+ // 11,305 files and claude-code's 6,334 listed, a page of 5,340 rows built; Codex's 980 files listed in 25 ms).
630
+ let codexIndexBackoff = 0, codexIndexRetry = null;
631
+ const subscribeCodex = () => this.#serveRequest('harness.v1.sessions.index.subscribe', { harnesses: ['codex'], limit: 0 }, 60_000)
632
+ .then((answer) => {
633
+ this.codexIndex = answer?.subscription ?? null; codexIndexBackoff = 0;
634
+ this.live.codexRowsReplaced();
635
+ for (const descriptor of answer?.initial ?? []) if (descriptor?.locator) this.live.codexIndex({ descriptor });
636
+ this.live.codexIndexed();
637
+ }, (error) => {
638
+ codexIndexBackoff = Math.min(300_000, Math.max(2000, (codexIndexBackoff || 1000) * 2));
639
+ this.emit('records-log', `live sessions: the Codex sessions' index could not be subscribed (${error.message}); tried again in ${Math.round(codexIndexBackoff / 1000)} s`);
640
+ clearTimeout(codexIndexRetry); codexIndexRetry = setTimeout(() => void subscribeCodex(), codexIndexBackoff); codexIndexRetry.unref?.();
641
+ });
642
+ void subscribeCodex();
643
+ this.on('serve-exit', () => {
644
+ this.liveActivity = null; this.codexIndex = null; followed = ''; this.live.codexForget(); this.live.emit('codex-followed');
645
+ clearTimeout(codexIndexRetry); codexIndexRetry = setTimeout(() => void subscribeCodex(), 2000); codexIndexRetry.unref?.();
620
646
  });
621
- this.on('serve-exit', () => { this.liveActivity = null; followed = ''; this.live.codexForget(); this.live.emit('codex-followed'); });
622
647
  }
623
648
 
624
649
  // ---- this machine's mail (mail/; docs/architecture/overview.md, "The mail operations") ---------------------------
@@ -782,8 +807,6 @@ export class TeamsMachine extends MachineCore {
782
807
  for (const change of params.changes ?? []) {
783
808
  if (change.kind === 'removed' && change.key) this.sessionDescriptors?.delete(`sc:${machineName(this.env)}:${change.key.harness}:${change.key.session_id}`);
784
809
  else if (change.descriptor?.locator) this.sessionDescriptors?.set(`sc:${machineName(this.env)}:${change.descriptor.locator.harness}:${change.descriptor.locator.session_id}`, change.descriptor);
785
- if (change.kind === 'removed' && change.key?.harness === 'codex') this.live?.codexIndex({ removed: change.key.session_id });
786
- else if (change.descriptor) this.live?.codexIndex({ descriptor: change.descriptor });
787
810
  if (change.kind === 'removed' && change.key) locators.delete(`${change.key.harness}:${change.key.session_id}`);
788
811
  else if (change.descriptor?.locator) locators.set(`${change.descriptor.locator.harness}:${change.descriptor.locator.session_id}`, change.descriptor.locator);
789
812
  }
@@ -796,9 +819,8 @@ export class TeamsMachine extends MachineCore {
796
819
  .then((answer) => {
797
820
  this.recordsIndex = answer?.subscription ?? null; indexBackoff = 0; locators.clear();
798
821
  this.sessionDescriptors?.clear();
799
- for (const descriptor of answer?.initial ?? []) if (descriptor?.locator) { locators.set(`${descriptor.locator.harness}:${descriptor.locator.session_id}`, descriptor.locator); this.live?.codexIndex({ descriptor }); this.sessionDescriptors?.set(`sc:${machineName(this.env)}:${descriptor.locator.harness}:${descriptor.locator.session_id}`, descriptor); }
822
+ for (const descriptor of answer?.initial ?? []) if (descriptor?.locator) { locators.set(`${descriptor.locator.harness}:${descriptor.locator.session_id}`, descriptor.locator); this.sessionDescriptors?.set(`sc:${machineName(this.env)}:${descriptor.locator.harness}:${descriptor.locator.session_id}`, descriptor); }
800
823
  producer.note('sessions_index', null); noteIndexParts(answer?.failed, null); both();
801
- this.live?.codexIndexed();
802
824
  }, (error) => {
803
825
  indexBackoff = backoff(indexBackoff);
804
826
  const why = `the session index could not be subscribed: ${error.message}; sessions and panes change on pane and mail events only until it is`;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@volter/supercode-teams",
3
- "version": "0.3.94",
3
+ "version": "0.3.95",
4
4
  "type": "module",
5
5
  "description": "A machine daemon serving this machine's doors, and a local or remote Teams server for shared session discovery, OpenTelemetry ingestion and access to enrolled machines.",
6
6
  "license": "MIT",