linkshell-cli 0.5.33 → 0.5.34

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.
@@ -4,6 +4,7 @@ export declare function makeAgentV2RemoteConversationId(provider: AgentProvider,
4
4
  export declare class AgentWorkspaceProxy {
5
5
  private readonly input;
6
6
  private clients;
7
+ private clientStartPromises;
7
8
  private agentProtocols;
8
9
  private providerCapabilities;
9
10
  private providerErrors;
@@ -58,6 +59,15 @@ export declare class AgentWorkspaceProxy {
58
59
  private defaultModelForProvider;
59
60
  private initialize;
60
61
  private ensureProviderClient;
62
+ private startProviderClient;
63
+ /** Kick off runtime capability discovery WITHOUT blocking the caller.
64
+ * refreshProviderCapabilities spawns a warm provider subprocess (measured
65
+ * 858ms warm, multi-second cold for Claude), and nothing on the open/prompt
66
+ * path needs it — sendCapabilities and prompt-time model resolution both
67
+ * degrade gracefully to static fallbacks until providerCapabilities is
68
+ * populated. When discovery lands we push a fresh agent.v2.capabilities so
69
+ * clients pick up the real model/command list. */
70
+ private refreshProviderCapabilitiesInBackground;
61
71
  private refreshProviderCapabilities;
62
72
  private syncProviderSessions;
63
73
  private hydrateConversationFromProvider;
@@ -1664,6 +1664,9 @@ function previewFromTimelineItem(item) {
1664
1664
  export class AgentWorkspaceProxy {
1665
1665
  input;
1666
1666
  clients = new Map();
1667
+ // In-flight client starts, so concurrent ensureProviderClient calls (eager
1668
+ // initialize() racing conversation.open) share one subprocess spawn.
1669
+ clientStartPromises = new Map();
1667
1670
  agentProtocols = new Map();
1668
1671
  providerCapabilities = new Map();
1669
1672
  providerErrors = new Map();
@@ -1983,6 +1986,24 @@ export class AgentWorkspaceProxy {
1983
1986
  const existing = this.clients.get(provider);
1984
1987
  if (existing)
1985
1988
  return existing;
1989
+ // Dedupe concurrent starts: eager initialize() and conversation.open can
1990
+ // race here before this.clients is populated (it's only set AFTER the
1991
+ // client finishes initializing), which would spawn the provider subprocess
1992
+ // twice. Memoize the in-flight promise so both callers share one spawn;
1993
+ // drop it once settled so a failed start can be retried.
1994
+ const inflight = this.clientStartPromises.get(provider);
1995
+ if (inflight)
1996
+ return inflight;
1997
+ const start = this.startProviderClient(provider);
1998
+ this.clientStartPromises.set(provider, start);
1999
+ try {
2000
+ return await start;
2001
+ }
2002
+ finally {
2003
+ this.clientStartPromises.delete(provider);
2004
+ }
2005
+ }
2006
+ async startProviderClient(provider) {
1986
2007
  const resolved = resolveAgentCommand({
1987
2008
  provider,
1988
2009
  command: this.input.command,
@@ -2033,7 +2054,7 @@ export class AgentWorkspaceProxy {
2033
2054
  const client = await tryCreateClient(resolved);
2034
2055
  this.clients.set(provider, client);
2035
2056
  this.providerErrors.delete(provider);
2036
- await this.refreshProviderCapabilities(provider, client, resolved.protocol);
2057
+ this.refreshProviderCapabilitiesInBackground(provider, client, resolved.protocol);
2037
2058
  this.status = "idle";
2038
2059
  this.error = undefined;
2039
2060
  this.sendCapabilities();
@@ -2054,7 +2075,7 @@ export class AgentWorkspaceProxy {
2054
2075
  const client = await tryCreateClient(fallback);
2055
2076
  this.clients.set(provider, client);
2056
2077
  this.providerErrors.delete(provider);
2057
- await this.refreshProviderCapabilities(provider, client, fallback.protocol);
2078
+ this.refreshProviderCapabilitiesInBackground(provider, client, fallback.protocol);
2058
2079
  this.status = "idle";
2059
2080
  this.error = undefined;
2060
2081
  this.sendCapabilities();
@@ -2074,6 +2095,22 @@ export class AgentWorkspaceProxy {
2074
2095
  return undefined;
2075
2096
  }
2076
2097
  }
2098
+ /** Kick off runtime capability discovery WITHOUT blocking the caller.
2099
+ * refreshProviderCapabilities spawns a warm provider subprocess (measured
2100
+ * 858ms warm, multi-second cold for Claude), and nothing on the open/prompt
2101
+ * path needs it — sendCapabilities and prompt-time model resolution both
2102
+ * degrade gracefully to static fallbacks until providerCapabilities is
2103
+ * populated. When discovery lands we push a fresh agent.v2.capabilities so
2104
+ * clients pick up the real model/command list. */
2105
+ refreshProviderCapabilitiesInBackground(provider, client, protocol) {
2106
+ void this.refreshProviderCapabilities(provider, client, protocol)
2107
+ .then(() => this.sendCapabilities())
2108
+ .catch((error) => {
2109
+ if (this.input.verbose) {
2110
+ process.stderr.write(`[agent:v2] capability refresh failed for ${provider}: ${error instanceof Error ? error.message : String(error)}\n`);
2111
+ }
2112
+ });
2113
+ }
2077
2114
  async refreshProviderCapabilities(provider, client, protocol) {
2078
2115
  if (client instanceof AcpClient && protocol !== "codex-app-server")
2079
2116
  return;