tabminal 3.0.36 → 3.0.38

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tabminal",
3
- "version": "3.0.36",
3
+ "version": "3.0.38",
4
4
  "description": "Tab(ter)minal, a Cloud-Native terminal and ACP agent workspace for desktop, tablet, and phone.",
5
5
  "type": "module",
6
6
  "bin": {
package/public/app.js CHANGED
@@ -8213,6 +8213,14 @@ class EditorManager {
8213
8213
  if (!agentTab) return;
8214
8214
  const session = agentTab.getLinkedSession();
8215
8215
  if (!session) return;
8216
+ this.#renderAgentCommandSuggestions([{
8217
+ kind: 'info',
8218
+ label: 'Opening previous session...',
8219
+ description: command.displayName
8220
+ || command.title
8221
+ || command.sessionId
8222
+ || ''
8223
+ }]);
8216
8224
  try {
8217
8225
  let targetAgentTab = null;
8218
8226
  let targetPromptDraft = '';
@@ -8265,11 +8273,13 @@ class EditorManager {
8265
8273
  targetPromptDraft,
8266
8274
  targetAgentTab || getActiveAgentTab() || agentTab
8267
8275
  );
8276
+ this.hideAgentCommandMenu();
8268
8277
  } catch (error) {
8269
8278
  alert(error.message, {
8270
8279
  type: 'error',
8271
8280
  title: getAgentBaseName(agentTab)
8272
8281
  });
8282
+ this.hideAgentCommandMenu();
8273
8283
  }
8274
8284
  return;
8275
8285
  }
@@ -14719,27 +14729,53 @@ async function activateAgentTab(session, agentTab, options = {}) {
14719
14729
  return agentTab;
14720
14730
  }
14721
14731
 
14732
+ const pendingAgentHistoryResumes = new Map();
14733
+
14734
+ function getAgentHistoryResumeKey(session, agentTab, historySession) {
14735
+ return [
14736
+ session?.server?.id || '',
14737
+ session?.key || '',
14738
+ agentTab?.agentId || '',
14739
+ String(historySession?.sessionId || '').trim()
14740
+ ].join('\0');
14741
+ }
14742
+
14722
14743
  async function resumeAgentTabFromHistory(session, agentTab, historySession) {
14723
14744
  if (!session || !agentTab || !historySession?.sessionId) return null;
14724
- const response = await session.server.fetch('/api/agents/tabs/resume', {
14725
- method: 'POST',
14726
- headers: { 'Content-Type': 'application/json' },
14727
- body: JSON.stringify({
14728
- agentId: agentTab.agentId,
14729
- cwd: agentTab.cwd || session.cwd || session.initialCwd || '/',
14730
- terminalSessionId: session.id,
14731
- sessionId: historySession.sessionId,
14732
- title: historySession.title || ''
14733
- })
14734
- });
14735
- if (!response.ok) {
14736
- await throwResponseError(response, 'Failed to resume agent session');
14745
+ const resumeKey = getAgentHistoryResumeKey(session, agentTab, historySession);
14746
+ const pendingResume = pendingAgentHistoryResumes.get(resumeKey);
14747
+ if (pendingResume) {
14748
+ return await pendingResume;
14749
+ }
14750
+
14751
+ const resumePromise = (async () => {
14752
+ const response = await session.server.fetch('/api/agents/tabs/resume', {
14753
+ method: 'POST',
14754
+ headers: { 'Content-Type': 'application/json' },
14755
+ body: JSON.stringify({
14756
+ agentId: agentTab.agentId,
14757
+ cwd: agentTab.cwd || session.cwd || session.initialCwd || '/',
14758
+ terminalSessionId: session.id,
14759
+ sessionId: historySession.sessionId,
14760
+ title: historySession.title || ''
14761
+ })
14762
+ });
14763
+ if (!response.ok) {
14764
+ await throwResponseError(response, 'Failed to resume agent session');
14765
+ }
14766
+ const data = await response.json();
14767
+ return await activateAgentTab(
14768
+ session,
14769
+ upsertAgentTab(session.server, data)
14770
+ );
14771
+ })();
14772
+ pendingAgentHistoryResumes.set(resumeKey, resumePromise);
14773
+
14774
+ try {
14775
+ return await resumePromise;
14776
+ } finally {
14777
+ pendingAgentHistoryResumes.delete(resumeKey);
14737
14778
  }
14738
- const data = await response.json();
14739
- return await activateAgentTab(
14740
- session,
14741
- upsertAgentTab(session.server, data)
14742
- );
14743
14779
  }
14744
14780
 
14745
14781
  function getServerEndpointKey(server) {
@@ -3890,6 +3890,7 @@ export class AcpManager {
3890
3890
  this.loadConfigs = options.loadConfigs || persistence.loadAgentConfigs;
3891
3891
  this.saveConfigs = options.saveConfigs || persistence.saveAgentConfigs;
3892
3892
  this.persistenceChain = Promise.resolve();
3893
+ this.pendingResumeTabs = new Map();
3893
3894
  this.transcriptPersistDelayMs = options.transcriptPersistDelayMs
3894
3895
  || DEFAULT_TRANSCRIPT_PERSIST_DELAY_MS;
3895
3896
  this.persistTabsTimer = null;
@@ -4569,12 +4570,21 @@ export class AcpManager {
4569
4570
  return existingTab;
4570
4571
  }
4571
4572
 
4573
+ const resumeKey = [
4574
+ definition.id,
4575
+ String(options.sessionId || '').trim()
4576
+ ].join('\0');
4577
+ const pendingResume = this.pendingResumeTabs.get(resumeKey);
4578
+ if (pendingResume) {
4579
+ return await pendingResume;
4580
+ }
4581
+
4572
4582
  const cwd = path.resolve(options.cwd || process.cwd());
4573
4583
  const { runtimeEntry, createdRuntime, runtimeStoreKey } =
4574
4584
  this.#ensureRuntimeEntry(definition, cwd);
4575
4585
  const tabId = crypto.randomUUID();
4576
4586
 
4577
- try {
4587
+ const resumePromise = (async () => {
4578
4588
  const rawSerialized = await runtimeEntry.runtime.resumeTab({
4579
4589
  id: tabId,
4580
4590
  acpSessionId: options.sessionId,
@@ -4603,6 +4613,11 @@ export class AcpManager {
4603
4613
  this.#clearDefinitionAvailabilityOverride(definition.id);
4604
4614
  await this.persistTabs();
4605
4615
  return tabEntry.serialize();
4616
+ })();
4617
+ this.pendingResumeTabs.set(resumeKey, resumePromise);
4618
+
4619
+ try {
4620
+ return await resumePromise;
4606
4621
  } catch (error) {
4607
4622
  const shouldDisposeRuntime = createdRuntime
4608
4623
  || runtimeEntry.runtime.tabs.size === 0;
@@ -4610,6 +4625,8 @@ export class AcpManager {
4610
4625
  await this.#disposeRuntimeEntry(runtimeStoreKey, runtimeEntry);
4611
4626
  }
4612
4627
  throw error;
4628
+ } finally {
4629
+ this.pendingResumeTabs.delete(resumeKey);
4613
4630
  }
4614
4631
  }
4615
4632