@parall/daemon 1.32.0 → 1.33.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.
Files changed (51) hide show
  1. package/bundle/bb-browser-daemon.js +15628 -0
  2. package/bundle/buildDomTree.js +1501 -0
  3. package/bundle/manifest.json +19 -11
  4. package/bundle/parall-claude-agent.js +224 -58
  5. package/bundle/parall-codex-agent.js +224 -58
  6. package/bundle/parall-daemon.js +4507 -2668
  7. package/bundle/parall-openclaw-agent.js +4 -3
  8. package/dist/cli.d.ts.map +1 -1
  9. package/dist/cli.js +8 -2
  10. package/dist/clip-runtime/browser-dependency.d.ts +20 -0
  11. package/dist/clip-runtime/browser-dependency.d.ts.map +1 -0
  12. package/dist/clip-runtime/browser-dependency.js +52 -0
  13. package/dist/clip-runtime/browser-profile-manager.d.ts +67 -0
  14. package/dist/clip-runtime/browser-profile-manager.d.ts.map +1 -0
  15. package/dist/clip-runtime/browser-profile-manager.js +595 -0
  16. package/dist/clip-runtime/bun-resolver.d.ts +24 -0
  17. package/dist/clip-runtime/bun-resolver.d.ts.map +1 -0
  18. package/dist/clip-runtime/bun-resolver.js +58 -0
  19. package/dist/clip-runtime/clip-installer.d.ts.map +1 -1
  20. package/dist/clip-runtime/clip-installer.js +59 -18
  21. package/dist/clip-runtime/clip-provider.d.ts +13 -2
  22. package/dist/clip-runtime/clip-provider.d.ts.map +1 -1
  23. package/dist/clip-runtime/clip-provider.js +106 -36
  24. package/dist/clip-runtime/hub-client.d.ts +79 -0
  25. package/dist/clip-runtime/hub-client.d.ts.map +1 -0
  26. package/dist/clip-runtime/hub-client.js +320 -0
  27. package/dist/clip-runtime/index.d.ts +2 -0
  28. package/dist/clip-runtime/index.d.ts.map +1 -1
  29. package/dist/clip-runtime/index.js +2 -0
  30. package/dist/clip-runtime/ipc.d.ts +6 -0
  31. package/dist/clip-runtime/ipc.d.ts.map +1 -1
  32. package/dist/clip-runtime/manifest.d.ts +16 -8
  33. package/dist/clip-runtime/manifest.d.ts.map +1 -1
  34. package/dist/clip-runtime/manifest.js +13 -0
  35. package/dist/clip-runtime/process-manager.d.ts +55 -3
  36. package/dist/clip-runtime/process-manager.d.ts.map +1 -1
  37. package/dist/clip-runtime/process-manager.js +233 -76
  38. package/dist/clip-runtime/process.d.ts +15 -1
  39. package/dist/clip-runtime/process.d.ts.map +1 -1
  40. package/dist/clip-runtime/process.js +73 -10
  41. package/dist/config.d.ts +9 -0
  42. package/dist/config.d.ts.map +1 -1
  43. package/dist/config.js +12 -0
  44. package/dist/index.js +46 -5
  45. package/dist/runtime-bin-resolver.d.ts +7 -0
  46. package/dist/runtime-bin-resolver.d.ts.map +1 -0
  47. package/dist/runtime-bin-resolver.js +292 -0
  48. package/dist/supervisor.d.ts +53 -4
  49. package/dist/supervisor.d.ts.map +1 -1
  50. package/dist/supervisor.js +449 -117
  51. package/package.json +7 -6
@@ -26776,10 +26776,15 @@ Other agents share this workspace. Before starting work, check whether someone
26776
26776
  ### Permissions and approvals
26777
26777
  You have real permissions based on your roles (chat member/admin, org member).
26778
26778
  If you lack permission for an action, the API returns PERMISSION_DENIED with the
26779
- \`action\` and \`resource_uri\` that were denied. When that happens, use
26780
- \`approvals request\` to ask someone with permission to approve it \u2014 don't retry
26781
- or work around the denial. Only request approval after an actual denial, never
26782
- preemptively.
26779
+ \`action\` and \`resource_uri\` that were denied. The server decides whether that
26780
+ action is approvable: if it is, the CLI prints an \`approvals request\` command \u2014
26781
+ fill in the placeholders it shows (\`--chat\`, \`--title\`, \`--reason\`) and run
26782
+ it to ask someone with permission. If it is NOT approvable, the output says so;
26783
+ ask a human with permission instead of requesting approval. A
26784
+ \`INVALID_TARGET\` error instead means you addressed the wrong kind of thing
26785
+ (e.g. a \`usr_\` id where a chat is expected) \u2014 follow the message (e.g. use
26786
+ \`dm\` for a user). Don't retry or work around a denial; only request approval
26787
+ after an actual denial, never preemptively.
26783
26788
 
26784
26789
  ### When in doubt
26785
26790
  Prefer asking over guessing. Prefer "I don't know" over fabricating. Your
@@ -26952,7 +26957,7 @@ See \`docs/engineering-design/agent-dm-loop-prevention.md\` \xA7 Layer 0 for why
26952
26957
 
26953
26958
  When you try an action (e.g., archive a chat) and receive a PERMISSION_DENIED error, you can request someone with permission to do it:
26954
26959
 
26955
- 1. The error includes a \`PERMISSION_DENIED\` code. For commonly approvable actions (archive, delete, restore), a \`Tip:\` line with an approval-request template is printed \u2014 copy it and fill in the remaining placeholders (\`--chat\`, \`--title\`, \`--reason\`)
26960
+ 1. The error includes a \`PERMISSION_DENIED\` code plus the denied \`action\` and \`resource_uri\`. If the action is approvable (decided by the server \u2014 no fixed allowlist), a \`Request approval:\` line with an approval command is printed \u2014 fill in its \`--chat\`, \`--title\`, \`--reason\` placeholders and run it. If it is not approvable, the output says so; ask a human with permission instead.
26956
26961
  2. Request approval: \`parall approvals request --action chat.archive --resource prll://cht_123 --chat prll://cht_456 --title "Archive #old-project" --reason "Channel inactive"\`
26957
26962
  3. A card will appear in the specified chat for someone with permission to approve
26958
26963
  4. Check the result: \`parall approvals get prll://<id>\` or wait: \`parall approvals wait prll://<id> --timeout 300\`
@@ -27158,6 +27163,7 @@ var ENDPOINTS = {
27158
27163
  MACHINE_AGENT_DAEMON_CONFIG: (orgId, machineId, agentId) => `${API_BASE}/orgs/${orgId}/machines/${machineId}/agents/${agentId}/daemon-config`,
27159
27164
  MACHINE_AGENT_WORKSPACE_SETUP: (orgId, machineId, agentId) => `${API_BASE}/orgs/${orgId}/machines/${machineId}/agents/${agentId}/workspace/setup`,
27160
27165
  MACHINE_LLM_SOURCE: (orgId, machineId) => `${API_BASE}/orgs/${orgId}/machines/${machineId}/llm-source`,
27166
+ MACHINE_PROVIDER_ENABLED: (orgId, machineId) => `${API_BASE}/orgs/${orgId}/machines/${machineId}/provider-enabled`,
27161
27167
  MACHINE_RUNTIME_AUTH: (orgId, machineId) => `${API_BASE}/orgs/${orgId}/machines/${machineId}/runtime-auth`,
27162
27168
  MACHINE_KEYS: (orgId, machineId) => `${API_BASE}/orgs/${orgId}/machines/${machineId}/keys`,
27163
27169
  MACHINE_KEY: (orgId, machineId, keyId) => `${API_BASE}/orgs/${orgId}/machines/${machineId}/keys/${keyId}`,
@@ -27171,8 +27177,9 @@ var ENDPOINTS = {
27171
27177
  MACHINES_ME: `${API_BASE}/machines/me`,
27172
27178
  MACHINES_ME_AGENTS: `${API_BASE}/machines/me/agents`,
27173
27179
  MACHINES_ME_HEALTH: `${API_BASE}/machines/me/health`,
27174
- MACHINES_ME_CLIP_INSTALLS: `${API_BASE}/machines/me/clip-installs`,
27175
- MACHINES_ME_CLIP_INSTALL_DONE: (clipId) => `${API_BASE}/machines/me/clip-installs/${clipId}/installed`,
27180
+ MACHINES_ME_CLIPS: `${API_BASE}/machines/me/clips`,
27181
+ MACHINES_ME_BROWSER_PROFILES: `${API_BASE}/machines/me/browser-profiles`,
27182
+ MACHINES_ME_BROWSER_PROFILE_STATUS: (profileId) => `${API_BASE}/machines/me/browser-profiles/${profileId}/status`,
27176
27183
  MACHINES_ME_AGENT_LAUNCH_CREDENTIAL: (agentId) => `${API_BASE}/machines/me/agents/${agentId}/launch-credential`,
27177
27184
  MACHINES_ME_AGENT_WORKSPACE_STATE: (agentId) => `${API_BASE}/machines/me/agents/${agentId}/workspace-state`,
27178
27185
  MACHINES_ME_WS_TICKET: `${API_BASE}/machines/me/ws/ticket`,
@@ -27271,6 +27278,7 @@ var ENDPOINTS = {
27271
27278
  DISPATCH_RECEIVED: (orgId) => `${API_BASE}/orgs/${orgId}/dispatch/received`,
27272
27279
  DISPATCH_ACK: (orgId) => `${API_BASE}/orgs/${orgId}/dispatch/ack`,
27273
27280
  DISPATCH_ACK_BY_ID: (orgId, id) => `${API_BASE}/orgs/${orgId}/dispatch/${id}/ack`,
27281
+ DISPATCH_EXPIRE: (orgId) => `${API_BASE}/orgs/${orgId}/dispatch/expire`,
27274
27282
  DISPATCH_BY_MESSAGES: (orgId) => `${API_BASE}/orgs/${orgId}/dispatch/by-messages`,
27275
27283
  // Unread
27276
27284
  UNREAD: `${API_BASE}/me/unread`,
@@ -27309,6 +27317,13 @@ var ENDPOINTS = {
27309
27317
  AGENT_CLIP: (orgId, agentId, clipId) => `${CLIP_BASE}/orgs/${orgId}/agents/${agentId}/clips/${clipId}`,
27310
27318
  CLIP_INVOKE: (orgId) => `${CLIP_BASE}/orgs/${orgId}/invoke`,
27311
27319
  CLIP_ONLINE: (orgId) => `${CLIP_BASE}/orgs/${orgId}/online`,
27320
+ BROWSER_PROFILES: (orgId) => `${CLIP_BASE}/orgs/${orgId}/browser-profiles`,
27321
+ BROWSER_PROFILE: (orgId, profileId) => `${CLIP_BASE}/orgs/${orgId}/browser-profiles/${profileId}`,
27322
+ BROWSER_PROFILE_OPEN: (orgId, profileId) => `${CLIP_BASE}/orgs/${orgId}/browser-profiles/${profileId}/open`,
27323
+ BROWSER_PROFILE_STOP: (orgId, profileId) => `${CLIP_BASE}/orgs/${orgId}/browser-profiles/${profileId}/stop`,
27324
+ BROWSER_PROFILE_RESET: (orgId, profileId) => `${CLIP_BASE}/orgs/${orgId}/browser-profiles/${profileId}/reset`,
27325
+ BROWSER_PROFILE_CONSENTS: (orgId, profileId) => `${CLIP_BASE}/orgs/${orgId}/browser-profiles/${profileId}/consents`,
27326
+ BROWSER_PROFILE_CONSENT: (orgId, profileId, clipId) => `${CLIP_BASE}/orgs/${orgId}/browser-profiles/${profileId}/consents/${clipId}`,
27312
27327
  // Clip registry (global, served by clip-service → Pinix Hub proxy)
27313
27328
  CLIP_REGISTRY: () => `${CLIP_BASE}/registry/clips`
27314
27329
  };
@@ -27383,9 +27398,10 @@ var WS_EVENTS = {
27383
27398
  MACHINE_FILESYSTEM_BROWSE: "machine.filesystem.browse",
27384
27399
  MACHINE_UPDATE: "machine.update",
27385
27400
  MACHINE_CONFIG_UPDATED: "machine.config.updated",
27386
- MACHINE_CLIP_INSTALL: "machine.clip.install",
27401
+ MACHINE_CLIP_SYNC: "machine.clip.sync",
27402
+ MACHINE_BROWSER_PROFILE_LIFECYCLE: "machine.browser_profile.lifecycle",
27387
27403
  AGENT_NEW_SESSION: "agent.new_session",
27388
- CLIP_INSTALLED: "clip.installed",
27404
+ CLIP_CREATED: "clip.created",
27389
27405
  CLIP_REMOVED: "clip.removed",
27390
27406
  CLIP_UPDATED: "clip.updated"
27391
27407
  };
@@ -27548,15 +27564,7 @@ var ParallClient = class _ParallClient {
27548
27564
  }
27549
27565
  if (!res.ok) {
27550
27566
  const rawErrorBody = await res.json().catch(() => ({}));
27551
- const errorBody = rawErrorBody !== null && typeof rawErrorBody === "object" ? rawErrorBody : {};
27552
- const errorObj = errorBody?.error && typeof errorBody.error === "object" ? errorBody.error : void 0;
27553
- const errMsg = errorObj?.message ?? (typeof errorBody?.error === "string" ? errorBody.error : void 0);
27554
- const errCode = errorObj?.code ?? (typeof errorBody?.code === "string" ? errorBody.code : void 0);
27555
- const apiError = new ApiError(res.status, errMsg ?? res.statusText, errCode);
27556
- const { error: _e, code: _c, message: _m, ...extras } = errorBody;
27557
- if (Object.keys(extras).length > 0)
27558
- apiError.extras = extras;
27559
- throw apiError;
27567
+ throw buildApiError(res, rawErrorBody);
27560
27568
  }
27561
27569
  if (res.status === 204)
27562
27570
  return void 0;
@@ -27608,15 +27616,7 @@ var ParallClient = class _ParallClient {
27608
27616
  }
27609
27617
  if (!res.ok) {
27610
27618
  const rawErrorBody = await res.json().catch(() => ({}));
27611
- const errorBody = rawErrorBody !== null && typeof rawErrorBody === "object" ? rawErrorBody : {};
27612
- const errorObj = errorBody?.error && typeof errorBody.error === "object" ? errorBody.error : void 0;
27613
- const errMsg = errorObj?.message ?? (typeof errorBody?.error === "string" ? errorBody.error : void 0);
27614
- const errCode = errorObj?.code ?? (typeof errorBody?.code === "string" ? errorBody.code : void 0);
27615
- const apiError = new ApiError(res.status, errMsg ?? res.statusText, errCode);
27616
- const { error: _e, code: _c, message: _m, ...extras } = errorBody;
27617
- if (Object.keys(extras).length > 0)
27618
- apiError.extras = extras;
27619
- throw apiError;
27619
+ throw buildApiError(res, rawErrorBody);
27620
27620
  }
27621
27621
  if (res.status === 204)
27622
27622
  return void 0;
@@ -27854,8 +27854,8 @@ var ParallClient = class _ParallClient {
27854
27854
  const res = await this.request("GET", ENDPOINTS.CHAT_MEMBERS(orgId, chatId));
27855
27855
  return res.data;
27856
27856
  }
27857
- async addChatMember(orgId, chatId, userId, role) {
27858
- return this.request("POST", ENDPOINTS.CHAT_MEMBERS(orgId, chatId), { user_id: userId, role });
27857
+ async addChatMember(orgId, chatId, userId) {
27858
+ return this.request("POST", ENDPOINTS.CHAT_MEMBERS(orgId, chatId), { user_id: userId });
27859
27859
  }
27860
27860
  async removeChatMember(orgId, chatId, userId) {
27861
27861
  return this.request("DELETE", ENDPOINTS.CHAT_MEMBER(orgId, chatId, userId));
@@ -28114,6 +28114,16 @@ var ParallClient = class _ParallClient {
28114
28114
  llm_source: llmSource2
28115
28115
  });
28116
28116
  }
28117
+ /**
28118
+ * Toggle whether the machine contributes its local clips as a hub provider
28119
+ * — org-admin-gated (RequireOrgAdmin), like all machine management. See
28120
+ * docs/engineering-design/clip-provider-sharing-design.md.
28121
+ */
28122
+ async patchMachineProviderEnabled(orgId, machineId, providerEnabled) {
28123
+ return this.request("PATCH", ENDPOINTS.MACHINE_PROVIDER_ENABLED(orgId, machineId), {
28124
+ provider_enabled: providerEnabled
28125
+ });
28126
+ }
28117
28127
  /** Get machine-level runtime auth state. */
28118
28128
  async getMachineRuntimeAuth(orgId, machineId) {
28119
28129
  return this.request("GET", ENDPOINTS.MACHINE_RUNTIME_AUTH(orgId, machineId));
@@ -28147,25 +28157,39 @@ var ParallClient = class _ParallClient {
28147
28157
  const res = await this.request("GET", ENDPOINTS.MACHINES_ME_AGENTS);
28148
28158
  return res.data;
28149
28159
  }
28150
- /** `GET /machines/me/clip-installs` — registry clips this machine should
28151
- * install but hasn't yet (durable reconcile, mck_-authed). */
28152
- async listClipInstalls() {
28153
- const res = await this.request("GET", ENDPOINTS.MACHINES_ME_CLIP_INSTALLS);
28160
+ /** `GET /machines/me/clips` — executable Clip definitions assigned to this machine. */
28161
+ async listMachineClips() {
28162
+ const res = await this.request("GET", ENDPOINTS.MACHINES_ME_CLIPS);
28154
28163
  return res.data;
28155
28164
  }
28156
- /** `POST /machines/me/clip-installs/{clipId}/installed` — report a finished install. */
28157
- async reportClipInstall(clipId, version) {
28158
- return this.request("POST", ENDPOINTS.MACHINES_ME_CLIP_INSTALL_DONE(clipId), version ? { version } : void 0);
28165
+ /** `GET /machines/me/browser-profiles` — browser profiles hosted by this machine. */
28166
+ async listMachineBrowserProfiles() {
28167
+ const res = await this.request("GET", ENDPOINTS.MACHINES_ME_BROWSER_PROFILES);
28168
+ return res.data;
28169
+ }
28170
+ /** `POST /machines/me/browser-profiles/{profileId}/status` — report runtime status. */
28171
+ async reportBrowserProfileStatus(profileId, status, errorMsg) {
28172
+ await this.request("POST", ENDPOINTS.MACHINES_ME_BROWSER_PROFILE_STATUS(profileId), {
28173
+ status,
28174
+ ...errorMsg ? { error_msg: errorMsg } : {}
28175
+ });
28159
28176
  }
28160
28177
  /**
28161
- * `POST /machines/me/health` — bump the Machine's `updated_at` to now.
28162
- * Body is intentionally empty; the server ignores any payload. The
28163
- * daemon should call this on a fixed cadence (e.g. every 30s) so an
28164
- * external observer can detect a wedged supervisor.
28178
+ * `POST /machines/me/health` — bump the Machine's `updated_at` to now and
28179
+ * report daemon state. The daemon should call this on a fixed cadence (e.g.
28180
+ * every 30s) so an external observer can detect a wedged supervisor. Both
28181
+ * fields are optional and only persisted when changed:
28182
+ * - `daemonVersion` — the running bundle/launcher version.
28183
+ * - `selfUpdateCapable` — whether the daemon can act on a machine.update
28184
+ * signal (true under a service manager, false for bare `npx` foreground).
28165
28185
  */
28166
- async postMachineHeartbeat(daemonVersion) {
28167
- const body = daemonVersion ? { daemon_version: daemonVersion } : void 0;
28168
- return this.request("POST", ENDPOINTS.MACHINES_ME_HEALTH, body);
28186
+ async postMachineHeartbeat(opts) {
28187
+ const body = {};
28188
+ if (opts?.daemonVersion)
28189
+ body.daemon_version = opts.daemonVersion;
28190
+ if (opts?.selfUpdateCapable !== void 0)
28191
+ body.self_update_capable = opts.selfUpdateCapable;
28192
+ return this.request("POST", ENDPOINTS.MACHINES_ME_HEALTH, Object.keys(body).length > 0 ? body : void 0);
28169
28193
  }
28170
28194
  async reportAgentWorkspaceState(agentId, state) {
28171
28195
  const res = await this.request("PUT", ENDPOINTS.MACHINES_ME_AGENT_WORKSPACE_STATE(agentId), state);
@@ -28267,6 +28291,10 @@ var ParallClient = class _ParallClient {
28267
28291
  async ackDispatchByID(orgId, id) {
28268
28292
  return this.request("POST", ENDPOINTS.DISPATCH_ACK_BY_ID(orgId, id));
28269
28293
  }
28294
+ async expireDispatch(orgId, maxAgeHours) {
28295
+ const params = maxAgeHours !== void 0 ? { max_age_hours: String(maxAgeHours) } : void 0;
28296
+ return this.request("POST", ENDPOINTS.DISPATCH_EXPIRE(orgId), void 0, params);
28297
+ }
28270
28298
  async getDispatchByMessages(orgId, chatId, messageIds) {
28271
28299
  const params = { chat_id: chatId, message_ids: messageIds.join(",") };
28272
28300
  return this.request("GET", ENDPOINTS.DISPATCH_BY_MESSAGES(orgId), void 0, params);
@@ -28298,15 +28326,7 @@ var ParallClient = class _ParallClient {
28298
28326
  return null;
28299
28327
  if (!res.ok) {
28300
28328
  const rawErrorBody = await res.json().catch(() => ({}));
28301
- const errorBody = rawErrorBody !== null && typeof rawErrorBody === "object" ? rawErrorBody : {};
28302
- const errorObj = errorBody?.error && typeof errorBody.error === "object" ? errorBody.error : void 0;
28303
- const errMsg = errorObj?.message ?? (typeof errorBody?.error === "string" ? errorBody.error : void 0);
28304
- const errCode = errorObj?.code ?? (typeof errorBody?.code === "string" ? errorBody.code : void 0);
28305
- const apiError = new ApiError(res.status, errMsg ?? res.statusText, errCode);
28306
- const { error: _e, code: _c, message: _m, ...extras } = errorBody;
28307
- if (Object.keys(extras).length > 0)
28308
- apiError.extras = extras;
28309
- throw apiError;
28329
+ throw buildApiError(res, rawErrorBody);
28310
28330
  }
28311
28331
  return res.json();
28312
28332
  }
@@ -28755,6 +28775,41 @@ var ParallClient = class _ParallClient {
28755
28775
  const resp = await this.request("GET", ENDPOINTS.CLIP_ONLINE(orgId));
28756
28776
  return resp.data;
28757
28777
  }
28778
+ async listBrowserProfiles(orgId) {
28779
+ const resp = await this.request("GET", ENDPOINTS.BROWSER_PROFILES(orgId));
28780
+ return resp.data;
28781
+ }
28782
+ async createBrowserProfile(orgId, req) {
28783
+ return this.request("POST", ENDPOINTS.BROWSER_PROFILES(orgId), req);
28784
+ }
28785
+ async getBrowserProfile(orgId, profileId) {
28786
+ return this.request("GET", ENDPOINTS.BROWSER_PROFILE(orgId, profileId));
28787
+ }
28788
+ async updateBrowserProfile(orgId, profileId, req) {
28789
+ return this.request("PATCH", ENDPOINTS.BROWSER_PROFILE(orgId, profileId), req);
28790
+ }
28791
+ async deleteBrowserProfile(orgId, profileId) {
28792
+ await this.request("DELETE", ENDPOINTS.BROWSER_PROFILE(orgId, profileId));
28793
+ }
28794
+ async openBrowserProfile(orgId, profileId, req = {}) {
28795
+ return this.request("POST", ENDPOINTS.BROWSER_PROFILE_OPEN(orgId, profileId), req);
28796
+ }
28797
+ async stopBrowserProfile(orgId, profileId) {
28798
+ return this.request("POST", ENDPOINTS.BROWSER_PROFILE_STOP(orgId, profileId), {});
28799
+ }
28800
+ async resetBrowserProfile(orgId, profileId) {
28801
+ return this.request("POST", ENDPOINTS.BROWSER_PROFILE_RESET(orgId, profileId));
28802
+ }
28803
+ async listBrowserProfileConsents(orgId, profileId) {
28804
+ const resp = await this.request("GET", ENDPOINTS.BROWSER_PROFILE_CONSENTS(orgId, profileId));
28805
+ return resp.data;
28806
+ }
28807
+ async grantBrowserProfileConsent(orgId, profileId, req) {
28808
+ return this.request("POST", ENDPOINTS.BROWSER_PROFILE_CONSENTS(orgId, profileId), req);
28809
+ }
28810
+ async revokeBrowserProfileConsent(orgId, profileId, clipId) {
28811
+ await this.request("DELETE", ENDPOINTS.BROWSER_PROFILE_CONSENT(orgId, profileId, clipId));
28812
+ }
28758
28813
  async listRegistryClips(q) {
28759
28814
  const url = ENDPOINTS.CLIP_REGISTRY() + (q ? `?q=${encodeURIComponent(q)}` : "");
28760
28815
  const resp = await this.request("GET", url);
@@ -28772,6 +28827,12 @@ var ApiError = class extends Error {
28772
28827
  status;
28773
28828
  code;
28774
28829
  extras;
28830
+ /** Attempted action (authorization denials) — e.g. "chat.add_member". */
28831
+ action;
28832
+ /** Target resource URI that was evaluated — e.g. "prll://cht_…". */
28833
+ resourceUri;
28834
+ /** Whether the action is approval-executable (PERMISSION_DENIED only). */
28835
+ approvable;
28775
28836
  constructor(status, message, code) {
28776
28837
  super(message);
28777
28838
  this.status = status;
@@ -28779,6 +28840,33 @@ var ApiError = class extends Error {
28779
28840
  this.name = "ApiError";
28780
28841
  }
28781
28842
  };
28843
+ function buildApiError(res, rawErrorBody) {
28844
+ const errorBody = rawErrorBody !== null && typeof rawErrorBody === "object" ? rawErrorBody : {};
28845
+ const errorObj = errorBody.error && typeof errorBody.error === "object" ? errorBody.error : void 0;
28846
+ const errMsg = (typeof errorObj?.message === "string" ? errorObj.message : void 0) ?? (typeof errorBody.message === "string" ? errorBody.message : void 0) ?? (typeof errorBody.error === "string" ? errorBody.error : void 0);
28847
+ const errCode = (typeof errorObj?.code === "string" ? errorObj.code : void 0) ?? (typeof errorBody.code === "string" ? errorBody.code : void 0);
28848
+ const apiError = new ApiError(res.status, errMsg ?? res.statusText, errCode);
28849
+ const anchors = errorObj ?? errorBody;
28850
+ if (typeof anchors.action === "string")
28851
+ apiError.action = anchors.action;
28852
+ if (typeof anchors.resource_uri === "string")
28853
+ apiError.resourceUri = anchors.resource_uri;
28854
+ if (typeof anchors.approvable === "boolean")
28855
+ apiError.approvable = anchors.approvable;
28856
+ const structural = /* @__PURE__ */ new Set(["error", "code", "message", "status"]);
28857
+ const extras = {};
28858
+ for (const [k, v] of Object.entries(errorBody))
28859
+ if (!structural.has(k))
28860
+ extras[k] = v;
28861
+ if (errorObj) {
28862
+ for (const [k, v] of Object.entries(errorObj))
28863
+ if (!structural.has(k))
28864
+ extras[k] = v;
28865
+ }
28866
+ if (Object.keys(extras).length > 0)
28867
+ apiError.extras = extras;
28868
+ return apiError;
28869
+ }
28782
28870
 
28783
28871
  // ts/sdk/dist/ws.js
28784
28872
  function isRetryableNetworkError(err) {
@@ -30705,8 +30793,28 @@ var ParallAgentGateway = class {
30705
30793
  return dispatched;
30706
30794
  }
30707
30795
  async catchUpFromDispatch() {
30796
+ const OVERFLOW_THRESHOLD = 500;
30797
+ const EXPIRE_AGE_HOURS = 24;
30798
+ const CATCHUP_MAX = 10;
30799
+ let expireSummary = null;
30800
+ let overflowMode = false;
30801
+ try {
30802
+ const { count } = await this.opts.client.getDispatchPendingCount(this.opts.config.org_id);
30803
+ if (count > OVERFLOW_THRESHOLD) {
30804
+ overflowMode = true;
30805
+ const result = await this.opts.client.expireDispatch(this.opts.config.org_id, EXPIRE_AGE_HOURS);
30806
+ if (result.total > 0) {
30807
+ this.opts.log?.warn(`dispatch catch-up overflow: ${count} pending, expired ${result.total} events older than ${EXPIRE_AGE_HOURS}h`);
30808
+ expireSummary = this.buildOfflineSummary(result.groups);
30809
+ }
30810
+ }
30811
+ } catch (err) {
30812
+ this.opts.log?.warn(`dispatch catch-up overflow check failed: ${String(err)}`);
30813
+ }
30708
30814
  let cursor;
30709
30815
  let processed = 0;
30816
+ let skipped = 0;
30817
+ const skippedByType = /* @__PURE__ */ new Map();
30710
30818
  do {
30711
30819
  const page = await this.opts.client.getDispatch(this.opts.config.org_id, {
30712
30820
  limit: 50,
@@ -30715,6 +30823,17 @@ var ParallAgentGateway = class {
30715
30823
  for (const item of page.data ?? []) {
30716
30824
  if (this.shuttingDown)
30717
30825
  break;
30826
+ if (overflowMode && processed >= CATCHUP_MAX) {
30827
+ try {
30828
+ await this.opts.client.ackDispatchByID(this.opts.config.org_id, item.id);
30829
+ skipped++;
30830
+ const key = item.event_type;
30831
+ skippedByType.set(key, (skippedByType.get(key) ?? 0) + 1);
30832
+ } catch {
30833
+ this.opts.log?.warn(`catch-up skip ack failed for ${item.id}, leaving pending`);
30834
+ }
30835
+ continue;
30836
+ }
30718
30837
  processed++;
30719
30838
  try {
30720
30839
  let dispatched = false;
@@ -30789,9 +30908,52 @@ var ParallAgentGateway = class {
30789
30908
  }
30790
30909
  cursor = !this.shuttingDown && page.has_more ? page.next_cursor : void 0;
30791
30910
  } while (cursor);
30792
- if (processed > 0) {
30793
- this.opts.log?.info(`dispatch catch-up: processed ${processed}`);
30911
+ if (expireSummary || skipped > 0) {
30912
+ const parts = [];
30913
+ if (expireSummary)
30914
+ parts.push(expireSummary);
30915
+ if (skipped > 0) {
30916
+ const recentLines = [...skippedByType.entries()].map(([type, count]) => `- ${count} recent ${type.replace(".", " ").replace("_", " ")} events`).join("\n");
30917
+ parts.push(expireSummary ? `Additionally, ${skipped} recent events exceeded the catch-up limit and were skipped:
30918
+ ${recentLines}` : `[Offline Summary] You were offline. ${skipped} pending events exceeded the catch-up limit and were skipped:
30919
+ ${recentLines}
30920
+
30921
+ Use your tools (read messages, check tasks) to review anything still relevant.`);
30922
+ }
30923
+ const fullSummary = parts.join("\n\n");
30924
+ this.pendingRestartNotification = this.pendingRestartNotification ? `${this.pendingRestartNotification}
30925
+
30926
+ ${fullSummary}` : fullSummary;
30927
+ }
30928
+ if (processed > 0 || skipped > 0) {
30929
+ this.opts.log?.info(`dispatch catch-up: processed ${processed}, skipped ${skipped}`);
30930
+ }
30931
+ }
30932
+ buildOfflineSummary(groups) {
30933
+ const lines = [
30934
+ "[Offline Summary] You were offline and had a large backlog of pending events. The following old events were skipped:"
30935
+ ];
30936
+ for (const g of groups) {
30937
+ const age = this.formatAge(g.oldest);
30938
+ if (g.chat_id && g.event_type === "message") {
30939
+ const name = g.chat_name ?? g.chat_id;
30940
+ lines.push(`- ${g.count} messages in "${name}" (oldest: ${age})`);
30941
+ } else {
30942
+ const label = g.event_type.replace(".", " ").replace("_", " ");
30943
+ lines.push(`- ${g.count} ${label} events (oldest: ${age})`);
30944
+ }
30794
30945
  }
30946
+ lines.push("");
30947
+ lines.push("These events were too old to process individually. Use your tools (read messages, check tasks) to review anything still relevant.");
30948
+ return lines.join("\n");
30949
+ }
30950
+ formatAge(iso) {
30951
+ const ms = Date.now() - new Date(iso).getTime();
30952
+ const hours = Math.floor(ms / 36e5);
30953
+ if (hours < 24)
30954
+ return `${hours}h ago`;
30955
+ const days = Math.floor(hours / 24);
30956
+ return `${days}d ago`;
30795
30957
  }
30796
30958
  async handleHello(data) {
30797
30959
  const { client, config, log: log2 } = this.opts;
@@ -31113,7 +31275,11 @@ parall dm "Alice" --file /tmp/report.pdf --text "Report attached"
31113
31275
 
31114
31276
  ## Approvals
31115
31277
 
31116
- When a CLI command returns a \`PERMISSION_DENIED\` error, the output includes a \`Tip:\` line with an approval-request template \u2014 copy it and fill in the remaining placeholders (\`--chat\`, \`--title\`, \`--reason\`). The \`Tip:\` only appears for commonly approvable actions (archive, delete, restore); for other actions, use \`parall approvals actions\` to check if it's approvable.
31278
+ When a CLI command returns a \`PERMISSION_DENIED\` error, the output includes the denied \`action\` and \`resource_uri\`. Whether that action can be approved is decided by the server (there is no fixed allowlist):
31279
+ - If it IS approvable, a \`Request approval:\` line with a \`parall approvals request\` command follows \u2014 fill in the placeholders it shows (\`--chat\`, \`--title\`, \`--reason\`) and run it.
31280
+ - If it is NOT approvable, the output says so \u2014 ask a human with permission instead of requesting approval.
31281
+
31282
+ A different \`INVALID_TARGET\` error means you addressed the wrong kind of thing (e.g. a \`usr_\` id where a chat is expected). Follow the message (e.g. use \`parall dm\` to message a user) \u2014 do not request approval for it.
31117
31283
 
31118
31284
  \`\`\`bash
31119
31285
  # Request approval (use action and resource_uri from the error)
@@ -31155,7 +31321,7 @@ Every entity is addressable with a \`prll://\` URI. Common prefixes you'll see i
31155
31321
 
31156
31322
  When a message or event references \`prll://sch_xxx\` or \`prll://srn_xxx\`, or when you receive \`[Event: schedule.fired]\`, switch to the **parall-schedules** skill for the CLI commands (create / list / pause / resume / cancel / runs).
31157
31323
 
31158
- All CLI output is JSON.
31324
+ CLI success output is JSON. Errors print a JSON line (\`{"error","status","code",...}\`) and, on a \`PERMISSION_DENIED\`, may add a plain-text \`Request approval:\` line \u2014 read both.
31159
31325
  `;
31160
31326
 
31161
31327
  // ts/agent-core/dist/skills/parall-tasks.js
@@ -31222,7 +31388,7 @@ When you receive \`[Event: task.comment.created]\`, someone commented on a task
31222
31388
  2. Reply via comment: \`tasks comments add prll://tsk_xxx --body "Response..."\`
31223
31389
  3. If the comment requests status changes, update accordingly
31224
31390
 
31225
- All CLI output is JSON.
31391
+ CLI success output is JSON; errors print a JSON line plus, on a \`PERMISSION_DENIED\`, an optional plain-text \`Request approval:\` line \u2014 read both.
31226
31392
  `;
31227
31393
 
31228
31394
  // ts/agent-core/dist/skills/parall-wiki.js
@@ -31355,7 +31521,7 @@ parall wiki reset <slug> # Restore all files to last synced state
31355
31521
  parall wiki log <slug> # Recent wiki operations
31356
31522
  \`\`\`
31357
31523
 
31358
- All CLI output is JSON. Run \`parall wiki --help\` for full options.
31524
+ CLI success output is JSON; errors may add a plain-text \`Request approval:\` line on a \`PERMISSION_DENIED\` \u2014 read both. Run \`parall wiki --help\` for full options.
31359
31525
  `;
31360
31526
 
31361
31527
  // ts/agent-core/dist/skills/parall-schedules.js