@parall/sdk 1.54.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,263 +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
- MCPConnectionSummary,
250
- EdgeOnboardingStatus,
251
- ExecEdgeClipRequest,
252
- EdgeClipExecResult,
253
- ReactionSummary,
254
- ToggleReactionResponse,
255
- DependencyCheckResult,
256
- DeployTemplateRequest,
257
- 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,
258
203
  Template,
259
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,
260
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,
261
258
  } from './types.js';
262
259
 
263
260
  export interface ParallClientOptions {
@@ -280,7 +277,7 @@ export interface ParallClientOptions {
280
277
  getFeatureFlagOverrides?: () => string | null | undefined;
281
278
  }
282
279
 
283
- export class ParallClient {
280
+ export class ParallClient extends TaskLabelClient {
284
281
  private baseUrl: string;
285
282
  private wikiBaseUrl: string;
286
283
  private token: string | null;
@@ -351,6 +348,7 @@ export class ParallClient {
351
348
  }
352
349
 
353
350
  constructor(options: ParallClientOptions = {}) {
351
+ super();
354
352
  this.baseUrl = options.baseUrl ?? '';
355
353
  // Defaults to baseUrl so existing single-origin consumers (web, desktop,
356
354
  // hosted agents behind one gateway) are unchanged; only split api/wiki
@@ -438,7 +436,7 @@ export class ParallClient {
438
436
  }
439
437
  }
440
438
 
441
- private async request<T>(
439
+ protected async request<T>(
442
440
  method: string,
443
441
  path: string,
444
442
  body?: unknown,
@@ -692,7 +690,8 @@ export class ParallClient {
692
690
 
693
691
  async createOrg(data: {
694
692
  name: string;
695
- invite_code: string;
693
+ /** Omitted when the deployment reports `cap:org-invite-code` disabled. */
694
+ invite_code?: string;
696
695
  avatar_url?: string;
697
696
  }): Promise<Organization> {
698
697
  return this.request('POST', ENDPOINTS.ORGS, data);
@@ -749,6 +748,60 @@ export class ParallClient {
749
748
  return res.data;
750
749
  }
751
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
+
752
805
  async getOnlineMembers(orgId: string): Promise<string[]> {
753
806
  const res = await this.request<{ user_ids: string[] }>(
754
807
  'GET',
@@ -2202,226 +2255,6 @@ export class ParallClient {
2202
2255
  return res.json() as Promise<PlatformConfigResponse>;
2203
2256
  }
2204
2257
 
2205
- // ---- Tasks (org-scoped) ----
2206
-
2207
- async createTask(orgId: string, data: CreateTaskRequest): Promise<Task> {
2208
- return this.request('POST', ENDPOINTS.TASKS(orgId), data);
2209
- }
2210
-
2211
- async getTasks(
2212
- orgId: string,
2213
- params?: {
2214
- q?: string;
2215
- status?: string;
2216
- priority?: string;
2217
- assignee_id?: string;
2218
- parent_id?: string;
2219
- project_id?: string;
2220
- limit?: number;
2221
- cursor?: string;
2222
- sort?: string;
2223
- order?: string;
2224
- scope?: 'active' | 'archived' | 'all';
2225
- },
2226
- ): Promise<PaginatedResponse<Task>> {
2227
- return this.request('GET', ENDPOINTS.TASKS(orgId), undefined, params);
2228
- }
2229
-
2230
- async getTask(orgId: string, taskId: string): Promise<Task> {
2231
- return this.request('GET', ENDPOINTS.TASK(orgId, taskId));
2232
- }
2233
-
2234
- async updateTask(orgId: string, taskId: string, data: UpdateTaskRequest): Promise<Task> {
2235
- return this.request('PATCH', ENDPOINTS.TASK(orgId, taskId), data);
2236
- }
2237
-
2238
- async deleteTask(orgId: string, taskId: string, opts?: { force?: boolean }): Promise<void> {
2239
- return this.request(
2240
- 'DELETE',
2241
- ENDPOINTS.TASK(orgId, taskId),
2242
- undefined,
2243
- opts?.force ? { force: 'true' } : undefined,
2244
- );
2245
- }
2246
-
2247
- async archiveTask(orgId: string, taskId: string): Promise<void> {
2248
- return this.request('POST', ENDPOINTS.TASK_ARCHIVE(orgId, taskId));
2249
- }
2250
-
2251
- async restoreTask(orgId: string, taskId: string): Promise<void> {
2252
- return this.request('POST', ENDPOINTS.TASK_RESTORE(orgId, taskId));
2253
- }
2254
-
2255
- async watchTask(orgId: string, taskId: string): Promise<void> {
2256
- return this.request('POST', ENDPOINTS.TASK_WATCH(orgId, taskId));
2257
- }
2258
-
2259
- async unwatchTask(orgId: string, taskId: string): Promise<void> {
2260
- return this.request('DELETE', ENDPOINTS.TASK_WATCH(orgId, taskId));
2261
- }
2262
-
2263
- async getTaskWatchers(orgId: string, taskId: string): Promise<TaskWatcher[]> {
2264
- const res = await this.request<{ data: TaskWatcher[] }>(
2265
- 'GET',
2266
- ENDPOINTS.TASK_WATCHERS(orgId, taskId),
2267
- );
2268
- return res.data;
2269
- }
2270
-
2271
- async subscribeTaskMember(orgId: string, taskId: string, userId: string): Promise<void> {
2272
- return this.request('PUT', ENDPOINTS.TASK_SUBSCRIBER(orgId, taskId, userId));
2273
- }
2274
-
2275
- async unsubscribeTaskMember(orgId: string, taskId: string, userId: string): Promise<void> {
2276
- return this.request('DELETE', ENDPOINTS.TASK_SUBSCRIBER(orgId, taskId, userId));
2277
- }
2278
-
2279
- async watchThread(threadRootId: string): Promise<void> {
2280
- return this.request('POST', ENDPOINTS.MESSAGE_WATCH(threadRootId));
2281
- }
2282
-
2283
- async unwatchThread(threadRootId: string): Promise<void> {
2284
- return this.request('DELETE', ENDPOINTS.MESSAGE_WATCH(threadRootId));
2285
- }
2286
-
2287
- async getThreadWatchers(threadRootId: string): Promise<ThreadWatcher[]> {
2288
- const res = await this.request<{ data: ThreadWatcher[] }>(
2289
- 'GET',
2290
- ENDPOINTS.MESSAGE_WATCHERS(threadRootId),
2291
- );
2292
- return res.data;
2293
- }
2294
-
2295
- async isWatchingThread(threadRootId: string): Promise<boolean> {
2296
- const res = await this.request<{ watching: boolean }>(
2297
- 'GET',
2298
- ENDPOINTS.MESSAGE_WATCHING(threadRootId),
2299
- );
2300
- return res.watching;
2301
- }
2302
-
2303
- async getSubtasks(orgId: string, taskId: string): Promise<Task[]> {
2304
- const res = await this.request<PaginatedResponse<Task>>(
2305
- 'GET',
2306
- ENDPOINTS.TASK_SUBTASKS(orgId, taskId),
2307
- );
2308
- return res.data;
2309
- }
2310
-
2311
- async createTaskRelation(
2312
- orgId: string,
2313
- taskId: string,
2314
- data: CreateTaskRelationRequest,
2315
- ): Promise<TaskRelation> {
2316
- return this.request('POST', ENDPOINTS.TASK_RELATIONS(orgId, taskId), data);
2317
- }
2318
-
2319
- async getTaskRelations(orgId: string, taskId: string): Promise<TaskRelation[]> {
2320
- const res = await this.request<{ data: TaskRelation[] }>(
2321
- 'GET',
2322
- ENDPOINTS.TASK_RELATIONS(orgId, taskId),
2323
- );
2324
- return res.data;
2325
- }
2326
-
2327
- async listTaskRelationsByTarget(
2328
- orgId: string,
2329
- params: { target_type: TaskRelationTargetType; target_id: string },
2330
- ): Promise<TaskRelation[]> {
2331
- const query = new URLSearchParams({
2332
- target_type: params.target_type,
2333
- target_id: params.target_id,
2334
- });
2335
- const res = await this.request<{ data: TaskRelation[] }>(
2336
- 'GET',
2337
- `${ENDPOINTS.TASK_RELATIONS_BY_TARGET(orgId)}?${query.toString()}`,
2338
- );
2339
- return res.data;
2340
- }
2341
-
2342
- async deleteTaskRelation(orgId: string, taskId: string, relationId: string): Promise<void> {
2343
- return this.request('DELETE', ENDPOINTS.TASK_RELATION(orgId, taskId, relationId));
2344
- }
2345
-
2346
- // ---- Task Comments ----
2347
-
2348
- async getTaskComments(
2349
- orgId: string,
2350
- taskId: string,
2351
- params?: {
2352
- limit?: number;
2353
- cursor?: string;
2354
- order?: string;
2355
- },
2356
- ): Promise<PaginatedResponse<TaskComment>> {
2357
- return this.request('GET', ENDPOINTS.TASK_COMMENTS(orgId, taskId), undefined, params);
2358
- }
2359
-
2360
- async getTaskComment(orgId: string, taskId: string, commentId: string): Promise<TaskComment> {
2361
- return this.request('GET', ENDPOINTS.TASK_COMMENT(orgId, taskId, commentId));
2362
- }
2363
-
2364
- async createTaskComment(
2365
- orgId: string,
2366
- taskId: string,
2367
- data: CreateTaskCommentRequest,
2368
- ): Promise<TaskComment> {
2369
- return this.request('POST', ENDPOINTS.TASK_COMMENTS(orgId, taskId), data);
2370
- }
2371
-
2372
- async updateTaskComment(
2373
- orgId: string,
2374
- taskId: string,
2375
- commentId: string,
2376
- data: UpdateTaskCommentRequest,
2377
- ): Promise<TaskComment> {
2378
- return this.request('PATCH', ENDPOINTS.TASK_COMMENT(orgId, taskId, commentId), data);
2379
- }
2380
-
2381
- async deleteTaskComment(orgId: string, taskId: string, commentId: string): Promise<void> {
2382
- return this.request('DELETE', ENDPOINTS.TASK_COMMENT(orgId, taskId, commentId));
2383
- }
2384
-
2385
- // ---- Task Activities ----
2386
-
2387
- async getTaskActivities(
2388
- orgId: string,
2389
- taskId: string,
2390
- params?: {
2391
- limit?: number;
2392
- cursor?: string;
2393
- },
2394
- ): Promise<PaginatedResponse<TaskActivity>> {
2395
- return this.request('GET', ENDPOINTS.TASK_ACTIVITIES(orgId, taskId), undefined, params);
2396
- }
2397
-
2398
- // ---- Projects (org-scoped) ----
2399
-
2400
- async createProject(orgId: string, data: CreateProjectRequest): Promise<Project> {
2401
- return this.request('POST', ENDPOINTS.PROJECTS(orgId), data);
2402
- }
2403
-
2404
- async getProjects(orgId: string): Promise<Project[]> {
2405
- const res = await this.request<{ data: Project[] }>('GET', ENDPOINTS.PROJECTS(orgId));
2406
- return res.data;
2407
- }
2408
-
2409
- async getProject(orgId: string, projectId: string): Promise<Project> {
2410
- return this.request('GET', ENDPOINTS.PROJECT(orgId, projectId));
2411
- }
2412
-
2413
- async updateProject(
2414
- orgId: string,
2415
- projectId: string,
2416
- data: UpdateProjectRequest,
2417
- ): Promise<Project> {
2418
- return this.request('PATCH', ENDPOINTS.PROJECT(orgId, projectId), data);
2419
- }
2420
-
2421
- async deleteProject(orgId: string, projectId: string): Promise<void> {
2422
- return this.request('DELETE', ENDPOINTS.PROJECT(orgId, projectId));
2423
- }
2424
-
2425
2258
  // ---- Schedules (org-scoped) ----
2426
2259
 
2427
2260
  async createSchedule(orgId: string, input: CreateScheduleInput): Promise<Schedule> {
@@ -2685,13 +2518,29 @@ export class ParallClient {
2685
2518
 
2686
2519
  /**
2687
2520
  * WeChat tier-B read verb (agent-only; internal research preview): the
2688
- * account's address book — friend wxids, saved group room ids, followed
2689
- * 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.
2690
2523
  */
2691
2524
  async listWechatContacts(orgId: string): Promise<WechatContactsPage> {
2692
2525
  return this.request('GET', ENDPOINTS.WECHAT_CONTACTS(orgId));
2693
2526
  }
2694
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
+
2695
2544
  async listChannelConversations(
2696
2545
  orgId: string,
2697
2546
  connectionId: string,
@@ -3361,7 +3210,8 @@ export class ParallClient {
3361
3210
 
3362
3211
  // ---- Feature Flags (org-scoped, server-evaluated) ----
3363
3212
 
3364
- async getFeatureFlags(orgId: string): Promise<FeatureFlagsResponse> {
3213
+ /** Omit orgId to resolve deployment capabilities before joining an org. */
3214
+ async getFeatureFlags(orgId?: string): Promise<FeatureFlagsResponse> {
3365
3215
  return this.request('GET', ENDPOINTS.FEATURE_FLAGS(orgId));
3366
3216
  }
3367
3217
 
@@ -3392,10 +3242,67 @@ export class ParallClient {
3392
3242
  });
3393
3243
  }
3394
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
+
3395
3302
  async getTemplateDeployment(
3396
3303
  orgId: string,
3397
3304
  deploymentId: string,
3398
- ): Promise<TemplateDeploymentReport> {
3305
+ ): Promise<TemplateDeploymentResult> {
3399
3306
  return this.request('GET', ENDPOINTS.TEMPLATE_DEPLOYMENT(orgId, deploymentId));
3400
3307
  }
3401
3308
 
@@ -3718,6 +3625,15 @@ export class ParallClient {
3718
3625
  await this.request<void>('DELETE', ENDPOINTS.ORG_CLIP_UNINSTALL(orgId, clipId));
3719
3626
  }
3720
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
+
3721
3637
  /** List the org's installed registry clips (full entries). */
3722
3638
  async listInstalledRegistryClips(orgId: string): Promise<ClipRegistryEntry[]> {
3723
3639
  const resp = await this.request<ClipRegistryEntry[] | null>(
@@ -3994,13 +3910,15 @@ export class ParallClient {
3994
3910
  return this.request('DELETE', ENDPOINTS.CLIP_CONNECTION(orgId, connId));
3995
3911
  }
3996
3912
 
3997
- // ---- MCP clip server config (cap:clip-mcp; publisher-org only) ----
3913
+ // ---- MCP clip server config (same-org or reviewed Official OAuth) ----
3998
3914
 
3999
3915
  /**
4000
- * Read the redacted MCP config. 404 NOT_FOUND when the clip has none yet;
4001
- * 403 MCP_CROSS_ORG_DISABLED for a cross-org installed clip (the whole
4002
- * mcp-config family is publisher-org property, reads included). `version`
4003
- * 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.
4004
3922
  */
4005
3923
  async getClipMCPConfig(orgId: string, clipId: string): Promise<MCPConfigResponse> {
4006
3924
  return this.request('GET', ENDPOINTS.ORG_CLIP_MCP_CONFIG(orgId, clipId));
@@ -4059,8 +3977,11 @@ export class ParallClient {
4059
3977
  * List the org's MCP connections for a clip, default first — one row per
4060
3978
  * connection (credential slot), WITHOUT the tools snapshot (`tool_count`
4061
3979
  * summarizes it; the per-config GET carries the full snapshot). Same
4062
- * family-wide fence as the singular GET: publisher-org members only
4063
- * cross-org installs get `403 MCP_CROSS_ORG_DISABLED`, and with
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
4064
3985
  * `cap:clip-mcp` off the route is not registered at all.
4065
3986
  */
4066
3987
  async listClipMCPConnections(
@@ -4070,6 +3991,22 @@ export class ParallClient {
4070
3991
  return this.request('GET', ENDPOINTS.ORG_CLIP_MCP_CONFIGS(orgId, clipId));
4071
3992
  }
4072
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
+
4073
4010
  /**
4074
4011
  * Re-run tools/list and replace the cached snapshot (org-admin only).
4075
4012
  * Deliberately does NOT advance the CAS version, so an in-flight edit in