@parall/parall 1.55.4 → 1.56.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.
@@ -51496,6 +51496,12 @@ function isForwardedMessageBody(body) {
51496
51496
  function sanitizeMeta(value) {
51497
51497
  return value.replace(/[\r\n]+/g, " ").replace(/[[\]|]/g, " ").trim();
51498
51498
  }
51499
+ function formatApprovalDecisionReason(status, reason) {
51500
+ const normalized = reason?.trim();
51501
+ if (status !== "rejected" || !normalized)
51502
+ return "";
51503
+ return `Reason (JSON): ${JSON.stringify(normalized)}`;
51504
+ }
51499
51505
  function buildEventBody(event) {
51500
51506
  const lines = [];
51501
51507
  if (event.type === "message") {
@@ -51513,6 +51519,8 @@ function buildEventBody(event) {
51513
51519
  ].filter(Boolean).join(" | ");
51514
51520
  lines.push(`[Thread: ${threadMeta}]`);
51515
51521
  }
51522
+ if (event.deliveryReason)
51523
+ lines.push(`[Delivery: ${sanitizeMeta(event.deliveryReason)}]`);
51516
51524
  if (event.unreadCount != null && event.unreadCount > 1) {
51517
51525
  const countStr = event.unreadCount >= 1e3 ? "999+" : String(event.unreadCount);
51518
51526
  const sinceStr = event.unreadSince ? ` | since: prll://${event.unreadSince}` : "";
@@ -51716,6 +51724,16 @@ function browserViewerRequestOptions(command, opts) {
51716
51724
  };
51717
51725
  }
51718
51726
 
51727
+ // ../sdk/dist/attachment-endpoints.js
51728
+ function attachmentEndpoints(apiBase) {
51729
+ return {
51730
+ UPLOAD_PRESIGN: (orgId) => `${apiBase}/orgs/${orgId}/upload/presign`,
51731
+ UPLOAD_COMPLETE: (orgId) => `${apiBase}/orgs/${orgId}/upload/complete`,
51732
+ UPLOAD_ABORT: (orgId) => `${apiBase}/orgs/${orgId}/upload/abort`,
51733
+ FILE: (id) => `${apiBase}/files/${id}`
51734
+ };
51735
+ }
51736
+
51719
51737
  // ../sdk/dist/constants.js
51720
51738
  var API_BASE = "/api/v1";
51721
51739
  var WIKI_BASE = "/wiki/v1";
@@ -51788,9 +51806,7 @@ var ENDPOINTS = {
51788
51806
  MESSAGE_REACTIONS: (id) => `${API_BASE}/messages/${id}/reactions`,
51789
51807
  MESSAGE_REACTION: (id, emoji) => `${API_BASE}/messages/${id}/reactions/${encodeURIComponent(emoji)}`,
51790
51808
  // Upload (org-scoped)
51791
- UPLOAD_PRESIGN: (orgId) => `${API_BASE}/orgs/${orgId}/upload/presign`,
51792
- UPLOAD_COMPLETE: (orgId) => `${API_BASE}/orgs/${orgId}/upload/complete`,
51793
- FILE: (id) => `${API_BASE}/files/${id}`,
51809
+ ...attachmentEndpoints(API_BASE),
51794
51810
  // Approval requests (org-scoped)
51795
51811
  APPROVAL_REQUESTS: (orgId) => `${API_BASE}/orgs/${orgId}/approval-requests`,
51796
51812
  // Approvals (global)
@@ -51876,6 +51892,7 @@ var ENDPOINTS = {
51876
51892
  TASKS: (orgId) => `${API_BASE}/orgs/${orgId}/tasks`,
51877
51893
  TASK_SUBTASK_SUMMARY: (orgId) => `${API_BASE}/orgs/${orgId}/tasks/subtask-summary`,
51878
51894
  TASK: (orgId, taskId) => `${API_BASE}/orgs/${orgId}/tasks/${taskId}`,
51895
+ TASK_MOVE: (orgId, taskId) => `${API_BASE}/orgs/${orgId}/tasks/${taskId}/move`,
51879
51896
  TASK_ARCHIVE: (orgId, taskId) => `${API_BASE}/orgs/${orgId}/tasks/${taskId}/archive`,
51880
51897
  TASK_RESTORE: (orgId, taskId) => `${API_BASE}/orgs/${orgId}/tasks/${taskId}/restore`,
51881
51898
  TASK_WATCH: (orgId, taskId) => `${API_BASE}/orgs/${orgId}/tasks/${taskId}/watch`,
@@ -51971,6 +51988,8 @@ var ENDPOINTS = {
51971
51988
  // backend router so `deleted` isn't captured as a {wikiId}; the SDK builder
51972
51989
  // is just a string.
51973
51990
  WIKIS_DELETED: (orgId) => `${WIKI_BASE}/orgs/${orgId}/wikis/deleted`,
51991
+ // Org-wide changeset listing across readable wikis (Working on tab).
51992
+ WIKI_ORG_CHANGESETS: (orgId) => `${WIKI_BASE}/orgs/${orgId}/wiki-changesets`,
51974
51993
  // Detail URL — also reused for DELETE (soft-delete) and `${WIKI}/restore`.
51975
51994
  WIKI: (orgId, wikiId) => `${WIKI_BASE}/orgs/${orgId}/wikis/${wikiId}`,
51976
51995
  WIKI_RESTORE: (orgId, wikiId) => `${WIKI_BASE}/orgs/${orgId}/wikis/${wikiId}/restore`,
@@ -52000,6 +52019,12 @@ var ENDPOINTS = {
52000
52019
  // Wiki Path Restrictions (AFCS narrowing ACL — private subtrees)
52001
52020
  WIKI_RESTRICTIONS: (orgId, wikiId) => `${WIKI_BASE}/orgs/${orgId}/wikis/${wikiId}/restrictions`,
52002
52021
  WIKI_RESTRICTION: (orgId, wikiId, restrictionId) => `${WIKI_BASE}/orgs/${orgId}/wikis/${wikiId}/restrictions/${restrictionId}`,
52022
+ WIKI_ACCESS_POLICY: (orgId, wikiId) => `${WIKI_BASE}/orgs/${orgId}/wikis/${wikiId}/access-policy`,
52023
+ WIKI_ACCESS_POLICY_MEMBERS: (orgId, wikiId) => `${WIKI_BASE}/orgs/${orgId}/wikis/${wikiId}/access-policy/members`,
52024
+ WIKI_MEMBERSHIP_SELF: (orgId, wikiId) => `${WIKI_BASE}/orgs/${orgId}/wikis/${wikiId}/membership/self`,
52025
+ // Library-level star (self-scoped bookmark; POST = star, DELETE = unstar).
52026
+ WIKI_STARS_SELF: (orgId, wikiId) => `${WIKI_BASE}/orgs/${orgId}/wikis/${wikiId}/stars/self`,
52027
+ WIKI_MEMBERS: (orgId, wikiId) => `${WIKI_BASE}/orgs/${orgId}/wikis/${wikiId}/members`,
52003
52028
  WIKI_ACCESS_STATUS: (orgId, wikiId) => `${WIKI_BASE}/orgs/${orgId}/wikis/${wikiId}/access-status`,
52004
52029
  WIKI_ACCESS_REQUESTS: (orgId, wikiId) => `${WIKI_BASE}/orgs/${orgId}/wikis/${wikiId}/access-requests`,
52005
52030
  // Wiki History (commits, file commits, blame)
@@ -52120,6 +52145,21 @@ var ENDPOINTS = {
52120
52145
  ORG_EDGE_DEVICE_UNREGISTER: (orgId, edgeId) => `/api/v1/orgs/${orgId}/edge/${edgeId}/unregister`,
52121
52146
  ORG_EDGE_ONBOARDING: (orgId) => `/api/v1/orgs/${orgId}/edge/onboarding`,
52122
52147
  ORG_EDGE_PROFILES: (orgId, edgeId) => `/api/v1/orgs/${orgId}/edge/${edgeId}/profiles`,
52148
+ ORG_EDGE_PROFILE_OPERATIONS: (orgId, edgeId) => `/api/v1/orgs/${orgId}/edge/${edgeId}/profile-operations`,
52149
+ ORG_EDGE_PROFILE_OPERATION: (orgId, edgeId, operationId) => `/api/v1/orgs/${orgId}/edge/${edgeId}/profile-operations/${operationId}`,
52150
+ ORG_EDGE_PROFILE_OPERATION_CONFIRM: (orgId, edgeId, operationId) => `/api/v1/orgs/${orgId}/edge/${edgeId}/profile-operations/${operationId}/confirm`,
52151
+ ORG_BROWSER_ALIASES: (orgId) => `/api/v1/orgs/${orgId}/browser-aliases`,
52152
+ ORG_BROWSER_ALIAS: (orgId, aliasId) => `/api/v1/orgs/${orgId}/browser-aliases/${aliasId}`,
52153
+ ORG_BROWSER_ALIAS_READINESS_CHECKS: (orgId, aliasId) => `/api/v1/orgs/${orgId}/browser-aliases/${aliasId}/readiness-checks`,
52154
+ ORG_BROWSER_ALIAS_READINESS_CHECK: (orgId, aliasId, checkId) => `/api/v1/orgs/${orgId}/browser-aliases/${aliasId}/readiness-checks/${checkId}`,
52155
+ ORG_API_KEY_BROWSER_ALIAS_GRANTS: (orgId, keyId) => `/api/v1/orgs/${orgId}/api-keys/${keyId}/browser-alias-grants`,
52156
+ ORG_API_KEY_BROWSER_ALIAS_GRANT: (orgId, keyId, aliasId) => `/api/v1/orgs/${orgId}/api-keys/${keyId}/browser-alias-grants/${aliasId}`,
52157
+ ORG_MANAGED_ALIASES: (orgId) => `/api/v1/orgs/${orgId}/aliases`,
52158
+ ORG_MANAGED_ALIAS: (orgId, aliasName) => `/api/v1/orgs/${orgId}/aliases/${encodeURIComponent(aliasName)}`,
52159
+ ORG_BROWSER_ALIAS_EXECUTIONS: (orgId) => `/api/v1/orgs/${orgId}/executions`,
52160
+ ORG_BROWSER_ALIAS_EXECUTION: (orgId, requestId) => `/api/v1/orgs/${orgId}/executions/${encodeURIComponent(requestId)}`,
52161
+ ORG_BROWSER_USE_OPERATIONS: (orgId) => `/api/v1/orgs/${orgId}/browser-use/operations`,
52162
+ ORG_BROWSER_USE_OPERATION: (orgId, operationId) => `/api/v1/orgs/${orgId}/browser-use/operations/${encodeURIComponent(operationId)}`,
52123
52163
  // Per-profile egress proxy (hosted Cloud Profiles; manager-only, human-only).
52124
52164
  ORG_EDGE_PROFILE_PROXY: (orgId, edgeId, profileName) => `/api/v1/orgs/${orgId}/edge/${edgeId}/profiles/${encodeURIComponent(profileName)}/proxy`,
52125
52165
  // Per-profile one-shot cookie seed (hosted Cloud Profiles; manager-only,
@@ -52134,6 +52174,8 @@ var ENDPOINTS = {
52134
52174
  CLIP_CONNECTION: (orgId, connId) => `/api/v1/orgs/${orgId}/clip-connections/${connId}`,
52135
52175
  // Clip registry (v3, org-scoped, served by api-server — `crg_` entries)
52136
52176
  ORG_CLIP_REGISTRY: (orgId) => `/api/v1/orgs/${orgId}/clip-registry`,
52177
+ ORG_CLIP_REGISTRY_RESOLVE: (orgId) => `/api/v1/orgs/${orgId}/clip-registry/resolve`,
52178
+ ORG_CLIP_REGISTRY_SEARCH: (orgId) => `/api/v1/orgs/${orgId}/clip-registry/search`,
52137
52179
  ORG_CLIP_REGISTRY_CLIP: (orgId, clipId) => `/api/v1/orgs/${orgId}/clip-registry/${clipId}`,
52138
52180
  ORG_CLIP_REGISTRY_PUBLISH: (orgId) => `/api/v1/orgs/${orgId}/clip-registry/publish`,
52139
52181
  ORG_CLIP_INSTALL: (orgId) => `/api/v1/orgs/${orgId}/clips/install`,
@@ -52267,6 +52309,15 @@ var ProjectTaskClient = class {
52267
52309
  async deleteTask(orgId, taskId, opts) {
52268
52310
  return this.request("DELETE", ENDPOINTS.TASK(orgId, taskId), void 0, opts?.force ? { force: "true" } : void 0);
52269
52311
  }
52312
+ /**
52313
+ * Moves a task and its whole subtree into another project (renumbering it
52314
+ * there; old identifiers stay resolvable as aliases). The caller needs
52315
+ * update access on the task (source project membership) and read access to
52316
+ * the target project.
52317
+ */
52318
+ async moveTask(orgId, taskId, data) {
52319
+ return this.request("POST", ENDPOINTS.TASK_MOVE(orgId, taskId), data);
52320
+ }
52270
52321
  async archiveTask(orgId, taskId) {
52271
52322
  return this.request("POST", ENDPOINTS.TASK_ARCHIVE(orgId, taskId));
52272
52323
  }
@@ -52470,8 +52521,44 @@ var WechatClient = class extends TaskLabelClient {
52470
52521
  }
52471
52522
  };
52472
52523
 
52524
+ // ../sdk/dist/attachment-client.js
52525
+ var COMPLETION_RETRY_DELAYS_MS = [250, 750];
52526
+ function isRetryableCompletionError(error) {
52527
+ if (!error || typeof error !== "object" || !("status" in error))
52528
+ return false;
52529
+ const status = error.status;
52530
+ return status === 0 || typeof status === "number" && status >= 500;
52531
+ }
52532
+ var AttachmentClient = class extends WechatClient {
52533
+ async getUploadPresignUrl(orgId, req) {
52534
+ return this.request("POST", ENDPOINTS.UPLOAD_PRESIGN(orgId), req);
52535
+ }
52536
+ async completeUpload(orgId, attachmentId, parts) {
52537
+ const body = {
52538
+ attachment_id: attachmentId,
52539
+ parts
52540
+ };
52541
+ for (let attempt = 0; ; attempt += 1) {
52542
+ try {
52543
+ return await this.request("POST", ENDPOINTS.UPLOAD_COMPLETE(orgId), body);
52544
+ } catch (error) {
52545
+ const delay = COMPLETION_RETRY_DELAYS_MS[attempt];
52546
+ if (delay === void 0 || !isRetryableCompletionError(error))
52547
+ throw error;
52548
+ await new Promise((resolve3) => setTimeout(resolve3, delay));
52549
+ }
52550
+ }
52551
+ }
52552
+ async abortUpload(orgId, attachmentId) {
52553
+ return this.request("POST", ENDPOINTS.UPLOAD_ABORT(orgId), { attachment_id: attachmentId });
52554
+ }
52555
+ async getFileUrl(id, opts) {
52556
+ return this.request("GET", ENDPOINTS.FILE(id), void 0, opts?.download ? { download: true } : void 0);
52557
+ }
52558
+ };
52559
+
52473
52560
  // ../sdk/dist/client.js
52474
- var ParallClient = class _ParallClient extends WechatClient {
52561
+ var ParallClient = class _ParallClient extends AttachmentClient {
52475
52562
  baseUrl;
52476
52563
  wikiBaseUrl;
52477
52564
  token;
@@ -53118,16 +53205,6 @@ var ParallClient = class _ParallClient extends WechatClient {
53118
53205
  const res = await this.request("GET", ENDPOINTS.MESSAGE_REACTIONS(messageId));
53119
53206
  return res.reactions;
53120
53207
  }
53121
- // ---- File Upload ----
53122
- async getUploadPresignUrl(orgId, req) {
53123
- return this.request("POST", ENDPOINTS.UPLOAD_PRESIGN(orgId), req);
53124
- }
53125
- async completeUpload(orgId, attachmentId) {
53126
- return this.request("POST", ENDPOINTS.UPLOAD_COMPLETE(orgId), { attachment_id: attachmentId });
53127
- }
53128
- async getFileUrl(id, opts) {
53129
- return this.request("GET", ENDPOINTS.FILE(id), void 0, opts?.download ? { download: true } : void 0);
53130
- }
53131
53208
  // ---- Approvals ----
53132
53209
  async getApproval(id) {
53133
53210
  return this.request("GET", ENDPOINTS.APPROVAL(id));
@@ -53135,8 +53212,14 @@ var ParallClient = class _ParallClient extends WechatClient {
53135
53212
  async requestApproval(orgId, req) {
53136
53213
  return this.request("POST", ENDPOINTS.APPROVAL_REQUESTS(orgId), req);
53137
53214
  }
53138
- async decideApproval(id, decision) {
53139
- return this.request("POST", ENDPOINTS.APPROVAL_DECIDE(id), { decision });
53215
+ async decideApproval(id, decision, reason) {
53216
+ if (decision === "approve" && reason?.trim()) {
53217
+ throw new ApiError(400, "Approval reason is only allowed for rejection decisions", "INVALID_DECISION_REASON");
53218
+ }
53219
+ return this.request("POST", ENDPOINTS.APPROVAL_DECIDE(id), {
53220
+ decision,
53221
+ ...decision === "reject" && reason !== void 0 ? { reason } : {}
53222
+ });
53140
53223
  }
53141
53224
  async cancelApproval(id) {
53142
53225
  return this.request("POST", ENDPOINTS.APPROVAL_CANCEL(id));
@@ -53969,6 +54052,17 @@ var ParallClient = class _ParallClient extends WechatClient {
53969
54052
  const res = await this.request("GET", ENDPOINTS.WIKI_CHANGESETS(orgId, wikiId));
53970
54053
  return res.data.map(normalizeWikiChangeset);
53971
54054
  }
54055
+ /** Org-wide changeset listing across every wiki the caller can read.
54056
+ * Server default (no `status`) is the pending set: proposed,
54057
+ * approval_pending, approved. */
54058
+ async getOrgWikiChangesets(orgId, opts) {
54059
+ const params = new URLSearchParams();
54060
+ for (const s of opts?.status ?? [])
54061
+ params.append("status", s);
54062
+ const qs = params.toString();
54063
+ const res = await this.request("GET", `${ENDPOINTS.WIKI_ORG_CHANGESETS(orgId)}${qs ? `?${qs}` : ""}`);
54064
+ return (res.data ?? []).map(normalizeWikiChangeset);
54065
+ }
53972
54066
  async getWikiChangeset(orgId, wikiId, changesetId) {
53973
54067
  return normalizeWikiChangeset(await this.request("GET", ENDPOINTS.WIKI_CHANGESET(orgId, wikiId, changesetId)));
53974
54068
  }
@@ -54057,6 +54151,46 @@ var ParallClient = class _ParallClient extends WechatClient {
54057
54151
  async getWikiAccessStatus(orgId, wikiId, path9) {
54058
54152
  return this.request("GET", ENDPOINTS.WIKI_ACCESS_STATUS(orgId, wikiId), void 0, path9 ? { path: path9 } : void 0);
54059
54153
  }
54154
+ // ---- Wiki membership projection (who-can-access, invites, join/leave) ----
54155
+ async getWikiAccessPolicy(orgId, wikiId, path9 = "") {
54156
+ return this.request("GET", ENDPOINTS.WIKI_ACCESS_POLICY(orgId, wikiId), void 0, path9 ? { path: path9 } : void 0);
54157
+ }
54158
+ async putWikiAccessPolicy(orgId, wikiId, policy) {
54159
+ return this.request("PUT", ENDPOINTS.WIKI_ACCESS_POLICY(orgId, wikiId), policy);
54160
+ }
54161
+ /** Add-only invite (viewer/editor); allowed for managers, and for editors
54162
+ * when the library enables editors_can_invite. */
54163
+ async addWikiMember(orgId, wikiId, subject, role) {
54164
+ await this.request("POST", ENDPOINTS.WIKI_ACCESS_POLICY_MEMBERS(orgId, wikiId), {
54165
+ subject,
54166
+ role
54167
+ });
54168
+ }
54169
+ /** Join a PUBLIC library as an explicit member (lands at the library's
54170
+ * default role). Restricted libraries answer 409 JOIN_REQUIRES_REQUEST —
54171
+ * go through createWikiAccessRequest instead. */
54172
+ async joinWiki(orgId, wikiId) {
54173
+ await this.request("POST", ENDPOINTS.WIKI_MEMBERSHIP_SELF(orgId, wikiId));
54174
+ }
54175
+ /** Remove the caller's explicit membership (team-granted membership stays). */
54176
+ async leaveWiki(orgId, wikiId) {
54177
+ await this.request("DELETE", ENDPOINTS.WIKI_MEMBERSHIP_SELF(orgId, wikiId));
54178
+ }
54179
+ /** Star a library for the caller (sidebar Starred group). Idempotent —
54180
+ * re-starring is a 204 no-op. Requires read access; hidden private
54181
+ * libraries answer 404 like absent IDs. */
54182
+ async starWiki(orgId, wikiId) {
54183
+ await this.request("POST", ENDPOINTS.WIKI_STARS_SELF(orgId, wikiId));
54184
+ }
54185
+ /** Remove the caller's star. Idempotent — unstarring a never-starred
54186
+ * library is a 204 no-op. */
54187
+ async unstarWiki(orgId, wikiId) {
54188
+ await this.request("DELETE", ENDPOINTS.WIKI_STARS_SELF(orgId, wikiId));
54189
+ }
54190
+ async getWikiMembers(orgId, wikiId) {
54191
+ const res = await this.request("GET", ENDPOINTS.WIKI_MEMBERS(orgId, wikiId));
54192
+ return res.data ?? [];
54193
+ }
54060
54194
  async createWikiAccessRequest(orgId, wikiId, data) {
54061
54195
  await this.request("POST", ENDPOINTS.WIKI_ACCESS_REQUESTS(orgId, wikiId), data);
54062
54196
  }
@@ -54406,6 +54540,31 @@ var ParallClient = class _ParallClient extends WechatClient {
54406
54540
  const resp = await this.request("GET", `${ENDPOINTS.ORG_CLIP_REGISTRY(orgId)}?limit=100`);
54407
54541
  return resp ?? [];
54408
54542
  }
54543
+ /**
54544
+ * Resolve an exact `<publisher org, name>` reference to its registry entry —
54545
+ * the npm-style point read. Deliberately independent of catalog size: no
54546
+ * Search, no pagination, same read-visibility boundary as `getRegistryClip`
54547
+ * (cross-org requires public + approved). 404 `NOT_FOUND` when the publisher
54548
+ * org has no visible clip of that exact name.
54549
+ */
54550
+ async resolveRegistryClip(orgId, publisherOrgId, name) {
54551
+ const params = new URLSearchParams({ org_id: publisherOrgId, name });
54552
+ return this.request("GET", `${ENDPOINTS.ORG_CLIP_REGISTRY_RESOLVE(orgId)}?${params}`);
54553
+ }
54554
+ /**
54555
+ * Server-side fuzzy discovery over the visible registry (name/description
54556
+ * substring match), paginated. The discovery verb: rows carry the `crg_` id
54557
+ * that {@link installRegistryClip} takes.
54558
+ */
54559
+ async searchOrgRegistryClips(orgId, query, opts) {
54560
+ const params = new URLSearchParams({ q: query });
54561
+ if (opts?.limit !== void 0)
54562
+ params.set("limit", String(opts.limit));
54563
+ if (opts?.offset !== void 0)
54564
+ params.set("offset", String(opts.offset));
54565
+ const resp = await this.request("GET", `${ENDPOINTS.ORG_CLIP_REGISTRY_SEARCH(orgId)}?${params}`);
54566
+ return resp ?? [];
54567
+ }
54409
54568
  /**
54410
54569
  * Install a registry clip into the org (a reference in `clip_installs`, not a
54411
54570
  * copy). Idempotent: installing an already-installed clip returns the same
@@ -54519,6 +54678,86 @@ var ParallClient = class _ParallClient extends WechatClient {
54519
54678
  async listEdgeProfiles(orgId, edgeId) {
54520
54679
  return this.request("GET", ENDPOINTS.ORG_EDGE_PROFILES(orgId, edgeId));
54521
54680
  }
54681
+ /** Start one durable Local BYOC Profile operation. Network-unknown callers
54682
+ * must retry with the same key or recover by operation id; a different body
54683
+ * under the same key is rejected. */
54684
+ async createEdgeProfileOperation(orgId, edgeId, request3, idempotencyKey) {
54685
+ return this.request("POST", ENDPOINTS.ORG_EDGE_PROFILE_OPERATIONS(orgId, edgeId), request3, void 0, false, { headers: { "Idempotency-Key": idempotencyKey } });
54686
+ }
54687
+ /** Strong-confirm the exact durable Delete impact. A changed impact returns
54688
+ * PROFILE_DELETE_IMPACT_CHANGED with a replacement receipt in
54689
+ * `ApiError.extras.details.operation`. */
54690
+ async confirmEdgeProfileOperation(orgId, edgeId, operationId, request3) {
54691
+ return this.request("POST", ENDPOINTS.ORG_EDGE_PROFILE_OPERATION_CONFIRM(orgId, edgeId, operationId), request3);
54692
+ }
54693
+ /** Sole read/recovery surface. The server may reconcile an already durable
54694
+ * dispatch/finalization while returning this receipt. */
54695
+ async getEdgeProfileOperation(orgId, edgeId, operationId) {
54696
+ return this.request("GET", ENDPOINTS.ORG_EDGE_PROFILE_OPERATION(orgId, edgeId, operationId));
54697
+ }
54698
+ /** Create and atomically materialize one Local BYOC Browser Alias. A replay
54699
+ * with the same idempotency key and body returns the original stable ccn_. */
54700
+ async createBrowserAlias(orgId, request3) {
54701
+ return this.request("POST", ENDPOINTS.ORG_BROWSER_ALIASES(orgId), request3);
54702
+ }
54703
+ async listBrowserAliases(orgId) {
54704
+ return this.request("GET", ENDPOINTS.ORG_BROWSER_ALIASES(orgId));
54705
+ }
54706
+ async getBrowserAlias(orgId, aliasId) {
54707
+ return this.request("GET", ENDPOINTS.ORG_BROWSER_ALIAS(orgId, aliasId));
54708
+ }
54709
+ async renameBrowserAlias(orgId, aliasId, request3) {
54710
+ return this.request("PATCH", ENDPOINTS.ORG_BROWSER_ALIAS(orgId, aliasId), request3);
54711
+ }
54712
+ async deleteBrowserAlias(orgId, aliasId, request3) {
54713
+ return this.request("DELETE", ENDPOINTS.ORG_BROWSER_ALIAS(orgId, aliasId), request3);
54714
+ }
54715
+ /** Start one durable readiness check. The key is carried as the standard
54716
+ * Idempotency-Key header; the request body is intentionally empty. */
54717
+ async createBrowserAliasReadinessCheck(orgId, aliasId, request3) {
54718
+ return this.request("POST", ENDPOINTS.ORG_BROWSER_ALIAS_READINESS_CHECKS(orgId, aliasId), void 0, void 0, false, { headers: { "Idempotency-Key": request3.idempotency_key } });
54719
+ }
54720
+ /** Sole durable recovery surface for one readiness request. */
54721
+ async getBrowserAliasReadinessCheck(orgId, aliasId, checkId) {
54722
+ return this.request("GET", ENDPOINTS.ORG_BROWSER_ALIAS_READINESS_CHECK(orgId, aliasId, checkId));
54723
+ }
54724
+ /** Organization Owner view. Hashes, reviewed snapshots and deltas are
54725
+ * intentionally available only on this human-JWT management surface. */
54726
+ async listBrowserAliasGrants(orgId, keyId) {
54727
+ return this.request("GET", ENDPOINTS.ORG_API_KEY_BROWSER_ALIAS_GRANTS(orgId, keyId));
54728
+ }
54729
+ async getBrowserAliasGrant(orgId, keyId, aliasId) {
54730
+ return this.request("GET", ENDPOINTS.ORG_API_KEY_BROWSER_ALIAS_GRANT(orgId, keyId, aliasId));
54731
+ }
54732
+ async replaceBrowserAliasGrant(orgId, keyId, aliasId, request3) {
54733
+ return this.request("PUT", ENDPOINTS.ORG_API_KEY_BROWSER_ALIAS_GRANT(orgId, keyId, aliasId), request3);
54734
+ }
54735
+ /** Managed-key discovery. The response is already grant-filtered and never
54736
+ * carries contract hashes, review snapshots, Edge IDs or Profile IDs. */
54737
+ async listManagedBrowserAliases(orgId) {
54738
+ return this.request("GET", ENDPOINTS.ORG_MANAGED_ALIASES(orgId));
54739
+ }
54740
+ async getManagedBrowserAlias(orgId, aliasName) {
54741
+ return this.request("GET", ENDPOINTS.ORG_MANAGED_ALIAS(orgId, aliasName));
54742
+ }
54743
+ /** Accept and dispatch one @alias command. request_id is generated by the
54744
+ * caller before local validation and is also the sole durable recovery key. */
54745
+ async createBrowserAliasExecution(orgId, request3) {
54746
+ return this.request("POST", ENDPOINTS.ORG_BROWSER_ALIAS_EXECUTIONS(orgId), request3);
54747
+ }
54748
+ async getBrowserAliasExecution(orgId, requestId) {
54749
+ return this.request("GET", ENDPOINTS.ORG_BROWSER_ALIAS_EXECUTION(orgId, requestId));
54750
+ }
54751
+ /** Accept one idempotent Browser Use operation for an explicit Profile.
54752
+ * The Server resolves Profile→Edge; callers never select an Edge directly. */
54753
+ async createBrowserUseOperation(orgId, request3) {
54754
+ return this.request("POST", ENDPOINTS.ORG_BROWSER_USE_OPERATIONS(orgId), request3);
54755
+ }
54756
+ /** Recover the durable receipt. Successful data is present only inside the
54757
+ * Server's short encrypted result TTL; terminal proof remains afterwards. */
54758
+ async getBrowserUseOperation(orgId, operationId) {
54759
+ return this.request("GET", ENDPOINTS.ORG_BROWSER_USE_OPERATION(orgId, operationId));
54760
+ }
54522
54761
  /**
54523
54762
  * Read a hosted Cloud Profile's egress-proxy status (manager-only: hosted
54524
54763
  * human maintainer or org admin). Sanitized — the password never comes back.
@@ -58783,11 +59022,28 @@ var ParallAgentGateway = class {
58783
59022
  const hasAttachments = message.attachments?.length;
58784
59023
  if (!body && !hasAttachments)
58785
59024
  return { action: "skip" };
58786
- if (chatInfo.type === "group" && chatInfo.agentRoutingMode !== "active") {
58787
- const mentions = content.mentions ?? [];
58788
- const isMentioned = mentions.some((mention) => mentionTargetsUser(mention.user_id, this.opts.agentUserId, "agent"));
58789
- if (!isMentioned)
59025
+ const mentions = content.mentions ?? [];
59026
+ const isMentioned = mentions.some((mention) => mentionTargetsUser(mention.user_id, this.opts.agentUserId, "agent"));
59027
+ let deliveryReason;
59028
+ if (message.thread_root_id) {
59029
+ if (isMentioned) {
59030
+ deliveryReason = "mention";
59031
+ } else {
59032
+ let watching;
59033
+ try {
59034
+ watching = await this.opts.client.isWatchingThread(message.thread_root_id);
59035
+ } catch {
59036
+ return { action: "retry" };
59037
+ }
59038
+ if (!watching)
59039
+ return { action: "skip" };
59040
+ deliveryReason = "watcher";
59041
+ }
59042
+ } else if (chatInfo.type === "group") {
59043
+ if (chatInfo.agentRoutingMode !== "active" && !isMentioned)
58790
59044
  return { action: "skip" };
59045
+ if (isMentioned)
59046
+ deliveryReason = "mention";
58791
59047
  }
58792
59048
  const attachments = (message.attachments ?? []).map((a) => ({
58793
59049
  id: a.id,
@@ -58828,6 +59084,7 @@ var ParallAgentGateway = class {
58828
59084
  messageId: message.id,
58829
59085
  body: body || "[attachment]",
58830
59086
  threadRootId: message.thread_root_id ?? void 0,
59087
+ deliveryReason,
58831
59088
  noReply: message.hints?.no_reply ?? false,
58832
59089
  attachments: attachments.length > 0 ? attachments : void 0,
58833
59090
  sentAt: message.created_at,
@@ -59305,7 +59562,10 @@ var ParallAgentGateway = class {
59305
59562
  this.opts.log?.info(`approval decided: ${approval.id} (${approval.status})`);
59306
59563
  const statusLabel = approval.status === "approved" ? "Approved" : "Rejected";
59307
59564
  const execInfo = approval.execution_status ? ` | execution: ${approval.execution_status}` : "";
59308
- const body = `${statusLabel}: ${approval.title}${execInfo}`;
59565
+ const reasonLine = formatApprovalDecisionReason(approval.status, approval.decision_reason);
59566
+ const reasonInfo = reasonLine ? `
59567
+ ${reasonLine}` : "";
59568
+ const body = `${statusLabel}: ${approval.title}${execInfo}${reasonInfo}`;
59309
59569
  const event = {
59310
59570
  type: "approval",
59311
59571
  targetId: chatId ?? approval.chat_id,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@parall/parall",
3
- "version": "1.55.4",
3
+ "version": "1.56.0",
4
4
  "description": "OpenClaw channel plugin for Parall IM",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -16,8 +16,8 @@
16
16
  "openclaw.plugin.json"
17
17
  ],
18
18
  "dependencies": {
19
- "@parall/agent-core": "1.55.4",
20
- "@parall/sdk": "1.55.4"
19
+ "@parall/agent-core": "1.56.0",
20
+ "@parall/sdk": "1.56.0"
21
21
  },
22
22
  "devDependencies": {
23
23
  "@types/node": "^22.0.0",
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: parall-platform
3
- description: "Parall platform queries and lightweight agent provisioning: list org members, agents, chats, read message history, check identity, create another agent, or walk the prll:// reference graph (resolve URIs, backlinks, multi-hop graph). Use when: user asks about org members, who's online, chat history, agent list, creating an agent, identity/auth questions, or you need to find what an entity is connected to / who references it."
3
+ description: "Parall platform queries and lightweight agent provisioning: list org members, agents, chats, read message history, watch/unwatch threads, check identity, create another agent, or walk the prll:// reference graph (resolve URIs, backlinks, multi-hop graph). Use when: user asks about org members, who's online, chat history, agent list, creating an agent, identity/auth questions, you want to follow or mute a thread (e.g. after `[Delivery: watcher]` wake-ups), or you need to find what an entity is connected to / who references it."
4
4
  ---
5
5
 
6
6
  # Parall Platform
@@ -140,7 +140,7 @@ parall dm prll://usr_xxx --text-file /tmp/reply.md
140
140
  parall dm "Alice" --text "Hello"
141
141
 
142
142
  # Thread reply
143
- parall messages send prll://cht_xxx --text-file /tmp/reply.md --thread-root-id 01JWC...
143
+ parall messages send prll://cht_xxx --text-file /tmp/reply.md --thread-root-id prll://msg_xxx
144
144
 
145
145
  # FYI message (no response expected — the recipient sees `[Hint: no_reply]`)
146
146
  parall messages send prll://cht_xxx --text "FYI: done" --no-reply
@@ -151,6 +151,27 @@ parall messages send prll://cht_xxx --text "FYI: done" --no-reply
151
151
  parall no-reply --reason "ack only, nothing to add"
152
152
  ```
153
153
 
154
+ ## Thread Subscriptions
155
+
156
+ Replying in a thread subscribes you to it: every later reply reaches you as
157
+ `[Event: message.new]` with a `[Thread: ...]` line, marked
158
+ `[Delivery: watcher]`. You are also auto-subscribed when a thread reply
159
+ @-mentions you personally, and when someone replies to a thread whose root
160
+ message you wrote. `[Delivery: mention]` means you were @-mentioned in that
161
+ message.
162
+
163
+ ```bash
164
+ parall messages watch prll://msg_xxx # follow a thread without replying (ID = the thread's root message)
165
+ parall messages unwatch prll://msg_xxx # stop receiving a thread's replies
166
+ parall messages watchers prll://msg_xxx # list who is watching a thread
167
+ ```
168
+
169
+ Unwatch is sticky: no automatic source (including later @-mentions — you
170
+ still get the one-off mention, just no subscription) re-subscribes you.
171
+ Only replying in the thread yourself or an explicit `watch` does. Unwatch
172
+ threads you have nothing more to contribute to instead of ignoring their
173
+ wake-ups.
174
+
154
175
  ## Files & Attachments
155
176
 
156
177
  Attachments appear in events as `[Attachment: prll://att_xxx | mime | size | name]`.