@stigmer/sdk 3.12.4 → 3.12.6

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.
Files changed (159) hide show
  1. package/__tests__/mcpserver-connect.test.d.ts +2 -0
  2. package/__tests__/mcpserver-connect.test.d.ts.map +1 -0
  3. package/__tests__/mcpserver-connect.test.js +146 -0
  4. package/__tests__/mcpserver-connect.test.js.map +1 -0
  5. package/__tests__/update-input-roundtrip.test.d.ts +2 -0
  6. package/__tests__/update-input-roundtrip.test.d.ts.map +1 -0
  7. package/__tests__/update-input-roundtrip.test.js +791 -0
  8. package/__tests__/update-input-roundtrip.test.js.map +1 -0
  9. package/__tests__/update-input.test.d.ts +2 -0
  10. package/__tests__/update-input.test.d.ts.map +1 -0
  11. package/__tests__/update-input.test.js +188 -0
  12. package/__tests__/update-input.test.js.map +1 -0
  13. package/gen/agent.d.ts +21 -0
  14. package/gen/agent.d.ts.map +1 -1
  15. package/gen/agent.js +73 -1
  16. package/gen/agent.js.map +1 -1
  17. package/gen/agentchannel.d.ts +23 -1
  18. package/gen/agentchannel.d.ts.map +1 -1
  19. package/gen/agentchannel.js +55 -1
  20. package/gen/agentchannel.js.map +1 -1
  21. package/gen/agentexecution.d.ts +29 -1
  22. package/gen/agentexecution.d.ts.map +1 -1
  23. package/gen/agentexecution.js +155 -2
  24. package/gen/agentexecution.js.map +1 -1
  25. package/gen/agentinstance.d.ts +21 -0
  26. package/gen/agentinstance.d.ts.map +1 -1
  27. package/gen/agentinstance.js +32 -1
  28. package/gen/agentinstance.js.map +1 -1
  29. package/gen/agentshare.d.ts +23 -1
  30. package/gen/agentshare.d.ts.map +1 -1
  31. package/gen/agentshare.js +53 -1
  32. package/gen/agentshare.js.map +1 -1
  33. package/gen/apikey.d.ts +21 -0
  34. package/gen/apikey.d.ts.map +1 -1
  35. package/gen/apikey.js +33 -1
  36. package/gen/apikey.js.map +1 -1
  37. package/gen/artifact.d.ts +8 -0
  38. package/gen/artifact.d.ts.map +1 -1
  39. package/gen/artifact.js +1 -0
  40. package/gen/artifact.js.map +1 -1
  41. package/gen/channelapp.d.ts +21 -0
  42. package/gen/channelapp.d.ts.map +1 -1
  43. package/gen/channelapp.js +45 -0
  44. package/gen/channelapp.js.map +1 -1
  45. package/gen/client.d.ts +3 -3
  46. package/gen/client.d.ts.map +1 -1
  47. package/gen/environment.d.ts +21 -0
  48. package/gen/environment.d.ts.map +1 -1
  49. package/gen/environment.js +31 -1
  50. package/gen/environment.js.map +1 -1
  51. package/gen/executioncontext.d.ts +8 -0
  52. package/gen/executioncontext.d.ts.map +1 -1
  53. package/gen/executioncontext.js +1 -0
  54. package/gen/executioncontext.js.map +1 -1
  55. package/gen/iampolicy.d.ts +8 -0
  56. package/gen/iampolicy.d.ts.map +1 -1
  57. package/gen/iampolicy.js +1 -0
  58. package/gen/iampolicy.js.map +1 -1
  59. package/gen/identityaccount.d.ts +29 -0
  60. package/gen/identityaccount.d.ts.map +1 -1
  61. package/gen/identityaccount.js +57 -2
  62. package/gen/identityaccount.js.map +1 -1
  63. package/gen/identityprovider.d.ts +21 -0
  64. package/gen/identityprovider.d.ts.map +1 -1
  65. package/gen/identityprovider.js +40 -0
  66. package/gen/identityprovider.js.map +1 -1
  67. package/gen/invitation.d.ts +8 -0
  68. package/gen/invitation.d.ts.map +1 -1
  69. package/gen/invitation.js +1 -0
  70. package/gen/invitation.js.map +1 -1
  71. package/gen/mcpserver.d.ts +22 -0
  72. package/gen/mcpserver.d.ts.map +1 -1
  73. package/gen/mcpserver.js +87 -1
  74. package/gen/mcpserver.js.map +1 -1
  75. package/gen/oauthapp.d.ts +23 -1
  76. package/gen/oauthapp.d.ts.map +1 -1
  77. package/gen/oauthapp.js +40 -0
  78. package/gen/oauthapp.js.map +1 -1
  79. package/gen/organization.d.ts +26 -0
  80. package/gen/organization.d.ts.map +1 -1
  81. package/gen/organization.js +49 -2
  82. package/gen/organization.js.map +1 -1
  83. package/gen/platformclient.d.ts +22 -0
  84. package/gen/platformclient.d.ts.map +1 -1
  85. package/gen/platformclient.js +42 -1
  86. package/gen/platformclient.js.map +1 -1
  87. package/gen/project.d.ts +21 -0
  88. package/gen/project.d.ts.map +1 -1
  89. package/gen/project.js +32 -1
  90. package/gen/project.js.map +1 -1
  91. package/gen/proto-utils.d.ts +36 -0
  92. package/gen/proto-utils.d.ts.map +1 -1
  93. package/gen/proto-utils.js +58 -0
  94. package/gen/proto-utils.js.map +1 -1
  95. package/gen/schedule.d.ts +23 -1
  96. package/gen/schedule.d.ts.map +1 -1
  97. package/gen/schedule.js +79 -1
  98. package/gen/schedule.js.map +1 -1
  99. package/gen/session.d.ts +21 -0
  100. package/gen/session.d.ts.map +1 -1
  101. package/gen/session.js +80 -1
  102. package/gen/session.js.map +1 -1
  103. package/gen/skill.d.ts +8 -0
  104. package/gen/skill.d.ts.map +1 -1
  105. package/gen/skill.js +1 -0
  106. package/gen/skill.js.map +1 -1
  107. package/gen/workflow.d.ts +21 -0
  108. package/gen/workflow.d.ts.map +1 -1
  109. package/gen/workflow.js +79 -0
  110. package/gen/workflow.js.map +1 -1
  111. package/gen/workflowexecution.d.ts +21 -0
  112. package/gen/workflowexecution.d.ts.map +1 -1
  113. package/gen/workflowexecution.js +36 -1
  114. package/gen/workflowexecution.js.map +1 -1
  115. package/gen/workflowinstance.d.ts +21 -0
  116. package/gen/workflowinstance.d.ts.map +1 -1
  117. package/gen/workflowinstance.js +33 -1
  118. package/gen/workflowinstance.js.map +1 -1
  119. package/index.d.ts +21 -20
  120. package/index.d.ts.map +1 -1
  121. package/index.js +25 -21
  122. package/index.js.map +1 -1
  123. package/mcpserver-connect.d.ts +79 -0
  124. package/mcpserver-connect.d.ts.map +1 -0
  125. package/mcpserver-connect.js +114 -0
  126. package/mcpserver-connect.js.map +1 -0
  127. package/package.json +2 -2
  128. package/src/__tests__/mcpserver-connect.test.ts +181 -0
  129. package/src/__tests__/update-input-roundtrip.test.ts +1031 -0
  130. package/src/__tests__/update-input.test.ts +250 -0
  131. package/src/gen/agent.ts +89 -3
  132. package/src/gen/agentchannel.ts +72 -4
  133. package/src/gen/agentexecution.ts +188 -6
  134. package/src/gen/agentinstance.ts +41 -1
  135. package/src/gen/agentshare.ts +68 -4
  136. package/src/gen/apikey.ts +42 -1
  137. package/src/gen/artifact.ts +9 -0
  138. package/src/gen/channelapp.ts +57 -1
  139. package/src/gen/client.ts +3 -3
  140. package/src/gen/environment.ts +40 -1
  141. package/src/gen/executioncontext.ts +9 -0
  142. package/src/gen/iampolicy.ts +9 -0
  143. package/src/gen/identityaccount.ts +77 -2
  144. package/src/gen/identityprovider.ts +49 -0
  145. package/src/gen/invitation.ts +9 -0
  146. package/src/gen/mcpserver.ts +101 -3
  147. package/src/gen/oauthapp.ts +51 -1
  148. package/src/gen/organization.ts +66 -2
  149. package/src/gen/platformclient.ts +52 -1
  150. package/src/gen/project.ts +41 -1
  151. package/src/gen/proto-utils.ts +64 -0
  152. package/src/gen/schedule.ts +98 -4
  153. package/src/gen/session.ts +97 -3
  154. package/src/gen/skill.ts +9 -0
  155. package/src/gen/workflow.ts +96 -2
  156. package/src/gen/workflowexecution.ts +45 -1
  157. package/src/gen/workflowinstance.ts +42 -1
  158. package/src/index.ts +32 -3
  159. package/src/mcpserver-connect.ts +159 -0
@@ -1,7 +1,7 @@
1
1
  // Code generated by stigmer-codegen. DO NOT EDIT.
2
2
 
3
3
  import { wrapError } from "./errors.js";
4
- import { stripUndefined } from "./proto-utils.js";
4
+ import { stripUndefined, toExecVarInputMap } from "./proto-utils.js";
5
5
  import { type EnvVarInput } from "./types.js";
6
6
  import { create } from "@bufbuild/protobuf";
7
7
  import { createClient, type Client, type Transport } from "@connectrpc/connect";
@@ -160,6 +160,14 @@ export class WorkflowExecutionClient {
160
160
 
161
161
  /** Input for creating/updating a WorkflowExecution. */
162
162
  export interface WorkflowExecutionInput {
163
+ /**
164
+ * The resource's `metadata.id`, for exact update addressing when set
165
+ * from a loaded resource. Required for updates to platform-scoped
166
+ * (org-less) kinds, where the org+slug fallback cannot match. On
167
+ * create, the cloud server stamps its own id regardless; the OSS
168
+ * server honors a caller-supplied id (existing apply semantics).
169
+ */
170
+ id?: string;
163
171
  name: string;
164
172
  slug?: string;
165
173
  org: string;
@@ -184,6 +192,7 @@ export function buildWorkflowExecutionProto(input: WorkflowExecutionInput): Work
184
192
  apiVersion: "agentic.stigmer.ai/v1",
185
193
  kind: "WorkflowExecution",
186
194
  metadata: Object.assign(create(ApiResourceMetadataSchema), {
195
+ ...(input.id && { id: input.id }),
187
196
  name: input.name,
188
197
  org: input.org,
189
198
  ...(input.slug && { slug: input.slug }),
@@ -201,3 +210,38 @@ export function buildWorkflowExecutionProto(input: WorkflowExecutionInput): Work
201
210
  })),
202
211
  }) as WorkflowExecution;
203
212
  }
213
+
214
+ /**
215
+ * Maps a fetched {@link WorkflowExecution} to a complete {@link WorkflowExecutionInput} for `update()`.
216
+ *
217
+ * The update RPC replaces the ENTIRE spec — spread this mapper's output
218
+ * and override only the fields you edit (spread nested objects the same
219
+ * way):
220
+ *
221
+ * await client.update({ ...toWorkflowExecutionUpdateInput(res), description: next });
222
+ *
223
+ * Proto3 defaults normalize to `undefined`; resource references keep
224
+ * `version` (pinned refs) and `kind`.
225
+ */
226
+ export function toWorkflowExecutionUpdateInput(resource: WorkflowExecution): WorkflowExecutionInput {
227
+ const meta = resource.metadata;
228
+ const spec = resource.spec ?? create(WorkflowExecutionSpecSchema);
229
+ return {
230
+ // Exact update addressing (id-first in the update pipeline) — for
231
+ // platform-scoped (org-less) kinds the org+slug fallback cannot
232
+ // match, so the id is the ONLY working address.
233
+ id: meta?.id || undefined,
234
+ name: meta?.name ?? "",
235
+ slug: meta?.slug || undefined,
236
+ org: meta?.org ?? "",
237
+ labels: meta?.labels && Object.keys(meta.labels).length > 0 ? { ...meta.labels } : undefined,
238
+ visibility: meta?.visibility || undefined,
239
+ workflowInstanceId: spec.workflowInstanceId || undefined,
240
+ workflowId: spec.workflowId || undefined,
241
+ triggerMessage: spec.triggerMessage || undefined,
242
+ triggerMetadata: Object.keys(spec.triggerMetadata ?? {}).length > 0 ? { ...spec.triggerMetadata } : undefined,
243
+ runtimeEnv: toExecVarInputMap(spec.runtimeEnv),
244
+ callbackToken: spec.callbackToken?.length ? spec.callbackToken : undefined,
245
+ executionTarget: spec.executionTarget || undefined,
246
+ };
247
+ }
@@ -1,7 +1,7 @@
1
1
  // Code generated by stigmer-codegen. DO NOT EDIT.
2
2
 
3
3
  import { wrapError } from "./errors.js";
4
- import { stripUndefined } from "./proto-utils.js";
4
+ import { stripUndefined, toResourceRefInputs } from "./proto-utils.js";
5
5
  import { type ResourceRef } from "./types.js";
6
6
  import { create } from "@bufbuild/protobuf";
7
7
  import { createClient, type Client, type Transport } from "@connectrpc/connect";
@@ -82,6 +82,14 @@ export class WorkflowInstanceClient {
82
82
 
83
83
  /** Input for creating/updating a WorkflowInstance. */
84
84
  export interface WorkflowInstanceInput {
85
+ /**
86
+ * The resource's `metadata.id`, for exact update addressing when set
87
+ * from a loaded resource. Required for updates to platform-scoped
88
+ * (org-less) kinds, where the org+slug fallback cannot match. On
89
+ * create, the cloud server stamps its own id regardless; the OSS
90
+ * server honors a caller-supplied id (existing apply semantics).
91
+ */
92
+ id?: string;
85
93
  name: string;
86
94
  slug?: string;
87
95
  org: string;
@@ -99,6 +107,7 @@ export function buildWorkflowInstanceProto(input: WorkflowInstanceInput): Workfl
99
107
  apiVersion: "agentic.stigmer.ai/v1",
100
108
  kind: "WorkflowInstance",
101
109
  metadata: Object.assign(create(ApiResourceMetadataSchema), {
110
+ ...(input.id && { id: input.id }),
102
111
  name: input.name,
103
112
  org: input.org,
104
113
  ...(input.slug && { slug: input.slug }),
@@ -113,3 +122,35 @@ export function buildWorkflowInstanceProto(input: WorkflowInstanceInput): Workfl
113
122
  })),
114
123
  }) as WorkflowInstance;
115
124
  }
125
+
126
+ /**
127
+ * Maps a fetched {@link WorkflowInstance} to a complete {@link WorkflowInstanceInput} for `update()`.
128
+ *
129
+ * The update RPC replaces the ENTIRE spec — spread this mapper's output
130
+ * and override only the fields you edit (spread nested objects the same
131
+ * way):
132
+ *
133
+ * await client.update({ ...toWorkflowInstanceUpdateInput(res), description: next });
134
+ *
135
+ * Proto3 defaults normalize to `undefined`; resource references keep
136
+ * `version` (pinned refs) and `kind`.
137
+ */
138
+ export function toWorkflowInstanceUpdateInput(resource: WorkflowInstance): WorkflowInstanceInput {
139
+ const meta = resource.metadata;
140
+ const spec = resource.spec ?? create(WorkflowInstanceSpecSchema);
141
+ return {
142
+ // Exact update addressing (id-first in the update pipeline) — for
143
+ // platform-scoped (org-less) kinds the org+slug fallback cannot
144
+ // match, so the id is the ONLY working address.
145
+ id: meta?.id || undefined,
146
+ name: meta?.name ?? "",
147
+ slug: meta?.slug || undefined,
148
+ org: meta?.org ?? "",
149
+ labels: meta?.labels && Object.keys(meta.labels).length > 0 ? { ...meta.labels } : undefined,
150
+ visibility: meta?.visibility || undefined,
151
+ workflowId: spec.workflowId || undefined,
152
+ description: spec.description || undefined,
153
+ environmentRefs: toResourceRefInputs(spec.environmentRefs),
154
+ executionVisibility: spec.executionVisibility || undefined,
155
+ };
156
+ }
package/src/index.ts CHANGED
@@ -160,10 +160,14 @@ export {
160
160
  type EnvVarInput,
161
161
  } from "./gen/types.js";
162
162
 
163
- // Re-export all resource client classes and input types
163
+ // Re-export all resource client classes and input types. The
164
+ // toXxxUpdateInput mappers are the full-spec-replace safety layer: they
165
+ // rebuild a COMPLETE input from a fetched resource so subset editors can
166
+ // spread-and-override without wiping unlisted fields.
164
167
  export {
165
168
  AgentClient,
166
169
  buildAgentProto,
170
+ toAgentUpdateInput,
167
171
  type AgentInput,
168
172
  type McpServerUsageInput,
169
173
  type ToolApprovalOverrideInput,
@@ -173,11 +177,13 @@ export {
173
177
  } from "./gen/agent.js";
174
178
  export {
175
179
  AgentChannelClient,
180
+ toAgentChannelUpdateInput,
176
181
  type AgentChannelInput,
177
182
  type SlackChannelConfigInput,
178
183
  } from "./gen/agentchannel.js";
179
184
  export {
180
185
  AgentExecutionClient,
186
+ toAgentExecutionUpdateInput,
181
187
  type AgentExecutionInput,
182
188
  type ExecutionConfigInput,
183
189
  type ContextManagementConfigInput,
@@ -185,21 +191,25 @@ export {
185
191
  } from "./gen/agentexecution.js";
186
192
  export {
187
193
  AgentInstanceClient,
194
+ toAgentInstanceUpdateInput,
188
195
  type AgentInstanceInput,
189
196
  } from "./gen/agentinstance.js";
190
197
  export {
191
198
  AgentShareClient,
199
+ toAgentShareUpdateInput,
192
200
  type AgentShareInput,
193
201
  type AgentShareMessagesInput,
194
202
  } from "./gen/agentshare.js";
195
- export { ApiKeyClient, type ApiKeyInput } from "./gen/apikey.js";
203
+ export { ApiKeyClient, toApiKeyUpdateInput, type ApiKeyInput } from "./gen/apikey.js";
196
204
  export {
197
205
  ChannelAppClient,
206
+ toChannelAppUpdateInput,
198
207
  type ChannelAppInput,
199
208
  type SlackChannelAppConfigInput,
200
209
  } from "./gen/channelapp.js";
201
210
  export {
202
211
  EnvironmentClient,
212
+ toEnvironmentUpdateInput,
203
213
  type EnvironmentInput,
204
214
  } from "./gen/environment.js";
205
215
  export {
@@ -213,6 +223,7 @@ export {
213
223
  } from "./gen/iampolicy.js";
214
224
  export {
215
225
  IdentityAccountClient,
226
+ toIdentityAccountUpdateInput,
216
227
  type IdentityAccountInput,
217
228
  } from "./gen/identityaccount.js";
218
229
  export {
@@ -221,38 +232,53 @@ export {
221
232
  } from "./gen/invitation.js";
222
233
  export {
223
234
  IdentityProviderClient,
235
+ toIdentityProviderUpdateInput,
224
236
  type IdentityProviderInput,
225
237
  } from "./gen/identityprovider.js";
226
238
  export {
227
239
  OAuthAppClient,
240
+ toOAuthAppUpdateInput,
228
241
  type OAuthAppInput,
229
242
  } from "./gen/oauthapp.js";
230
243
  export {
231
244
  McpServerClient,
232
245
  buildMcpServerProto,
246
+ toMcpServerUpdateInput,
233
247
  type McpServerInput,
234
248
  type StdioServerConfigInput,
235
249
  type HttpServerConfigInput,
236
250
  type ToolApprovalPolicyInput,
237
251
  } from "./gen/mcpserver.js";
252
+ export {
253
+ connectAndWait,
254
+ ConnectStillRunningError,
255
+ CONNECT_POLL_INTERVAL_MS,
256
+ CONNECT_SETTLE_BOUND_MS,
257
+ type ConnectAndWaitOptions,
258
+ type McpServerConnectLane,
259
+ } from "./mcpserver-connect.js";
238
260
  export {
239
261
  OrganizationClient,
262
+ toOrganizationUpdateInput,
240
263
  type OrganizationInput,
241
264
  } from "./gen/organization.js";
242
265
  export {
243
266
  PlatformClientClient,
267
+ toPlatformClientUpdateInput,
244
268
  type PlatformClientInput,
245
269
  } from "./gen/platformclient.js";
246
- export { ProjectClient, type ProjectInput } from "./gen/project.js";
270
+ export { ProjectClient, toProjectUpdateInput, type ProjectInput } from "./gen/project.js";
247
271
  export {
248
272
  ScheduleClient,
249
273
  buildScheduleProto,
274
+ toScheduleUpdateInput,
250
275
  type ScheduleInput,
251
276
  type AgentInvocationInput,
252
277
  type RunConfigInput,
253
278
  } from "./gen/schedule.js";
254
279
  export {
255
280
  SessionClient,
281
+ toSessionUpdateInput,
256
282
  type SessionInput,
257
283
  type WorkspaceEntryInput,
258
284
  type WorkspaceSourceInput,
@@ -297,6 +323,7 @@ export { SkillClient, type SkillInput } from "./gen/skill.js";
297
323
  export { RoutedSkillClient, MAX_INLINE_ARTIFACT_BYTES } from "./skill.js";
298
324
  export {
299
325
  WorkflowClient,
326
+ toWorkflowUpdateInput,
300
327
  type WorkflowInput,
301
328
  type WorkflowDocumentInput,
302
329
  type WorkflowTaskInput,
@@ -305,9 +332,11 @@ export {
305
332
  } from "./gen/workflow.js";
306
333
  export {
307
334
  WorkflowExecutionClient,
335
+ toWorkflowExecutionUpdateInput,
308
336
  type WorkflowExecutionInput,
309
337
  } from "./gen/workflowexecution.js";
310
338
  export {
311
339
  WorkflowInstanceClient,
340
+ toWorkflowInstanceUpdateInput,
312
341
  type WorkflowInstanceInput,
313
342
  } from "./gen/workflowinstance.js";
@@ -0,0 +1,159 @@
1
+ import { Code, ConnectError } from "@connectrpc/connect";
2
+ import type { McpServer } from "@stigmer/protos/ai/stigmer/agentic/mcpserver/v1/api_pb";
3
+ import type { ConnectInput } from "@stigmer/protos/ai/stigmer/agentic/mcpserver/v1/io_pb";
4
+ import { ConnectPhase } from "@stigmer/protos/ai/stigmer/agentic/mcpserver/v1/status_pb";
5
+ import { isUnimplemented, wrapError } from "./gen/errors.js";
6
+
7
+ /**
8
+ * The slice of {@link McpServerClient} the connect protocol needs — the
9
+ * async-lane pair plus the blocking fallback. Structural on purpose: the
10
+ * full client satisfies it, and tests can hand in three functions.
11
+ */
12
+ export interface McpServerConnectLane {
13
+ startConnect(input: ConnectInput): Promise<McpServer>;
14
+ connect(input: ConnectInput): Promise<McpServer>;
15
+ get(id: string): Promise<McpServer>;
16
+ }
17
+
18
+ /**
19
+ * How often {@link connectAndWait} re-reads the resource while a connect
20
+ * operation runs. Discovery legitimately takes tens of seconds to minutes;
21
+ * a few seconds of staleness is invisible next to that, and each poll is
22
+ * one cheap get.
23
+ */
24
+ export const CONNECT_POLL_INTERVAL_MS = 2_500;
25
+
26
+ /**
27
+ * Absolute bound on waiting for a connect to settle: the backend's async
28
+ * connect ceiling (its asyncConnectTimeout, 60 min) plus margin. Every
29
+ * operation settles within the ceiling by construction; only a
30
+ * connect_status orphaned by a backend restart can still read CONNECTING
31
+ * past it, and this bound turns that into a typed error instead of an
32
+ * infinite wait.
33
+ */
34
+ export const CONNECT_SETTLE_BOUND_MS = 65 * 60_000;
35
+
36
+ /**
37
+ * Thrown by {@link connectAndWait} when it stopped waiting while the
38
+ * server-side operation was still running. NOT a failure: the backend
39
+ * finishes the connect on its own and persists the result — re-read the
40
+ * resource (or re-run the connect) to observe the outcome.
41
+ */
42
+ export class ConnectStillRunningError extends Error {
43
+ readonly mcpServerId: string;
44
+
45
+ constructor(mcpServerId: string, waitedMs: number) {
46
+ super(
47
+ `the connect of MCP server '${mcpServerId}' is still running server-side after ${Math.round(waitedMs / 1000)}s — ` +
48
+ "it will persist its result on its own; re-read the server to observe the outcome",
49
+ );
50
+ this.name = "ConnectStillRunningError";
51
+ this.mcpServerId = mcpServerId;
52
+ }
53
+ }
54
+
55
+ /** Options for {@link connectAndWait}. */
56
+ export interface ConnectAndWaitOptions {
57
+ /** Poll cadence. Defaults to {@link CONNECT_POLL_INTERVAL_MS}. */
58
+ readonly pollIntervalMs?: number;
59
+ /**
60
+ * Stop waiting after this long (soft bound — the server-side operation
61
+ * keeps running). Defaults to {@link CONNECT_SETTLE_BOUND_MS}, and is
62
+ * capped by it: waiting longer than the backend's own ceiling can only
63
+ * ever observe an orphaned record.
64
+ */
65
+ readonly deadlineMs?: number;
66
+ /**
67
+ * Observe the CONNECTING snapshot the moment the operation is accepted —
68
+ * the place to read `status.connect_status.warning` (the dead-runner
69
+ * advisory) before the wait begins. Not called on the blocking fallback,
70
+ * which has no start-time snapshot.
71
+ */
72
+ readonly onStarted?: (started: McpServer) => void;
73
+ }
74
+
75
+ /**
76
+ * Connect an MCP server and wait for the operation to settle, without any
77
+ * long-lived RPC (stigmer/stigmer#425).
78
+ *
79
+ * Uses the async lane — `startConnect` returns immediately with
80
+ * `status.connect_status = CONNECTING`, then the resource is polled until
81
+ * the operation settles — so the wait survives transport limits that kill
82
+ * a long-blocking unary call (browsers drop no-bytes responses around
83
+ * ~300s, below the server's discovery ceiling). Callers never see the
84
+ * mechanics: the promise resolves with the updated server exactly as the
85
+ * blocking `connect` RPC resolved, and a failed operation rejects with the
86
+ * same {@link StigmerError} classification the blocking RPC would have
87
+ * thrown (`connect_status.failure_code` is the Go gRPC code name, which
88
+ * matches connect-es `Code` member names — rehydration is lossless).
89
+ *
90
+ * Backends that predate the async lane answer UNIMPLEMENTED for
91
+ * `startConnect`; this falls back to the blocking `connect` RPC — the same
92
+ * edition capability-probe idiom as the skill artifact-transfer lane
93
+ * (skill.ts) and the org-OAuth-app surface.
94
+ */
95
+ export async function connectAndWait(
96
+ client: McpServerConnectLane,
97
+ input: ConnectInput,
98
+ options?: ConnectAndWaitOptions,
99
+ ): Promise<McpServer> {
100
+ const pollIntervalMs = options?.pollIntervalMs ?? CONNECT_POLL_INTERVAL_MS;
101
+ const waitMs = Math.min(options?.deadlineMs ?? CONNECT_SETTLE_BOUND_MS, CONNECT_SETTLE_BOUND_MS);
102
+
103
+ let started: McpServer;
104
+ try {
105
+ started = await client.startConnect(input);
106
+ } catch (err) {
107
+ if (!isUnimplemented(err)) throw err;
108
+ return blockingConnect(client, input, waitMs);
109
+ }
110
+ options?.onStarted?.(started);
111
+
112
+ const deadline = Date.now() + waitMs;
113
+ for (;;) {
114
+ if (Date.now() >= deadline) {
115
+ throw new ConnectStillRunningError(input.mcpServerId, waitMs);
116
+ }
117
+ await sleep(Math.min(pollIntervalMs, Math.max(1, deadline - Date.now())));
118
+
119
+ const current = await client.get(input.mcpServerId);
120
+ const cs = current.status?.connectStatus;
121
+ if (cs?.phase === ConnectPhase.succeeded) return current;
122
+ if (cs?.phase === ConnectPhase.failed) {
123
+ throw rehydrateConnectFailure(cs.failureCode, cs.failureMessage);
124
+ }
125
+ }
126
+ }
127
+
128
+ // The pre-async-lane path, kept behaviorally identical for old backends: one
129
+ // blocking RPC, raced (not cancelled — the server finishes and persists on
130
+ // its own) against the caller's soft bound.
131
+ async function blockingConnect(client: McpServerConnectLane, input: ConnectInput, waitMs: number): Promise<McpServer> {
132
+ const push = client.connect(input);
133
+ // The losing push may settle after the caller has moved on; swallow its
134
+ // late rejection so it cannot surface as an unhandled-rejection crash.
135
+ void push.catch(() => {});
136
+
137
+ let timer: ReturnType<typeof setTimeout> | undefined;
138
+ const timeout = new Promise<never>((_, reject) => {
139
+ timer = setTimeout(() => reject(new ConnectStillRunningError(input.mcpServerId, waitMs)), waitMs);
140
+ });
141
+ try {
142
+ return await Promise.race([push, timeout]);
143
+ } finally {
144
+ if (timer !== undefined) clearTimeout(timer);
145
+ }
146
+ }
147
+
148
+ // Rebuild the failure the blocking connect RPC would have thrown, from the
149
+ // classification the backend persisted on connect_status. Routing the
150
+ // rehydrated ConnectError through wrapError makes the result byte-identical
151
+ // to a live RPC failure (same StigmerError code mapping, same raw message).
152
+ function rehydrateConnectFailure(failureCode: string, failureMessage: string) {
153
+ const code = (Code as Record<string, unknown>)[failureCode];
154
+ return wrapError(new ConnectError(failureMessage, typeof code === "number" ? (code as Code) : Code.Unknown));
155
+ }
156
+
157
+ function sleep(ms: number): Promise<void> {
158
+ return new Promise((resolve) => setTimeout(resolve, ms));
159
+ }