@parall/sdk 1.53.0 → 1.55.0

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/src/client.ts CHANGED
@@ -1,262 +1,260 @@
1
1
  import { type BrowserViewerRequestOptions, browserViewerRequestOptions } from './browser-viewer.js';
2
2
  import { API_BASE, ENDPOINTS, WIKI_BASE } from './constants.js';
3
+ import { TaskLabelClient } from './task-label-client.js';
3
4
  import type {
5
+ AddTeamMemberRequest,
6
+ AgentClip,
7
+ AgentInstructions,
8
+ AgentProviderConfigRead,
9
+ AgentSessionDB,
10
+ AgentStep,
11
+ AgentWithRuntime,
12
+ AgentWorkspaceReportStatus,
13
+ AgentWorkspaceState,
14
+ ApiKey,
15
+ Approval,
16
+ AttachAgentRequest,
17
+ AttachedAgent,
18
+ AttachedAgentsResponse,
19
+ AuthTokens,
20
+ AutoReloadSettings,
21
+ AvatarUploadResponse,
22
+ BacklinksResponse,
23
+ BillingSummary,
24
+ BindAgentClipRequest,
25
+ BrokenRefsResponse,
26
+ BrowseMachineFilesystemResponse,
27
+ BrowserProfile,
28
+ BrowserProfileConsent,
29
+ BrowserProfileLifecycleRequest,
30
+ BrowserProfileListItem,
31
+ BrowserProfileStatus,
32
+ BrowserRuntimeStatus,
33
+ BrowserViewerCommandRequest,
34
+ BrowserViewerCommandResponse,
35
+ BulkUpdateClipMetadataRequest,
36
+ ChangePasswordRequest,
37
+ ChannelConnection,
38
+ ChannelConversation,
39
+ ChannelCredentialsInput,
40
+ ChannelMessage,
41
+ ChannelProvisioningSession,
42
+ Chat,
43
+ ChatMember,
44
+ ChatMemberRole,
45
+ CheckEmailResponse,
4
46
  ClaimDispatchRequest,
5
47
  ClaimDispatchResponse,
6
- SteerDispatchRequest,
7
- SteerDispatchResponse,
8
- UpdateDispatchInputStateRequest,
9
- UpdateDispatchInputStateResponse,
48
+ Clip,
49
+ ClipAgentExecAccess,
50
+ ClipConnection,
51
+ ClipRegistryEntry,
52
+ Comment,
10
53
  CompleteDispatchByIDRequest,
11
54
  CompleteDispatchBySourceResult,
12
55
  CompleteDispatchLaneRequest,
13
56
  CompleteDispatchRequest,
14
- CompleteDispatchSourceFormRequest,
15
57
  CompleteDispatchResult,
58
+ CompleteDispatchSourceFormRequest,
16
59
  CompleteDispatchSourcesRequest,
17
60
  CompleteDispatchSourcesResult,
18
- AuthTokens,
19
- AvatarUploadResponse,
20
- RegisterRequest,
21
- RegisterResponse,
22
- LoginRequest,
23
- ChangePasswordRequest,
24
- CheckEmailResponse,
25
- User,
26
- Organization,
27
- OrgMember,
28
- OrgMemberRole,
29
- MemberProfile,
30
- UpdateMemberProfileRequest,
31
- AgentInstructions,
32
- UpdateAgentInstructionsRequest,
33
- Team,
34
- Chat,
35
- ChatMember,
36
- ChatMemberRole,
37
- CreateChatRequest,
38
- DiscoverableChat,
39
- Message,
40
- SendMessageRequest,
41
- SendDirectMessageRequest,
42
- DirectMessageResponse,
43
- PaginatedResponse,
44
- Approval,
45
- CreateApprovalRequest,
46
- PresignResponse,
47
- PresignUploadRequest,
48
- FileUrlResponse,
61
+ CompleteRuntimeAuthSessionRequest,
62
+ ComputePricing,
63
+ ComputePricingResponse,
64
+ CopyWikiFileRequest,
65
+ CopyWikiFileResponse,
49
66
  CreateAgentRequest,
50
67
  CreateAgentResponse,
51
- AgentProviderConfigRead,
52
- UpdateAgentProviderConfigRequest,
53
- AgentWithRuntime,
54
- ApiKey,
55
- WsTicketResponse,
56
- Machine,
57
- MachineCapability,
58
- ResizeMachineRequest,
59
- MachineKey,
60
- MachineRuntimeAuthState,
61
- AgentWorkspaceState,
62
- AgentWorkspaceReportStatus,
63
- DetectedRuntime,
64
- BrowseMachineFilesystemResponse,
65
- FilesystemEntry,
66
- DaemonAgentConfig,
67
- AttachedAgent,
68
- AttachAgentRequest,
69
- AttachedAgentsResponse,
70
- LaunchCredentialResponse,
71
- Task,
72
- CreateTaskRequest,
73
- UpdateTaskRequest,
74
- TaskRelation,
75
- TaskRelationTargetType,
76
- TaskWatcher,
77
- RefSearchResponse,
78
- ThreadWatcher,
79
- CreateTaskRelationRequest,
80
- TaskComment,
81
- CreateTaskCommentRequest,
82
- UpdateTaskCommentRequest,
83
- TaskActivity,
84
- Project,
85
- CreateProjectRequest,
86
- UpdateProjectRequest,
87
- Schedule,
88
- ScheduleRun,
68
+ CreateAgentSessionRequest,
69
+ CreateAgentStepRequest,
70
+ CreateApprovalRequest,
71
+ CreateBrowserProfileRequest,
72
+ CreateChannelConnectionInput,
73
+ CreateChatRequest,
74
+ CreateCheckoutRequest,
75
+ CreateCheckoutResponse,
76
+ CreateClipRequest,
77
+ CreateCommentRequest,
78
+ CreateExternalConnectionInput,
79
+ CreateExternalTriggerInput,
89
80
  CreateScheduleInput,
90
- UpdateScheduleInput,
91
- ScheduleFilters,
92
- ScheduleRunFilters,
81
+ CreateSetupIntentResponse,
82
+ CreateTeamRequest,
83
+ CreateWikiAccessRequest,
84
+ CreateWikiChangesetRequest,
85
+ CreateWikiPathRestrictionRequest,
86
+ CreateWikiPathScopeRequest,
87
+ CreateWikiRequest,
88
+ CreditTransaction,
89
+ CreditTransactionAgentGroup,
90
+ CreditTransactionMachineGroup,
91
+ DaemonAgentConfig,
92
+ DependencyCheckResult,
93
+ DeployTemplateRequest,
94
+ DetectedRuntime,
95
+ DirectMessageResponse,
96
+ DiscoverableChat,
97
+ DispatchEvent,
98
+ DispatchExpireResult,
99
+ EdgeBrowserProfile,
100
+ EdgeClipExecResult,
101
+ EdgeDevice,
102
+ EdgeOnboardingStatus,
103
+ EdgePlacement,
104
+ EdgeProfileProxyStatus,
105
+ EdgeViewerCommandRequest,
106
+ EdgeViewerCommandResponse,
107
+ ExecEdgeClipRequest,
93
108
  ExternalConnection,
94
- CreateExternalConnectionInput,
95
- UpdateExternalConnectionInput,
96
109
  ExternalConnectionFilters,
97
- ChannelConnection,
98
- ChannelConversation,
99
- ChannelMessage,
100
- ChannelCredentialsInput,
101
- ChannelProvisioningSession,
102
- CreateChannelConnectionInput,
103
- InitiateChannelProvisioningInput,
104
- SendChannelMessageInput,
105
- SlackChannelsPage,
106
- SlackHistoryPage,
107
- SlackManifestLinkResult,
108
- SlackMembersPage,
109
- SlackReadPageQuery,
110
- SlackStatusInput,
111
- SlackUsersPage,
112
- WechatContactsPage,
113
- SentChannelMessage,
114
- UpdateChannelConnectionInput,
115
110
  ExternalIngressEvent,
116
111
  ExternalIngressEventFilters,
117
112
  ExternalTrigger,
118
- CreateExternalTriggerInput,
119
- UpdateExternalTriggerInput,
120
113
  ExternalTriggerFilters,
121
114
  ExternalTriggerRun,
122
115
  ExternalTriggerRunFilters,
123
116
  ExternalTriggerSchema,
124
- AgentSessionDB,
125
- AgentStep,
126
- CreateAgentSessionRequest,
127
- CreateAgentStepRequest,
128
- UpdateAgentSessionRequest,
117
+ FeatureFlagsResponse,
118
+ FilesystemEntry,
119
+ FileUrlResponse,
120
+ GrantBrowserProfileConsentRequest,
121
+ InboxItem,
122
+ InboxUnreadCountResponse,
123
+ InitiateChannelProvisioningInput,
124
+ InstallRegistryClipResponse,
125
+ InvitationPublicInfo,
126
+ InvokeClipRequest,
127
+ InvokeClipResponse,
128
+ JoinByLinkResponse,
129
+ LaunchCredentialResponse,
130
+ LoginRequest,
131
+ Machine,
132
+ MachineBrowserProfile,
133
+ MachineBrowserProfileViewerResponse,
134
+ MachineCapability,
135
+ MachineClip,
136
+ MachineKey,
137
+ MachineRuntimeAuthState,
138
+ MCPConfigPutRequest,
139
+ MCPConfigResponse,
140
+ MCPConnectionSummary,
141
+ MCPOAuthInitiateResponse,
142
+ MCPOfficialClipRemovalResponse,
143
+ MemberProfile,
144
+ Message,
129
145
  NewSessionResponse,
146
+ NotificationPreferences,
147
+ NotifPrefs,
148
+ OnboardingProgress,
149
+ OnlineClipInfo,
150
+ Organization,
130
151
  OrgInvitation,
131
- InvitationPublicInfo,
132
152
  OrgInviteLink,
133
- JoinByLinkResponse,
134
153
  OrgJoinRequest,
135
- PlatformConfigResponse,
136
- Wiki,
137
- WikiBlob,
138
- CopyWikiFileRequest,
139
- CopyWikiFileResponse,
140
- WikiChangeset,
141
- WikiFileUploadResponse,
142
- WikiFilePreviewUrlResponse,
143
- WikiTreeResponse,
144
- WikiNodeSectionArtifact,
145
- WikiSearchResponse,
146
- WikiPageIndex,
147
- SearchParams,
148
- SearchResponse,
149
- WikiRefsResponse,
150
- WikiRefsCheckResponse,
151
- WikiAnchorStatusRequest,
152
- WikiAnchorStatusResponse,
153
- WikiAnchorResolveRequest,
154
- WikiAnchorResolveResponse,
155
- WikiDiff,
156
- WikiPathScope,
157
- WikiAccessStatus,
158
- WikiOperation,
159
- WikiOperationsResponse,
160
- CreateWikiRequest,
161
- CreateWikiChangesetRequest,
162
- UpdateWikiChangesetRequest,
163
- CreateWikiPathScopeRequest,
164
- WikiPathRestriction,
165
- CreateWikiPathRestrictionRequest,
166
- CreateWikiAccessRequest,
167
- Comment,
168
- CreateCommentRequest,
169
- UpdateCommentRequest,
170
- WikiCommit,
171
- WikiBlameEntry,
172
- InboxItem,
173
- InboxUnreadCountResponse,
174
- DispatchEvent,
175
- DispatchExpireResult,
176
- ResolveRefsResponse,
177
- BacklinksResponse,
154
+ OrgMember,
155
+ OrgMemberRole,
178
156
  OutboundRefsRequest,
179
157
  OutboundRefsResponse,
180
- RefGraphResponse,
181
- BrokenRefsResponse,
158
+ PaginatedResponse,
159
+ PlatformConfigResponse,
160
+ PlatformModelsResponse,
161
+ PresignResponse,
162
+ PresignUploadRequest,
163
+ PublishRegistryClipRequest,
182
164
  PushSubscribeRequest,
183
- NotifPrefs,
184
- NotificationPreferences,
185
- FeatureFlagsResponse,
186
- RuntimeAuthSession,
165
+ ReactionSummary,
166
+ RefGraphResponse,
167
+ RefSearchResponse,
168
+ RegisterRequest,
169
+ RegisterResponse,
170
+ ResizeMachineRequest,
171
+ ResolveRefsResponse,
187
172
  RuntimeAuthConnectedState,
188
- StartRuntimeAuthSessionRequest,
189
- CompleteRuntimeAuthSessionRequest,
190
- RuntimeStatus,
173
+ RuntimeAuthSession,
191
174
  RuntimeAvailableTag,
192
- RuntimeRelease,
193
- SetRuntimeModeRequest,
194
- UpdateAgentRequest,
195
- TransferChatOwnershipRequest,
196
- UpdateChatMemberRequest,
197
- UnreadEntry,
198
- ThreadUnreadEntry,
199
- BillingSummary,
200
- CreditTransaction,
201
- CreditTransactionAgentGroup,
202
- CreditTransactionMachineGroup,
203
- CreateCheckoutRequest,
204
- CreateCheckoutResponse,
205
- CreateSetupIntentResponse,
206
- AutoReloadSettings,
207
- UpdateAutoReloadRequest,
208
- ComputePricing,
209
- ComputePricingResponse,
210
175
  RuntimeCapability,
211
- PlatformModelsResponse,
212
- Clip,
213
- AgentClip,
214
- CreateClipRequest,
215
- UpdateClipRequest,
216
- BulkUpdateClipMetadataRequest,
217
- BindAgentClipRequest,
218
- InvokeClipRequest,
219
- InvokeClipResponse,
220
- OnlineClipInfo,
221
- ClipAgentExecAccess,
222
- ClipRegistryEntry,
223
- InstallRegistryClipResponse,
224
- PublishRegistryClipRequest,
225
- MachineClip,
226
- BrowserProfile,
227
- MachineBrowserProfile,
228
- MachineBrowserProfileViewerResponse,
229
- BrowserProfileListItem,
230
- BrowserProfileStatus,
231
- BrowserRuntimeStatus,
232
- BrowserProfileConsent,
233
- CreateBrowserProfileRequest,
234
- UpdateBrowserProfileRequest,
235
- BrowserProfileLifecycleRequest,
236
- BrowserViewerCommandRequest,
237
- BrowserViewerCommandResponse,
238
- EdgeViewerCommandRequest,
239
- EdgeViewerCommandResponse,
240
- GrantBrowserProfileConsentRequest,
241
- EdgeDevice,
242
- EdgePlacement,
243
- EdgeBrowserProfile,
244
- EdgeProfileProxyStatus,
176
+ RuntimeRelease,
177
+ RuntimeStatus,
178
+ Schedule,
179
+ ScheduleFilters,
180
+ ScheduleRun,
181
+ ScheduleRunFilters,
182
+ SearchParams,
183
+ SearchResponse,
184
+ SendChannelMessageInput,
185
+ SendDirectMessageRequest,
186
+ SendMessageRequest,
187
+ SentChannelMessage,
245
188
  SetEdgeProfileProxyRequest,
246
- ClipConnection,
247
- MCPConfigPutRequest,
248
- MCPConfigResponse,
249
- EdgeOnboardingStatus,
250
- ExecEdgeClipRequest,
251
- EdgeClipExecResult,
252
- ReactionSummary,
253
- ToggleReactionResponse,
254
- DependencyCheckResult,
255
- DeployTemplateRequest,
256
- OnboardingProgress,
189
+ SetRuntimeModeRequest,
190
+ SlackChannelsPage,
191
+ SlackHistoryPage,
192
+ SlackManifestLinkResult,
193
+ SlackMembersPage,
194
+ SlackReadPageQuery,
195
+ SlackStatusInput,
196
+ SlackUsersPage,
197
+ StartRuntimeAuthSessionRequest,
198
+ SteerDispatchRequest,
199
+ SteerDispatchResponse,
200
+ Task,
201
+ Team,
202
+ TeamMember,
257
203
  Template,
258
204
  TemplateDeploymentReport,
205
+ TemplateDeploymentResult,
206
+ ThreadUnreadEntry,
207
+ ToggleReactionResponse,
208
+ TransferChatOwnershipRequest,
209
+ UnreadEntry,
210
+ UpdateAgentInstructionsRequest,
211
+ UpdateAgentProviderConfigRequest,
212
+ UpdateAgentRequest,
213
+ UpdateAgentSessionRequest,
214
+ UpdateAutoReloadRequest,
215
+ UpdateBrowserProfileRequest,
216
+ UpdateChannelConnectionInput,
217
+ UpdateChatMemberRequest,
218
+ UpdateClipRequest,
219
+ UpdateCommentRequest,
220
+ UpdateDispatchInputStateRequest,
221
+ UpdateDispatchInputStateResponse,
222
+ UpdateExternalConnectionInput,
223
+ UpdateExternalTriggerInput,
224
+ UpdateMemberProfileRequest,
259
225
  UpdateOnboardingProgressRequest,
226
+ UpdateScheduleInput,
227
+ UpdateTeamMemberRequest,
228
+ UpdateTeamRequest,
229
+ UpdateWikiChangesetRequest,
230
+ User,
231
+ WechatContactsPage,
232
+ WechatProfileView,
233
+ WechatStatusView,
234
+ Wiki,
235
+ WikiAccessStatus,
236
+ WikiAnchorResolveRequest,
237
+ WikiAnchorResolveResponse,
238
+ WikiAnchorStatusRequest,
239
+ WikiAnchorStatusResponse,
240
+ WikiBlameEntry,
241
+ WikiBlob,
242
+ WikiChangeset,
243
+ WikiCommit,
244
+ WikiDiff,
245
+ WikiFilePreviewUrlResponse,
246
+ WikiFileUploadResponse,
247
+ WikiNodeSectionArtifact,
248
+ WikiOperation,
249
+ WikiOperationsResponse,
250
+ WikiPageIndex,
251
+ WikiPathRestriction,
252
+ WikiPathScope,
253
+ WikiRefsCheckResponse,
254
+ WikiRefsResponse,
255
+ WikiSearchResponse,
256
+ WikiTreeResponse,
257
+ WsTicketResponse,
260
258
  } from './types.js';
261
259
 
262
260
  export interface ParallClientOptions {
@@ -279,7 +277,7 @@ export interface ParallClientOptions {
279
277
  getFeatureFlagOverrides?: () => string | null | undefined;
280
278
  }
281
279
 
282
- export class ParallClient {
280
+ export class ParallClient extends TaskLabelClient {
283
281
  private baseUrl: string;
284
282
  private wikiBaseUrl: string;
285
283
  private token: string | null;
@@ -350,6 +348,7 @@ export class ParallClient {
350
348
  }
351
349
 
352
350
  constructor(options: ParallClientOptions = {}) {
351
+ super();
353
352
  this.baseUrl = options.baseUrl ?? '';
354
353
  // Defaults to baseUrl so existing single-origin consumers (web, desktop,
355
354
  // hosted agents behind one gateway) are unchanged; only split api/wiki
@@ -437,7 +436,7 @@ export class ParallClient {
437
436
  }
438
437
  }
439
438
 
440
- private async request<T>(
439
+ protected async request<T>(
441
440
  method: string,
442
441
  path: string,
443
442
  body?: unknown,
@@ -691,7 +690,8 @@ export class ParallClient {
691
690
 
692
691
  async createOrg(data: {
693
692
  name: string;
694
- invite_code: string;
693
+ /** Omitted when the deployment reports `cap:org-invite-code` disabled. */
694
+ invite_code?: string;
695
695
  avatar_url?: string;
696
696
  }): Promise<Organization> {
697
697
  return this.request('POST', ENDPOINTS.ORGS, data);
@@ -748,6 +748,60 @@ export class ParallClient {
748
748
  return res.data;
749
749
  }
750
750
 
751
+ async getTeam(orgId: string, teamId: string): Promise<Team> {
752
+ return this.request('GET', ENDPOINTS.TEAM(orgId, teamId));
753
+ }
754
+
755
+ /** Creating, renaming and deleting a team are org-admin actions. */
756
+ async createTeam(orgId: string, req: CreateTeamRequest): Promise<Team> {
757
+ return this.request('POST', ENDPOINTS.TEAMS(orgId), req);
758
+ }
759
+
760
+ /**
761
+ * Renames a team. The slug cannot be changed — wiki ACL rows reference it as
762
+ * `@slug`, so the server answers 400 SLUG_IMMUTABLE if one is sent.
763
+ */
764
+ async updateTeam(orgId: string, teamId: string, req: UpdateTeamRequest): Promise<Team> {
765
+ return this.request('PATCH', ENDPOINTS.TEAM(orgId, teamId), req);
766
+ }
767
+
768
+ async deleteTeam(orgId: string, teamId: string): Promise<void> {
769
+ return this.request('DELETE', ENDPOINTS.TEAM(orgId, teamId));
770
+ }
771
+
772
+ /** Roster with display info; members who left the org are already excluded. */
773
+ async getTeamMembers(orgId: string, teamId: string): Promise<TeamMember[]> {
774
+ const res = await this.request<{ data: TeamMember[] }>(
775
+ 'GET',
776
+ ENDPOINTS.TEAM_MEMBERS(orgId, teamId),
777
+ );
778
+ return res.data;
779
+ }
780
+
781
+ /**
782
+ * Adds an org member (human or agent) to a team. Org admins and that team's
783
+ * managers may add ordinary members; adding straight to `manager` is an
784
+ * org-admin action.
785
+ */
786
+ async addTeamMember(orgId: string, teamId: string, req: AddTeamMemberRequest): Promise<void> {
787
+ return this.request('POST', ENDPOINTS.TEAM_MEMBERS(orgId, teamId), req);
788
+ }
789
+
790
+ /** Appointing or demoting a manager is org-admin only. */
791
+ async updateTeamMember(
792
+ orgId: string,
793
+ teamId: string,
794
+ userId: string,
795
+ req: UpdateTeamMemberRequest,
796
+ ): Promise<void> {
797
+ return this.request('PATCH', ENDPOINTS.TEAM_MEMBER(orgId, teamId, userId), req);
798
+ }
799
+
800
+ /** A team manager may remove ordinary members; removing a peer manager is org-admin only. */
801
+ async removeTeamMember(orgId: string, teamId: string, userId: string): Promise<void> {
802
+ return this.request('DELETE', ENDPOINTS.TEAM_MEMBER(orgId, teamId, userId));
803
+ }
804
+
751
805
  async getOnlineMembers(orgId: string): Promise<string[]> {
752
806
  const res = await this.request<{ user_ids: string[] }>(
753
807
  'GET',
@@ -2201,226 +2255,6 @@ export class ParallClient {
2201
2255
  return res.json() as Promise<PlatformConfigResponse>;
2202
2256
  }
2203
2257
 
2204
- // ---- Tasks (org-scoped) ----
2205
-
2206
- async createTask(orgId: string, data: CreateTaskRequest): Promise<Task> {
2207
- return this.request('POST', ENDPOINTS.TASKS(orgId), data);
2208
- }
2209
-
2210
- async getTasks(
2211
- orgId: string,
2212
- params?: {
2213
- q?: string;
2214
- status?: string;
2215
- priority?: string;
2216
- assignee_id?: string;
2217
- parent_id?: string;
2218
- project_id?: string;
2219
- limit?: number;
2220
- cursor?: string;
2221
- sort?: string;
2222
- order?: string;
2223
- scope?: 'active' | 'archived' | 'all';
2224
- },
2225
- ): Promise<PaginatedResponse<Task>> {
2226
- return this.request('GET', ENDPOINTS.TASKS(orgId), undefined, params);
2227
- }
2228
-
2229
- async getTask(orgId: string, taskId: string): Promise<Task> {
2230
- return this.request('GET', ENDPOINTS.TASK(orgId, taskId));
2231
- }
2232
-
2233
- async updateTask(orgId: string, taskId: string, data: UpdateTaskRequest): Promise<Task> {
2234
- return this.request('PATCH', ENDPOINTS.TASK(orgId, taskId), data);
2235
- }
2236
-
2237
- async deleteTask(orgId: string, taskId: string, opts?: { force?: boolean }): Promise<void> {
2238
- return this.request(
2239
- 'DELETE',
2240
- ENDPOINTS.TASK(orgId, taskId),
2241
- undefined,
2242
- opts?.force ? { force: 'true' } : undefined,
2243
- );
2244
- }
2245
-
2246
- async archiveTask(orgId: string, taskId: string): Promise<void> {
2247
- return this.request('POST', ENDPOINTS.TASK_ARCHIVE(orgId, taskId));
2248
- }
2249
-
2250
- async restoreTask(orgId: string, taskId: string): Promise<void> {
2251
- return this.request('POST', ENDPOINTS.TASK_RESTORE(orgId, taskId));
2252
- }
2253
-
2254
- async watchTask(orgId: string, taskId: string): Promise<void> {
2255
- return this.request('POST', ENDPOINTS.TASK_WATCH(orgId, taskId));
2256
- }
2257
-
2258
- async unwatchTask(orgId: string, taskId: string): Promise<void> {
2259
- return this.request('DELETE', ENDPOINTS.TASK_WATCH(orgId, taskId));
2260
- }
2261
-
2262
- async getTaskWatchers(orgId: string, taskId: string): Promise<TaskWatcher[]> {
2263
- const res = await this.request<{ data: TaskWatcher[] }>(
2264
- 'GET',
2265
- ENDPOINTS.TASK_WATCHERS(orgId, taskId),
2266
- );
2267
- return res.data;
2268
- }
2269
-
2270
- async subscribeTaskMember(orgId: string, taskId: string, userId: string): Promise<void> {
2271
- return this.request('PUT', ENDPOINTS.TASK_SUBSCRIBER(orgId, taskId, userId));
2272
- }
2273
-
2274
- async unsubscribeTaskMember(orgId: string, taskId: string, userId: string): Promise<void> {
2275
- return this.request('DELETE', ENDPOINTS.TASK_SUBSCRIBER(orgId, taskId, userId));
2276
- }
2277
-
2278
- async watchThread(threadRootId: string): Promise<void> {
2279
- return this.request('POST', ENDPOINTS.MESSAGE_WATCH(threadRootId));
2280
- }
2281
-
2282
- async unwatchThread(threadRootId: string): Promise<void> {
2283
- return this.request('DELETE', ENDPOINTS.MESSAGE_WATCH(threadRootId));
2284
- }
2285
-
2286
- async getThreadWatchers(threadRootId: string): Promise<ThreadWatcher[]> {
2287
- const res = await this.request<{ data: ThreadWatcher[] }>(
2288
- 'GET',
2289
- ENDPOINTS.MESSAGE_WATCHERS(threadRootId),
2290
- );
2291
- return res.data;
2292
- }
2293
-
2294
- async isWatchingThread(threadRootId: string): Promise<boolean> {
2295
- const res = await this.request<{ watching: boolean }>(
2296
- 'GET',
2297
- ENDPOINTS.MESSAGE_WATCHING(threadRootId),
2298
- );
2299
- return res.watching;
2300
- }
2301
-
2302
- async getSubtasks(orgId: string, taskId: string): Promise<Task[]> {
2303
- const res = await this.request<PaginatedResponse<Task>>(
2304
- 'GET',
2305
- ENDPOINTS.TASK_SUBTASKS(orgId, taskId),
2306
- );
2307
- return res.data;
2308
- }
2309
-
2310
- async createTaskRelation(
2311
- orgId: string,
2312
- taskId: string,
2313
- data: CreateTaskRelationRequest,
2314
- ): Promise<TaskRelation> {
2315
- return this.request('POST', ENDPOINTS.TASK_RELATIONS(orgId, taskId), data);
2316
- }
2317
-
2318
- async getTaskRelations(orgId: string, taskId: string): Promise<TaskRelation[]> {
2319
- const res = await this.request<{ data: TaskRelation[] }>(
2320
- 'GET',
2321
- ENDPOINTS.TASK_RELATIONS(orgId, taskId),
2322
- );
2323
- return res.data;
2324
- }
2325
-
2326
- async listTaskRelationsByTarget(
2327
- orgId: string,
2328
- params: { target_type: TaskRelationTargetType; target_id: string },
2329
- ): Promise<TaskRelation[]> {
2330
- const query = new URLSearchParams({
2331
- target_type: params.target_type,
2332
- target_id: params.target_id,
2333
- });
2334
- const res = await this.request<{ data: TaskRelation[] }>(
2335
- 'GET',
2336
- `${ENDPOINTS.TASK_RELATIONS_BY_TARGET(orgId)}?${query.toString()}`,
2337
- );
2338
- return res.data;
2339
- }
2340
-
2341
- async deleteTaskRelation(orgId: string, taskId: string, relationId: string): Promise<void> {
2342
- return this.request('DELETE', ENDPOINTS.TASK_RELATION(orgId, taskId, relationId));
2343
- }
2344
-
2345
- // ---- Task Comments ----
2346
-
2347
- async getTaskComments(
2348
- orgId: string,
2349
- taskId: string,
2350
- params?: {
2351
- limit?: number;
2352
- cursor?: string;
2353
- order?: string;
2354
- },
2355
- ): Promise<PaginatedResponse<TaskComment>> {
2356
- return this.request('GET', ENDPOINTS.TASK_COMMENTS(orgId, taskId), undefined, params);
2357
- }
2358
-
2359
- async getTaskComment(orgId: string, taskId: string, commentId: string): Promise<TaskComment> {
2360
- return this.request('GET', ENDPOINTS.TASK_COMMENT(orgId, taskId, commentId));
2361
- }
2362
-
2363
- async createTaskComment(
2364
- orgId: string,
2365
- taskId: string,
2366
- data: CreateTaskCommentRequest,
2367
- ): Promise<TaskComment> {
2368
- return this.request('POST', ENDPOINTS.TASK_COMMENTS(orgId, taskId), data);
2369
- }
2370
-
2371
- async updateTaskComment(
2372
- orgId: string,
2373
- taskId: string,
2374
- commentId: string,
2375
- data: UpdateTaskCommentRequest,
2376
- ): Promise<TaskComment> {
2377
- return this.request('PATCH', ENDPOINTS.TASK_COMMENT(orgId, taskId, commentId), data);
2378
- }
2379
-
2380
- async deleteTaskComment(orgId: string, taskId: string, commentId: string): Promise<void> {
2381
- return this.request('DELETE', ENDPOINTS.TASK_COMMENT(orgId, taskId, commentId));
2382
- }
2383
-
2384
- // ---- Task Activities ----
2385
-
2386
- async getTaskActivities(
2387
- orgId: string,
2388
- taskId: string,
2389
- params?: {
2390
- limit?: number;
2391
- cursor?: string;
2392
- },
2393
- ): Promise<PaginatedResponse<TaskActivity>> {
2394
- return this.request('GET', ENDPOINTS.TASK_ACTIVITIES(orgId, taskId), undefined, params);
2395
- }
2396
-
2397
- // ---- Projects (org-scoped) ----
2398
-
2399
- async createProject(orgId: string, data: CreateProjectRequest): Promise<Project> {
2400
- return this.request('POST', ENDPOINTS.PROJECTS(orgId), data);
2401
- }
2402
-
2403
- async getProjects(orgId: string): Promise<Project[]> {
2404
- const res = await this.request<{ data: Project[] }>('GET', ENDPOINTS.PROJECTS(orgId));
2405
- return res.data;
2406
- }
2407
-
2408
- async getProject(orgId: string, projectId: string): Promise<Project> {
2409
- return this.request('GET', ENDPOINTS.PROJECT(orgId, projectId));
2410
- }
2411
-
2412
- async updateProject(
2413
- orgId: string,
2414
- projectId: string,
2415
- data: UpdateProjectRequest,
2416
- ): Promise<Project> {
2417
- return this.request('PATCH', ENDPOINTS.PROJECT(orgId, projectId), data);
2418
- }
2419
-
2420
- async deleteProject(orgId: string, projectId: string): Promise<void> {
2421
- return this.request('DELETE', ENDPOINTS.PROJECT(orgId, projectId));
2422
- }
2423
-
2424
2258
  // ---- Schedules (org-scoped) ----
2425
2259
 
2426
2260
  async createSchedule(orgId: string, input: CreateScheduleInput): Promise<Schedule> {
@@ -2684,13 +2518,29 @@ export class ParallClient {
2684
2518
 
2685
2519
  /**
2686
2520
  * WeChat tier-B read verb (agent-only; internal research preview): the
2687
- * account's address book — friend wxids, saved group room ids, followed
2688
- * official accounts. Same live gate as the send verb.
2521
+ * account's address book — friends/chatrooms enriched with display names,
2522
+ * followed official accounts. Same live gate as the send verb.
2689
2523
  */
2690
2524
  async listWechatContacts(orgId: string): Promise<WechatContactsPage> {
2691
2525
  return this.request('GET', ENDPOINTS.WECHAT_CONTACTS(orgId));
2692
2526
  }
2693
2527
 
2528
+ /**
2529
+ * WeChat tier-B read verb (agent-only): the connected account's identity
2530
+ * (wxid / alias / nickName / app id).
2531
+ */
2532
+ async wechatProfile(orgId: string): Promise<WechatProfileView> {
2533
+ return this.request('GET', ENDPOINTS.WECHAT_PROFILE(orgId));
2534
+ }
2535
+
2536
+ /**
2537
+ * WeChat tier-B read verb (agent-only): live online probe + identity +
2538
+ * the platform's offline record.
2539
+ */
2540
+ async wechatStatus(orgId: string): Promise<WechatStatusView> {
2541
+ return this.request('GET', ENDPOINTS.WECHAT_STATUS(orgId));
2542
+ }
2543
+
2694
2544
  async listChannelConversations(
2695
2545
  orgId: string,
2696
2546
  connectionId: string,
@@ -3360,7 +3210,8 @@ export class ParallClient {
3360
3210
 
3361
3211
  // ---- Feature Flags (org-scoped, server-evaluated) ----
3362
3212
 
3363
- async getFeatureFlags(orgId: string): Promise<FeatureFlagsResponse> {
3213
+ /** Omit orgId to resolve deployment capabilities before joining an org. */
3214
+ async getFeatureFlags(orgId?: string): Promise<FeatureFlagsResponse> {
3364
3215
  return this.request('GET', ENDPOINTS.FEATURE_FLAGS(orgId));
3365
3216
  }
3366
3217
 
@@ -3391,10 +3242,67 @@ export class ParallClient {
3391
3242
  });
3392
3243
  }
3393
3244
 
3245
+ /** Queue a template deployment and poll its durable deployment row. Each
3246
+ * request is short-lived; closing the client does not cancel server work. */
3247
+ async deployTemplateAsync(
3248
+ orgId: string,
3249
+ request: DeployTemplateRequest,
3250
+ idempotencyKey: string,
3251
+ ): Promise<TemplateDeploymentReport> {
3252
+ const queue = () =>
3253
+ this.request<TemplateDeploymentResult>('POST', ENDPOINTS.TEMPLATE_DEPLOYMENTS(orgId), {
3254
+ ...request,
3255
+ async: true,
3256
+ idempotency_key: idempotencyKey,
3257
+ });
3258
+
3259
+ let result: TemplateDeploymentResult | undefined;
3260
+ for (let attempt = 0; attempt < 2 && result === undefined; attempt += 1) {
3261
+ try {
3262
+ result = await queue();
3263
+ } catch (error) {
3264
+ // A lost response or transient server failure is safe to retry because
3265
+ // the key resolves to the same deployment row rather than starting a
3266
+ // second team. A second transient failure remains outcome-unknown.
3267
+ if (!(error instanceof ApiError) || (error.status !== 0 && error.status < 500)) throw error;
3268
+ }
3269
+ }
3270
+ if (result === undefined) {
3271
+ throw new ApiError(0, 'Template deployment request outcome is unknown', 'NETWORK_ERROR');
3272
+ }
3273
+
3274
+ const deadline = Date.now() + 30 * 60 * 1000;
3275
+ while (result.status === 'queued' || result.status === 'deploying') {
3276
+ if (Date.now() >= deadline) {
3277
+ throw new ApiError(0, 'Template deployment is still running', 'REQUEST_TIMEOUT');
3278
+ }
3279
+ await new Promise((resolve) => setTimeout(resolve, 2000));
3280
+ try {
3281
+ result = await this.request<TemplateDeploymentResult>(
3282
+ 'GET',
3283
+ ENDPOINTS.TEMPLATE_DEPLOYMENT(orgId, result.deployment_id),
3284
+ );
3285
+ } catch (error) {
3286
+ if (!(error instanceof ApiError) || (error.status !== 0 && error.status < 500)) throw error;
3287
+ // A network failure or transient server error does not change the
3288
+ // durable deployment. Keep polling instead of presenting a definite
3289
+ // failure that could make a fresh-key retry create another team.
3290
+ }
3291
+ }
3292
+ if (result.status !== 'deployed') {
3293
+ throw new ApiError(
3294
+ 500,
3295
+ result.error?.message ?? 'Template deployment failed',
3296
+ result.error?.code,
3297
+ );
3298
+ }
3299
+ return result;
3300
+ }
3301
+
3394
3302
  async getTemplateDeployment(
3395
3303
  orgId: string,
3396
3304
  deploymentId: string,
3397
- ): Promise<TemplateDeploymentReport> {
3305
+ ): Promise<TemplateDeploymentResult> {
3398
3306
  return this.request('GET', ENDPOINTS.TEMPLATE_DEPLOYMENT(orgId, deploymentId));
3399
3307
  }
3400
3308
 
@@ -3717,6 +3625,15 @@ export class ParallClient {
3717
3625
  await this.request<void>('DELETE', ENDPOINTS.ORG_CLIP_UNINSTALL(orgId, clipId));
3718
3626
  }
3719
3627
 
3628
+ /** Best-effort provider revoke followed by atomic local removal of an
3629
+ * installed Official MCP Clip and all org-owned connection state. */
3630
+ async removeOfficialMCPClip(
3631
+ orgId: string,
3632
+ clipId: string,
3633
+ ): Promise<MCPOfficialClipRemovalResponse> {
3634
+ return this.request('DELETE', ENDPOINTS.ORG_CLIP_MCP_REMOVE(orgId, clipId));
3635
+ }
3636
+
3720
3637
  /** List the org's installed registry clips (full entries). */
3721
3638
  async listInstalledRegistryClips(orgId: string): Promise<ClipRegistryEntry[]> {
3722
3639
  const resp = await this.request<ClipRegistryEntry[] | null>(
@@ -3993,13 +3910,15 @@ export class ParallClient {
3993
3910
  return this.request('DELETE', ENDPOINTS.CLIP_CONNECTION(orgId, connId));
3994
3911
  }
3995
3912
 
3996
- // ---- MCP clip server config (cap:clip-mcp; publisher-org only) ----
3913
+ // ---- MCP clip server config (same-org or reviewed Official OAuth) ----
3997
3914
 
3998
3915
  /**
3999
- * Read the redacted MCP config. 404 NOT_FOUND when the clip has none yet;
4000
- * 403 MCP_CROSS_ORG_DISABLED for a cross-org installed clip (the whole
4001
- * mcp-config family is publisher-org property, reads included). `version`
4002
- * is the CAS token the mutations echo via If-Match.
3916
+ * Read the redacted MCP config. 404 NOT_FOUND when the clip has none yet
3917
+ * and also when a cross-org clip is not public + approved + installed, which
3918
+ * reads as nonexistent rather than refused (same existence-hiding as exec).
3919
+ * A cross-org clip that IS installed and approved reads fine regardless of
3920
+ * auth shape; what may then be configured is decided per credential owner.
3921
+ * `version` is the CAS token the mutations echo via If-Match.
4003
3922
  */
4004
3923
  async getClipMCPConfig(orgId: string, clipId: string): Promise<MCPConfigResponse> {
4005
3924
  return this.request('GET', ENDPOINTS.ORG_CLIP_MCP_CONFIG(orgId, clipId));
@@ -4054,6 +3973,40 @@ export class ParallClient {
4054
3973
  );
4055
3974
  }
4056
3975
 
3976
+ /**
3977
+ * List the org's MCP connections for a clip, default first — one row per
3978
+ * connection (credential slot), WITHOUT the tools snapshot (`tool_count`
3979
+ * summarizes it; the per-config GET carries the full snapshot). Same
3980
+ * family-wide fence as the singular GET: same-org clips, or a cross-org clip
3981
+ * that is public + approved + installed; anything else reads as
3982
+ * `404 NOT_FOUND`. An installed cross-org clip with no connection yet lists
3983
+ * as an empty array — including one whose approved auth mode cannot be
3984
+ * configured at all (auth=none), which the write path is what refuses. With
3985
+ * `cap:clip-mcp` off the route is not registered at all.
3986
+ */
3987
+ async listClipMCPConnections(
3988
+ orgId: string,
3989
+ clipId: string,
3990
+ ): Promise<{ data: MCPConnectionSummary[] }> {
3991
+ return this.request('GET', ENDPOINTS.ORG_CLIP_MCP_CONFIGS(orgId, clipId));
3992
+ }
3993
+
3994
+ /** Start a new Official OAuth MCP connection with the platform-owned app.
3995
+ * Omitting oauth_client is load-bearing: the server resolves the exact
3996
+ * reviewed-version binding and never falls back to DCR/CIMD cross-org. */
3997
+ async createClipMCPOAuthConnection(
3998
+ orgId: string,
3999
+ clipId: string,
4000
+ serverUrl: string,
4001
+ alias?: string,
4002
+ ): Promise<MCPOAuthInitiateResponse> {
4003
+ return this.request('POST', ENDPOINTS.ORG_CLIP_MCP_CONFIGS(orgId, clipId), {
4004
+ server_url: serverUrl,
4005
+ auth_type: 'oauth',
4006
+ ...(alias ? { alias } : {}),
4007
+ });
4008
+ }
4009
+
4057
4010
  /**
4058
4011
  * Re-run tools/list and replace the cached snapshot (org-admin only).
4059
4012
  * Deliberately does NOT advance the CAS version, so an in-flight edit in