@parall/sdk 1.54.0 → 1.55.1

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,263 @@
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
+ ClipAgentExecAccessUpdate,
51
+ ClipConnection,
52
+ ClipRegistryEntry,
53
+ Comment,
10
54
  CompleteDispatchByIDRequest,
11
55
  CompleteDispatchBySourceResult,
12
56
  CompleteDispatchLaneRequest,
13
57
  CompleteDispatchRequest,
14
- CompleteDispatchSourceFormRequest,
15
58
  CompleteDispatchResult,
59
+ CompleteDispatchSourceFormRequest,
16
60
  CompleteDispatchSourcesRequest,
17
61
  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,
62
+ CompleteRuntimeAuthSessionRequest,
63
+ ComputePricing,
64
+ ComputePricingResponse,
65
+ CopyWikiFileRequest,
66
+ CopyWikiFileResponse,
49
67
  CreateAgentRequest,
50
68
  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,
69
+ CreateAgentSessionRequest,
70
+ CreateAgentStepRequest,
71
+ CreateApprovalRequest,
72
+ CreateBrowserProfileRequest,
73
+ CreateChannelConnectionInput,
74
+ CreateChatRequest,
75
+ CreateCheckoutRequest,
76
+ CreateCheckoutResponse,
77
+ CreateClipRequest,
78
+ CreateCommentRequest,
79
+ CreateExternalConnectionInput,
80
+ CreateExternalTriggerInput,
89
81
  CreateScheduleInput,
90
- UpdateScheduleInput,
91
- ScheduleFilters,
92
- ScheduleRunFilters,
82
+ CreateSetupIntentResponse,
83
+ CreateTeamRequest,
84
+ CreateWikiAccessRequest,
85
+ CreateWikiChangesetRequest,
86
+ CreateWikiPathRestrictionRequest,
87
+ CreateWikiPathScopeRequest,
88
+ CreateWikiRequest,
89
+ CreditTransaction,
90
+ CreditTransactionAgentGroup,
91
+ CreditTransactionMachineGroup,
92
+ DaemonAgentConfig,
93
+ DependencyCheckResult,
94
+ DeployTemplateRequest,
95
+ DetectedRuntime,
96
+ DirectMessageResponse,
97
+ DiscoverableChat,
98
+ DispatchEvent,
99
+ DispatchExpireResult,
100
+ EdgeBrowserProfile,
101
+ EdgeClipExecResult,
102
+ EdgeCookieSeedStatus,
103
+ EdgeDevice,
104
+ EdgeOnboardingStatus,
105
+ EdgePlacement,
106
+ EdgeProfileProxyStatus,
107
+ EdgeViewerCommandRequest,
108
+ EdgeViewerCommandResponse,
109
+ ExecEdgeClipRequest,
93
110
  ExternalConnection,
94
- CreateExternalConnectionInput,
95
- UpdateExternalConnectionInput,
96
111
  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
112
  ExternalIngressEvent,
116
113
  ExternalIngressEventFilters,
117
114
  ExternalTrigger,
118
- CreateExternalTriggerInput,
119
- UpdateExternalTriggerInput,
120
115
  ExternalTriggerFilters,
121
116
  ExternalTriggerRun,
122
117
  ExternalTriggerRunFilters,
123
118
  ExternalTriggerSchema,
124
- AgentSessionDB,
125
- AgentStep,
126
- CreateAgentSessionRequest,
127
- CreateAgentStepRequest,
128
- UpdateAgentSessionRequest,
119
+ FeatureFlagsResponse,
120
+ FilesystemEntry,
121
+ FileUrlResponse,
122
+ GrantBrowserProfileConsentRequest,
123
+ InboxItem,
124
+ InboxUnreadCountResponse,
125
+ InitiateChannelProvisioningInput,
126
+ InstallRegistryClipResponse,
127
+ InvitationPublicInfo,
128
+ InvokeClipRequest,
129
+ InvokeClipResponse,
130
+ JoinByLinkResponse,
131
+ LaunchCredentialResponse,
132
+ LoginRequest,
133
+ Machine,
134
+ MachineBrowserProfile,
135
+ MachineBrowserProfileViewerResponse,
136
+ MachineCapability,
137
+ MachineClip,
138
+ MachineKey,
139
+ MachineRuntimeAuthState,
140
+ MCPConfigPutRequest,
141
+ MCPConfigResponse,
142
+ MCPConnectionSummary,
143
+ MCPOAuthInitiateResponse,
144
+ MCPOfficialClipRemovalResponse,
145
+ MemberProfile,
146
+ Message,
129
147
  NewSessionResponse,
148
+ NotificationPreferences,
149
+ NotifPrefs,
150
+ OnboardingProgress,
151
+ OnlineClipInfo,
152
+ Organization,
130
153
  OrgInvitation,
131
- InvitationPublicInfo,
132
154
  OrgInviteLink,
133
- JoinByLinkResponse,
134
155
  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,
156
+ OrgMember,
157
+ OrgMemberRole,
178
158
  OutboundRefsRequest,
179
159
  OutboundRefsResponse,
180
- RefGraphResponse,
181
- BrokenRefsResponse,
160
+ PaginatedResponse,
161
+ PlatformConfigResponse,
162
+ PlatformModelsResponse,
163
+ PresignResponse,
164
+ PresignUploadRequest,
165
+ PublishRegistryClipRequest,
182
166
  PushSubscribeRequest,
183
- NotifPrefs,
184
- NotificationPreferences,
185
- FeatureFlagsResponse,
186
- RuntimeAuthSession,
167
+ ReactionSummary,
168
+ RefGraphResponse,
169
+ RefSearchResponse,
170
+ RegisterRequest,
171
+ RegisterResponse,
172
+ ResizeMachineRequest,
173
+ ResolveRefsResponse,
187
174
  RuntimeAuthConnectedState,
188
- StartRuntimeAuthSessionRequest,
189
- CompleteRuntimeAuthSessionRequest,
190
- RuntimeStatus,
175
+ RuntimeAuthSession,
191
176
  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
177
  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,
178
+ RuntimeRelease,
179
+ RuntimeStatus,
180
+ Schedule,
181
+ ScheduleFilters,
182
+ ScheduleRun,
183
+ ScheduleRunFilters,
184
+ SearchParams,
185
+ SearchResponse,
186
+ SendChannelMessageInput,
187
+ SendDirectMessageRequest,
188
+ SendMessageRequest,
189
+ SentChannelMessage,
190
+ SetEdgeCookieSeedRequest,
245
191
  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,
192
+ SetRuntimeModeRequest,
193
+ SlackChannelsPage,
194
+ SlackHistoryPage,
195
+ SlackManifestLinkResult,
196
+ SlackMembersPage,
197
+ SlackReadPageQuery,
198
+ SlackStatusInput,
199
+ SlackUsersPage,
200
+ StartRuntimeAuthSessionRequest,
201
+ SteerDispatchRequest,
202
+ SteerDispatchResponse,
203
+ Task,
204
+ Team,
205
+ TeamMember,
258
206
  Template,
259
207
  TemplateDeploymentReport,
208
+ TemplateDeploymentResult,
209
+ ThreadUnreadEntry,
210
+ ToggleReactionResponse,
211
+ TransferChatOwnershipRequest,
212
+ UnreadEntry,
213
+ UpdateAgentInstructionsRequest,
214
+ UpdateAgentProviderConfigRequest,
215
+ UpdateAgentRequest,
216
+ UpdateAgentSessionRequest,
217
+ UpdateAutoReloadRequest,
218
+ UpdateBrowserProfileRequest,
219
+ UpdateChannelConnectionInput,
220
+ UpdateChatMemberRequest,
221
+ UpdateClipRequest,
222
+ UpdateCommentRequest,
223
+ UpdateDispatchInputStateRequest,
224
+ UpdateDispatchInputStateResponse,
225
+ UpdateExternalConnectionInput,
226
+ UpdateExternalTriggerInput,
227
+ UpdateMemberProfileRequest,
260
228
  UpdateOnboardingProgressRequest,
229
+ UpdateScheduleInput,
230
+ UpdateTeamMemberRequest,
231
+ UpdateTeamRequest,
232
+ UpdateWikiChangesetRequest,
233
+ User,
234
+ WechatContactsPage,
235
+ WechatProfileView,
236
+ WechatStatusView,
237
+ Wiki,
238
+ WikiAccessStatus,
239
+ WikiAnchorResolveRequest,
240
+ WikiAnchorResolveResponse,
241
+ WikiAnchorStatusRequest,
242
+ WikiAnchorStatusResponse,
243
+ WikiBlameEntry,
244
+ WikiBlob,
245
+ WikiChangeset,
246
+ WikiCommit,
247
+ WikiDiff,
248
+ WikiFilePreviewUrlResponse,
249
+ WikiFileUploadResponse,
250
+ WikiNodeSectionArtifact,
251
+ WikiOperation,
252
+ WikiOperationsResponse,
253
+ WikiPageIndex,
254
+ WikiPathRestriction,
255
+ WikiPathScope,
256
+ WikiRefsCheckResponse,
257
+ WikiRefsResponse,
258
+ WikiSearchResponse,
259
+ WikiTreeResponse,
260
+ WsTicketResponse,
261
261
  } from './types.js';
262
262
 
263
263
  export interface ParallClientOptions {
@@ -280,7 +280,7 @@ export interface ParallClientOptions {
280
280
  getFeatureFlagOverrides?: () => string | null | undefined;
281
281
  }
282
282
 
283
- export class ParallClient {
283
+ export class ParallClient extends TaskLabelClient {
284
284
  private baseUrl: string;
285
285
  private wikiBaseUrl: string;
286
286
  private token: string | null;
@@ -351,6 +351,7 @@ export class ParallClient {
351
351
  }
352
352
 
353
353
  constructor(options: ParallClientOptions = {}) {
354
+ super();
354
355
  this.baseUrl = options.baseUrl ?? '';
355
356
  // Defaults to baseUrl so existing single-origin consumers (web, desktop,
356
357
  // hosted agents behind one gateway) are unchanged; only split api/wiki
@@ -438,7 +439,7 @@ export class ParallClient {
438
439
  }
439
440
  }
440
441
 
441
- private async request<T>(
442
+ protected async request<T>(
442
443
  method: string,
443
444
  path: string,
444
445
  body?: unknown,
@@ -692,7 +693,8 @@ export class ParallClient {
692
693
 
693
694
  async createOrg(data: {
694
695
  name: string;
695
- invite_code: string;
696
+ /** Omitted when the deployment reports `cap:org-invite-code` disabled. */
697
+ invite_code?: string;
696
698
  avatar_url?: string;
697
699
  }): Promise<Organization> {
698
700
  return this.request('POST', ENDPOINTS.ORGS, data);
@@ -749,6 +751,61 @@ export class ParallClient {
749
751
  return res.data;
750
752
  }
751
753
 
754
+ async getTeam(orgId: string, teamId: string): Promise<Team> {
755
+ return this.request('GET', ENDPOINTS.TEAM(orgId, teamId));
756
+ }
757
+
758
+ /** Creating, renaming and deleting a team are org-admin actions. */
759
+ async createTeam(orgId: string, req: CreateTeamRequest): Promise<Team> {
760
+ return this.request('POST', ENDPOINTS.TEAMS(orgId), req);
761
+ }
762
+
763
+ /**
764
+ * Renames a team. Renaming is an ordinary edit: ACL rows reference teams by
765
+ * ID. Names are org-unique (case-insensitive); a duplicate answers 409
766
+ * NAME_TAKEN.
767
+ */
768
+ async updateTeam(orgId: string, teamId: string, req: UpdateTeamRequest): Promise<Team> {
769
+ return this.request('PATCH', ENDPOINTS.TEAM(orgId, teamId), req);
770
+ }
771
+
772
+ async deleteTeam(orgId: string, teamId: string): Promise<void> {
773
+ return this.request('DELETE', ENDPOINTS.TEAM(orgId, teamId));
774
+ }
775
+
776
+ /** Roster with display info; members who left the org are already excluded. */
777
+ async getTeamMembers(orgId: string, teamId: string): Promise<TeamMember[]> {
778
+ const res = await this.request<{ data: TeamMember[] }>(
779
+ 'GET',
780
+ ENDPOINTS.TEAM_MEMBERS(orgId, teamId),
781
+ );
782
+ return res.data;
783
+ }
784
+
785
+ /**
786
+ * Adds an org member (human or agent) to a team. Org admins and that team's
787
+ * managers may add ordinary members; adding straight to `manager` is an
788
+ * org-admin action.
789
+ */
790
+ async addTeamMember(orgId: string, teamId: string, req: AddTeamMemberRequest): Promise<void> {
791
+ return this.request('POST', ENDPOINTS.TEAM_MEMBERS(orgId, teamId), req);
792
+ }
793
+
794
+ /** Appointing or demoting a manager is org-admin only. */
795
+ async updateTeamMember(
796
+ orgId: string,
797
+ teamId: string,
798
+ userId: string,
799
+ req: UpdateTeamMemberRequest,
800
+ ): Promise<void> {
801
+ return this.request('PATCH', ENDPOINTS.TEAM_MEMBER(orgId, teamId, userId), req);
802
+ }
803
+
804
+ /** A team manager may remove ordinary members; removing a peer manager is org-admin only. */
805
+ async removeTeamMember(orgId: string, teamId: string, userId: string): Promise<void> {
806
+ return this.request('DELETE', ENDPOINTS.TEAM_MEMBER(orgId, teamId, userId));
807
+ }
808
+
752
809
  async getOnlineMembers(orgId: string): Promise<string[]> {
753
810
  const res = await this.request<{ user_ids: string[] }>(
754
811
  'GET',
@@ -2202,226 +2259,6 @@ export class ParallClient {
2202
2259
  return res.json() as Promise<PlatformConfigResponse>;
2203
2260
  }
2204
2261
 
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
2262
  // ---- Schedules (org-scoped) ----
2426
2263
 
2427
2264
  async createSchedule(orgId: string, input: CreateScheduleInput): Promise<Schedule> {
@@ -2685,13 +2522,29 @@ export class ParallClient {
2685
2522
 
2686
2523
  /**
2687
2524
  * 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.
2525
+ * account's address book — friends/chatrooms enriched with display names,
2526
+ * followed official accounts. Same live gate as the send verb.
2690
2527
  */
2691
2528
  async listWechatContacts(orgId: string): Promise<WechatContactsPage> {
2692
2529
  return this.request('GET', ENDPOINTS.WECHAT_CONTACTS(orgId));
2693
2530
  }
2694
2531
 
2532
+ /**
2533
+ * WeChat tier-B read verb (agent-only): the connected account's identity
2534
+ * (wxid / alias / nickName / app id).
2535
+ */
2536
+ async wechatProfile(orgId: string): Promise<WechatProfileView> {
2537
+ return this.request('GET', ENDPOINTS.WECHAT_PROFILE(orgId));
2538
+ }
2539
+
2540
+ /**
2541
+ * WeChat tier-B read verb (agent-only): live online probe + identity +
2542
+ * the platform's offline record.
2543
+ */
2544
+ async wechatStatus(orgId: string): Promise<WechatStatusView> {
2545
+ return this.request('GET', ENDPOINTS.WECHAT_STATUS(orgId));
2546
+ }
2547
+
2695
2548
  async listChannelConversations(
2696
2549
  orgId: string,
2697
2550
  connectionId: string,
@@ -3361,7 +3214,8 @@ export class ParallClient {
3361
3214
 
3362
3215
  // ---- Feature Flags (org-scoped, server-evaluated) ----
3363
3216
 
3364
- async getFeatureFlags(orgId: string): Promise<FeatureFlagsResponse> {
3217
+ /** Omit orgId to resolve deployment capabilities before joining an org. */
3218
+ async getFeatureFlags(orgId?: string): Promise<FeatureFlagsResponse> {
3365
3219
  return this.request('GET', ENDPOINTS.FEATURE_FLAGS(orgId));
3366
3220
  }
3367
3221
 
@@ -3392,10 +3246,67 @@ export class ParallClient {
3392
3246
  });
3393
3247
  }
3394
3248
 
3249
+ /** Queue a template deployment and poll its durable deployment row. Each
3250
+ * request is short-lived; closing the client does not cancel server work. */
3251
+ async deployTemplateAsync(
3252
+ orgId: string,
3253
+ request: DeployTemplateRequest,
3254
+ idempotencyKey: string,
3255
+ ): Promise<TemplateDeploymentReport> {
3256
+ const queue = () =>
3257
+ this.request<TemplateDeploymentResult>('POST', ENDPOINTS.TEMPLATE_DEPLOYMENTS(orgId), {
3258
+ ...request,
3259
+ async: true,
3260
+ idempotency_key: idempotencyKey,
3261
+ });
3262
+
3263
+ let result: TemplateDeploymentResult | undefined;
3264
+ for (let attempt = 0; attempt < 2 && result === undefined; attempt += 1) {
3265
+ try {
3266
+ result = await queue();
3267
+ } catch (error) {
3268
+ // A lost response or transient server failure is safe to retry because
3269
+ // the key resolves to the same deployment row rather than starting a
3270
+ // second team. A second transient failure remains outcome-unknown.
3271
+ if (!(error instanceof ApiError) || (error.status !== 0 && error.status < 500)) throw error;
3272
+ }
3273
+ }
3274
+ if (result === undefined) {
3275
+ throw new ApiError(0, 'Template deployment request outcome is unknown', 'NETWORK_ERROR');
3276
+ }
3277
+
3278
+ const deadline = Date.now() + 30 * 60 * 1000;
3279
+ while (result.status === 'queued' || result.status === 'deploying') {
3280
+ if (Date.now() >= deadline) {
3281
+ throw new ApiError(0, 'Template deployment is still running', 'REQUEST_TIMEOUT');
3282
+ }
3283
+ await new Promise((resolve) => setTimeout(resolve, 2000));
3284
+ try {
3285
+ result = await this.request<TemplateDeploymentResult>(
3286
+ 'GET',
3287
+ ENDPOINTS.TEMPLATE_DEPLOYMENT(orgId, result.deployment_id),
3288
+ );
3289
+ } catch (error) {
3290
+ if (!(error instanceof ApiError) || (error.status !== 0 && error.status < 500)) throw error;
3291
+ // A network failure or transient server error does not change the
3292
+ // durable deployment. Keep polling instead of presenting a definite
3293
+ // failure that could make a fresh-key retry create another team.
3294
+ }
3295
+ }
3296
+ if (result.status !== 'deployed') {
3297
+ throw new ApiError(
3298
+ 500,
3299
+ result.error?.message ?? 'Template deployment failed',
3300
+ result.error?.code,
3301
+ );
3302
+ }
3303
+ return result;
3304
+ }
3305
+
3395
3306
  async getTemplateDeployment(
3396
3307
  orgId: string,
3397
3308
  deploymentId: string,
3398
- ): Promise<TemplateDeploymentReport> {
3309
+ ): Promise<TemplateDeploymentResult> {
3399
3310
  return this.request('GET', ENDPOINTS.TEMPLATE_DEPLOYMENT(orgId, deploymentId));
3400
3311
  }
3401
3312
 
@@ -3718,6 +3629,15 @@ export class ParallClient {
3718
3629
  await this.request<void>('DELETE', ENDPOINTS.ORG_CLIP_UNINSTALL(orgId, clipId));
3719
3630
  }
3720
3631
 
3632
+ /** Best-effort provider revoke followed by atomic local removal of an
3633
+ * installed Official MCP Clip and all org-owned connection state. */
3634
+ async removeOfficialMCPClip(
3635
+ orgId: string,
3636
+ clipId: string,
3637
+ ): Promise<MCPOfficialClipRemovalResponse> {
3638
+ return this.request('DELETE', ENDPOINTS.ORG_CLIP_MCP_REMOVE(orgId, clipId));
3639
+ }
3640
+
3721
3641
  /** List the org's installed registry clips (full entries). */
3722
3642
  async listInstalledRegistryClips(orgId: string): Promise<ClipRegistryEntry[]> {
3723
3643
  const resp = await this.request<ClipRegistryEntry[] | null>(
@@ -3761,7 +3681,7 @@ export class ParallClient {
3761
3681
  /**
3762
3682
  * Read a clip's per-org agent exec access. Org-member readable (agents
3763
3683
  * included, so a denied agent can learn why exec answered
3764
- * `CLIP_AGENT_NOT_ALLOWED`).
3684
+ * `CLIP_AGENT_NOT_ALLOWED` / `CLIP_AGENT_CONNECTION_NOT_ALLOWED`).
3765
3685
  */
3766
3686
  async getClipAgentExecAccess(orgId: string, clipId: string): Promise<ClipAgentExecAccess> {
3767
3687
  return this.request('GET', ENDPOINTS.ORG_CLIP_EXEC_ACCESS(orgId, clipId));
@@ -3769,13 +3689,16 @@ export class ParallClient {
3769
3689
 
3770
3690
  /**
3771
3691
  * Replace a clip's per-org agent exec access. Human-only (agent principals
3772
- * get 403); under `all_agents` the `agent_ids` must be empty. Every granted
3773
- * id must be an active agent of this org (else `400 INVALID_INPUT`).
3692
+ * get 403); under `all_agents` both lists must be empty; pass either
3693
+ * `agent_ids` (legacy flat form every agent gets `connection_scope: 'all'`)
3694
+ * or `grants` (connection-scoped), never both. Every granted id must be an
3695
+ * active agent of this org, and every `connection_ids` entry a connection of
3696
+ * THIS clip in this org (else `400 INVALID_INPUT`).
3774
3697
  */
3775
3698
  async putClipAgentExecAccess(
3776
3699
  orgId: string,
3777
3700
  clipId: string,
3778
- access: ClipAgentExecAccess,
3701
+ access: ClipAgentExecAccessUpdate,
3779
3702
  ): Promise<ClipAgentExecAccess> {
3780
3703
  return this.request('PUT', ENDPOINTS.ORG_CLIP_EXEC_ACCESS(orgId, clipId), access);
3781
3704
  }
@@ -3903,6 +3826,73 @@ export class ParallClient {
3903
3826
  );
3904
3827
  }
3905
3828
 
3829
+ /**
3830
+ * Read a hosted Cloud Profile's one-shot cookie-seed status (manager-only:
3831
+ * hosted human maintainer or org admin). Sanitized — cookie VALUES never come
3832
+ * back, only `cookie_count` and the distinct target `domains`. `can_mutate` /
3833
+ * `lease_status` are the authoritative idle gate. Typed errors: `EDGE_NOT_HOSTED`
3834
+ * (BYOC device), `NOT_FOUND` (unknown profile).
3835
+ */
3836
+ async getEdgeProfileCookieSeed(
3837
+ orgId: string,
3838
+ edgeId: string,
3839
+ profileName: string,
3840
+ ): Promise<EdgeCookieSeedStatus> {
3841
+ return this.request('GET', ENDPOINTS.ORG_EDGE_PROFILE_COOKIES(orgId, edgeId, profileName));
3842
+ }
3843
+
3844
+ /**
3845
+ * Set/replace the profile's one-shot cookie seed (the full normalized cookie
3846
+ * array every time) — IDLE ONLY: while the profile's hosted browser is running
3847
+ * the server answers 409 `EDGE_PROFILE_IN_USE`; close the viewer, wait for idle
3848
+ * scale-to-zero, and retry. The next cold start injects the cookies into the
3849
+ * profile partition and consumes the seed. Other typed errors:
3850
+ * `EDGE_COOKIE_SEED_STALE` (409 — expectedVersion lost a tab race, sent as the
3851
+ * `cookieseed-<version>` If-Match), `EDGE_DELETING` (409), and
3852
+ * `SECRETBOX_UNCONFIGURED` (503 — server cannot store cookies safely).
3853
+ */
3854
+ async setEdgeProfileCookieSeed(
3855
+ orgId: string,
3856
+ edgeId: string,
3857
+ profileName: string,
3858
+ req: SetEdgeCookieSeedRequest,
3859
+ expectedVersion?: string,
3860
+ ): Promise<EdgeCookieSeedStatus> {
3861
+ return this.request(
3862
+ 'PUT',
3863
+ ENDPOINTS.ORG_EDGE_PROFILE_COOKIES(orgId, edgeId, profileName),
3864
+ req,
3865
+ undefined,
3866
+ false,
3867
+ {
3868
+ headers: expectedVersion ? { 'If-Match': `"cookieseed-${expectedVersion}"` } : undefined,
3869
+ },
3870
+ );
3871
+ }
3872
+
3873
+ /**
3874
+ * Clear the pending cookie seed (does NOT sign the profile out — cookies
3875
+ * already injected into the partition stay). Idle-only like set — 409
3876
+ * `EDGE_PROFILE_IN_USE` while the browser is live.
3877
+ */
3878
+ async clearEdgeProfileCookieSeed(
3879
+ orgId: string,
3880
+ edgeId: string,
3881
+ profileName: string,
3882
+ expectedVersion?: string,
3883
+ ): Promise<EdgeCookieSeedStatus> {
3884
+ return this.request(
3885
+ 'DELETE',
3886
+ ENDPOINTS.ORG_EDGE_PROFILE_COOKIES(orgId, edgeId, profileName),
3887
+ undefined,
3888
+ undefined,
3889
+ false,
3890
+ {
3891
+ headers: expectedVersion ? { 'If-Match': `"cookieseed-${expectedVersion}"` } : undefined,
3892
+ },
3893
+ );
3894
+ }
3895
+
3906
3896
  /**
3907
3897
  * Execute a registry clip command on an Edge device.
3908
3898
  *
@@ -3994,13 +3984,15 @@ export class ParallClient {
3994
3984
  return this.request('DELETE', ENDPOINTS.CLIP_CONNECTION(orgId, connId));
3995
3985
  }
3996
3986
 
3997
- // ---- MCP clip server config (cap:clip-mcp; publisher-org only) ----
3987
+ // ---- MCP clip server config (same-org or reviewed Official OAuth) ----
3998
3988
 
3999
3989
  /**
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.
3990
+ * Read the redacted MCP config. 404 NOT_FOUND when the clip has none yet
3991
+ * and also when a cross-org clip is not public + approved + installed, which
3992
+ * reads as nonexistent rather than refused (same existence-hiding as exec).
3993
+ * A cross-org clip that IS installed and approved reads fine regardless of
3994
+ * auth shape; what may then be configured is decided per credential owner.
3995
+ * `version` is the CAS token the mutations echo via If-Match.
4004
3996
  */
4005
3997
  async getClipMCPConfig(orgId: string, clipId: string): Promise<MCPConfigResponse> {
4006
3998
  return this.request('GET', ENDPOINTS.ORG_CLIP_MCP_CONFIG(orgId, clipId));
@@ -4059,8 +4051,11 @@ export class ParallClient {
4059
4051
  * List the org's MCP connections for a clip, default first — one row per
4060
4052
  * connection (credential slot), WITHOUT the tools snapshot (`tool_count`
4061
4053
  * 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
4054
+ * family-wide fence as the singular GET: same-org clips, or a cross-org clip
4055
+ * that is public + approved + installed; anything else reads as
4056
+ * `404 NOT_FOUND`. An installed cross-org clip with no connection yet lists
4057
+ * as an empty array — including one whose approved auth mode cannot be
4058
+ * configured at all (auth=none), which the write path is what refuses. With
4064
4059
  * `cap:clip-mcp` off the route is not registered at all.
4065
4060
  */
4066
4061
  async listClipMCPConnections(
@@ -4070,6 +4065,22 @@ export class ParallClient {
4070
4065
  return this.request('GET', ENDPOINTS.ORG_CLIP_MCP_CONFIGS(orgId, clipId));
4071
4066
  }
4072
4067
 
4068
+ /** Start a new Official OAuth MCP connection with the platform-owned app.
4069
+ * Omitting oauth_client is load-bearing: the server resolves the exact
4070
+ * reviewed-version binding and never falls back to DCR/CIMD cross-org. */
4071
+ async createClipMCPOAuthConnection(
4072
+ orgId: string,
4073
+ clipId: string,
4074
+ serverUrl: string,
4075
+ alias?: string,
4076
+ ): Promise<MCPOAuthInitiateResponse> {
4077
+ return this.request('POST', ENDPOINTS.ORG_CLIP_MCP_CONFIGS(orgId, clipId), {
4078
+ server_url: serverUrl,
4079
+ auth_type: 'oauth',
4080
+ ...(alias ? { alias } : {}),
4081
+ });
4082
+ }
4083
+
4073
4084
  /**
4074
4085
  * Re-run tools/list and replace the cached snapshot (org-admin only).
4075
4086
  * Deliberately does NOT advance the CAS version, so an in-flight edit in