@parall/daemon 1.52.0 → 1.52.2
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/bundle/manifest.json +11 -11
- package/bundle/parall-browser-pod.js +66 -12
- package/bundle/parall-claude-agent.js +177 -60
- package/bundle/parall-codex-agent.js +180 -62
- package/bundle/parall-daemon.js +66 -12
- package/package.json +6 -6
package/bundle/manifest.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
|
-
"version": "1.52.
|
|
3
|
-
"built_at": "2026-08-
|
|
2
|
+
"version": "1.52.2",
|
|
3
|
+
"built_at": "2026-08-05T06:13:33.099Z",
|
|
4
4
|
"min_node_version": "20.0.0",
|
|
5
5
|
"files": {
|
|
6
6
|
"bb-browser-daemon.js": {
|
|
@@ -16,29 +16,29 @@
|
|
|
16
16
|
"size": 18
|
|
17
17
|
},
|
|
18
18
|
"parall-browser-pod.js": {
|
|
19
|
-
"sha256": "
|
|
20
|
-
"size":
|
|
19
|
+
"sha256": "4d5b8c1f431963dac5ab39cbca769e63db91d0e0c15a118b9c8aa9fba0a19ecf",
|
|
20
|
+
"size": 2916134
|
|
21
21
|
},
|
|
22
22
|
"parall-channel-exec.js": {
|
|
23
23
|
"sha256": "7c2a6e12483a45e9eb4a42cd7d4cdd3c4fa21dd09ac1347d9a3e177b4ddee930",
|
|
24
24
|
"size": 7220
|
|
25
25
|
},
|
|
26
26
|
"parall-claude-agent.js": {
|
|
27
|
-
"sha256": "
|
|
28
|
-
"size":
|
|
27
|
+
"sha256": "2b780cc9718945476c05ae4f173426c5f064150ce7af499dba339ed293b4afff",
|
|
28
|
+
"size": 2779447
|
|
29
29
|
},
|
|
30
30
|
"parall-codex-agent.js": {
|
|
31
|
-
"sha256": "
|
|
32
|
-
"size":
|
|
31
|
+
"sha256": "40ec7af38394abf1a926e4b982a08a110f3902cd609bdb1d9c5453f1e3d43434",
|
|
32
|
+
"size": 2810151
|
|
33
33
|
},
|
|
34
34
|
"parall-daemon.js": {
|
|
35
|
-
"sha256": "
|
|
36
|
-
"size":
|
|
35
|
+
"sha256": "b2e754ab09cf56e435b5947275968401721b3f194193701a6447e4d0ef2d61a9",
|
|
36
|
+
"size": 2977953
|
|
37
37
|
},
|
|
38
38
|
"parall-openclaw-agent.js": {
|
|
39
39
|
"sha256": "856a1c3a9ae0ffef8efe2481fa1171dbeb1d67cccb88616aa9bf16da96a69355",
|
|
40
40
|
"size": 9923
|
|
41
41
|
}
|
|
42
42
|
},
|
|
43
|
-
"signature": "
|
|
43
|
+
"signature": "d11VXm3N6e4KIaGx7lp08AdQA9IE3RNCbcj673a+Wd7u2ibl/5VgBCXAMlOaO9HS3PoCGF1IMh3lsFciaHQ7Ag=="
|
|
44
44
|
}
|
|
@@ -63715,6 +63715,8 @@ var ENDPOINTS = {
|
|
|
63715
63715
|
SLACK_HISTORY: (orgId) => `${API_BASE}/orgs/${orgId}/agents/me/slack/history`,
|
|
63716
63716
|
SLACK_MEMBERS: (orgId) => `${API_BASE}/orgs/${orgId}/agents/me/slack/members`,
|
|
63717
63717
|
SLACK_STATUS: (orgId) => `${API_BASE}/orgs/${orgId}/agents/me/slack/status`,
|
|
63718
|
+
// WeChat tier-B read verb (agent-only; internal research preview).
|
|
63719
|
+
WECHAT_CONTACTS: (orgId) => `${API_BASE}/orgs/${orgId}/agents/me/wechat/contacts`,
|
|
63718
63720
|
// Invitations (org-scoped, admin)
|
|
63719
63721
|
ORG_INVITATIONS: (orgId) => `${API_BASE}/orgs/${orgId}/invitations`,
|
|
63720
63722
|
ORG_INVITATION: (orgId, invId) => `${API_BASE}/orgs/${orgId}/invitations/${invId}`,
|
|
@@ -63876,8 +63878,6 @@ var ENDPOINTS = {
|
|
|
63876
63878
|
// Live viewer command — on api-server (API_BASE), not clip-service: it rides
|
|
63877
63879
|
// the machine control-plane request/reply bridge that lives in api-server.
|
|
63878
63880
|
BROWSER_PROFILE_VIEWER_COMMAND: (orgId, profileId) => `${API_BASE}/orgs/${orgId}/browser-profiles/${profileId}/viewer/command`,
|
|
63879
|
-
// Clip registry (global, served by clip-service → Pinix Hub proxy)
|
|
63880
|
-
CLIP_REGISTRY: () => `${CLIP_BASE}/registry/clips`,
|
|
63881
63881
|
// Edge device endpoints
|
|
63882
63882
|
ORG_EDGE: (orgId) => `/api/v1/orgs/${orgId}/edge`,
|
|
63883
63883
|
ORG_EDGE_DEVICES: (orgId) => `/api/v1/orgs/${orgId}/edge/devices`,
|
|
@@ -63894,15 +63894,20 @@ var ENDPOINTS = {
|
|
|
63894
63894
|
ORG_EDGE_VIEWER_COMMAND: (orgId, edgeId) => `/api/v1/orgs/${orgId}/edge/${edgeId}/viewer/command`,
|
|
63895
63895
|
CLIP_CONNECTIONS: (orgId, clipId) => `/api/v1/orgs/${orgId}/clip-registry/${clipId}/connections`,
|
|
63896
63896
|
CLIP_CONNECTION: (orgId, connId) => `/api/v1/orgs/${orgId}/clip-connections/${connId}`,
|
|
63897
|
-
// Clip registry (v3, org-scoped, served by api-server — `crg_` entries
|
|
63898
|
-
// Pinix Hub catalog proxy above is a different, id-less surface)
|
|
63897
|
+
// Clip registry (v3, org-scoped, served by api-server — `crg_` entries)
|
|
63899
63898
|
ORG_CLIP_REGISTRY: (orgId) => `/api/v1/orgs/${orgId}/clip-registry`,
|
|
63899
|
+
ORG_CLIP_REGISTRY_CLIP: (orgId, clipId) => `/api/v1/orgs/${orgId}/clip-registry/${clipId}`,
|
|
63900
|
+
ORG_CLIP_REGISTRY_PUBLISH: (orgId) => `/api/v1/orgs/${orgId}/clip-registry/publish`,
|
|
63900
63901
|
ORG_CLIP_INSTALL: (orgId) => `/api/v1/orgs/${orgId}/clips/install`,
|
|
63901
63902
|
ORG_CLIPS_INSTALLED: (orgId) => `/api/v1/orgs/${orgId}/clips/installed`,
|
|
63903
|
+
ORG_CLIP_UNINSTALL: (orgId, clipId) => `/api/v1/orgs/${orgId}/clips/${clipId}/uninstall`,
|
|
63904
|
+
// Per-org agent exec access for one clip (default all agents; PUT human-only)
|
|
63905
|
+
ORG_CLIP_EXEC_ACCESS: (orgId, clipId) => `/api/v1/orgs/${orgId}/clips/${clipId}/exec-access`,
|
|
63902
63906
|
// MCP clip server config (cap:clip-mcp; publisher-org only — cross-org gets
|
|
63903
63907
|
// 403 MCP_CROSS_ORG_DISABLED on the whole family, reads included)
|
|
63904
63908
|
ORG_CLIP_MCP_CONFIG: (orgId, clipId) => `/api/v1/orgs/${orgId}/clip-registry/${clipId}/mcp-config`,
|
|
63905
|
-
ORG_CLIP_MCP_TOOLS_REFRESH: (orgId, clipId) => `/api/v1/orgs/${orgId}/clip-registry/${clipId}/mcp-config/tools/refresh
|
|
63909
|
+
ORG_CLIP_MCP_TOOLS_REFRESH: (orgId, clipId) => `/api/v1/orgs/${orgId}/clip-registry/${clipId}/mcp-config/tools/refresh`,
|
|
63910
|
+
ORG_CLIP_MCP_OAUTH_DISCONNECT: (orgId, clipId) => `/api/v1/orgs/${orgId}/clip-registry/${clipId}/mcp-config/oauth/disconnect`
|
|
63906
63911
|
};
|
|
63907
63912
|
|
|
63908
63913
|
// ts/sdk/dist/client.js
|
|
@@ -65312,6 +65317,14 @@ var ParallClient = class _ParallClient {
|
|
|
65312
65317
|
async setSlackStatus(orgId, input) {
|
|
65313
65318
|
await this.request("POST", ENDPOINTS.SLACK_STATUS(orgId), input);
|
|
65314
65319
|
}
|
|
65320
|
+
/**
|
|
65321
|
+
* WeChat tier-B read verb (agent-only; internal research preview): the
|
|
65322
|
+
* account's address book — friend wxids, saved group room ids, followed
|
|
65323
|
+
* official accounts. Same live gate as the send verb.
|
|
65324
|
+
*/
|
|
65325
|
+
async listWechatContacts(orgId) {
|
|
65326
|
+
return this.request("GET", ENDPOINTS.WECHAT_CONTACTS(orgId));
|
|
65327
|
+
}
|
|
65315
65328
|
async listChannelConversations(orgId, connectionId) {
|
|
65316
65329
|
return this.request("GET", ENDPOINTS.CHANNEL_CONNECTION_CONVERSATIONS(orgId, connectionId));
|
|
65317
65330
|
}
|
|
@@ -65850,17 +65863,11 @@ var ParallClient = class _ParallClient {
|
|
|
65850
65863
|
async revokeBrowserProfileConsent(orgId, profileId, clipId) {
|
|
65851
65864
|
await this.request("DELETE", ENDPOINTS.BROWSER_PROFILE_CONSENT(orgId, profileId, clipId));
|
|
65852
65865
|
}
|
|
65853
|
-
async listRegistryClips(q2) {
|
|
65854
|
-
const url = ENDPOINTS.CLIP_REGISTRY() + (q2 ? `?q=${encodeURIComponent(q2)}` : "");
|
|
65855
|
-
const resp = await this.request("GET", url);
|
|
65856
|
-
return resp.data;
|
|
65857
|
-
}
|
|
65858
65866
|
// ---- Clip registry (v3, api-server org registry — `crg_` entries) ----
|
|
65859
65867
|
/**
|
|
65860
65868
|
* List registry clips visible to the org: its own plus public+approved
|
|
65861
65869
|
* cross-org entries. This is the surface `installRegistryClip` and clip
|
|
65862
|
-
* connections operate on
|
|
65863
|
-
* ({@link listRegistryClips}), whose entries carry no `crg_` id.
|
|
65870
|
+
* connections operate on.
|
|
65864
65871
|
*/
|
|
65865
65872
|
async listOrgRegistryClips(orgId) {
|
|
65866
65873
|
const resp = await this.request("GET", `${ENDPOINTS.ORG_CLIP_REGISTRY(orgId)}?limit=100`);
|
|
@@ -65875,11 +65882,58 @@ var ParallClient = class _ParallClient {
|
|
|
65875
65882
|
async installRegistryClip(orgId, clipId) {
|
|
65876
65883
|
return this.request("POST", ENDPOINTS.ORG_CLIP_INSTALL(orgId), { clip_id: clipId });
|
|
65877
65884
|
}
|
|
65885
|
+
/**
|
|
65886
|
+
* Remove an org's install of a registry clip. Keyed by the REGISTRY id
|
|
65887
|
+
* (`crg_`), the same id {@link installRegistryClip} takes — the v2
|
|
65888
|
+
* `deleteClip` operates on a different table and cannot reach these.
|
|
65889
|
+
*/
|
|
65890
|
+
async uninstallRegistryClip(orgId, clipId) {
|
|
65891
|
+
await this.request("DELETE", ENDPOINTS.ORG_CLIP_UNINSTALL(orgId, clipId));
|
|
65892
|
+
}
|
|
65878
65893
|
/** List the org's installed registry clips (full entries). */
|
|
65879
65894
|
async listInstalledRegistryClips(orgId) {
|
|
65880
65895
|
const resp = await this.request("GET", ENDPOINTS.ORG_CLIPS_INSTALLED(orgId));
|
|
65881
65896
|
return resp ?? [];
|
|
65882
65897
|
}
|
|
65898
|
+
/**
|
|
65899
|
+
* Fetch one registry clip by its `crg_` id. For a clip OWNED by the calling
|
|
65900
|
+
* org the entry additionally carries `review_status`/`review_note` — the
|
|
65901
|
+
* state of the latest submitted version and the reviewer's rejection
|
|
65902
|
+
* feedback. This is the polling surface for "did platform review approve my
|
|
65903
|
+
* public publish yet"; cross-org callers see only public+approved entries
|
|
65904
|
+
* and never any review-state fields.
|
|
65905
|
+
*/
|
|
65906
|
+
async getRegistryClip(orgId, clipId) {
|
|
65907
|
+
return this.request("GET", ENDPOINTS.ORG_CLIP_REGISTRY_CLIP(orgId, clipId));
|
|
65908
|
+
}
|
|
65909
|
+
/**
|
|
65910
|
+
* Publish (create, or author-only update) a clip in the org registry,
|
|
65911
|
+
* replacing its whole file set. See {@link PublishRegistryClipRequest} for
|
|
65912
|
+
* the visibility/review semantics; the returned entry carries
|
|
65913
|
+
* `review_status` when a public publish queued a review submission — poll
|
|
65914
|
+
* {@link getRegistryClip} for the outcome.
|
|
65915
|
+
*/
|
|
65916
|
+
async publishRegistryClip(orgId, req) {
|
|
65917
|
+
return this.request("POST", ENDPOINTS.ORG_CLIP_REGISTRY_PUBLISH(orgId), req, void 0, false, {
|
|
65918
|
+
timeoutMs: 6e4
|
|
65919
|
+
});
|
|
65920
|
+
}
|
|
65921
|
+
/**
|
|
65922
|
+
* Read a clip's per-org agent exec access. Org-member readable (agents
|
|
65923
|
+
* included, so a denied agent can learn why exec answered
|
|
65924
|
+
* `CLIP_AGENT_NOT_ALLOWED`).
|
|
65925
|
+
*/
|
|
65926
|
+
async getClipAgentExecAccess(orgId, clipId) {
|
|
65927
|
+
return this.request("GET", ENDPOINTS.ORG_CLIP_EXEC_ACCESS(orgId, clipId));
|
|
65928
|
+
}
|
|
65929
|
+
/**
|
|
65930
|
+
* Replace a clip's per-org agent exec access. Human-only (agent principals
|
|
65931
|
+
* get 403); under `all_agents` the `agent_ids` must be empty. Every granted
|
|
65932
|
+
* id must be an active agent of this org (else `400 INVALID_INPUT`).
|
|
65933
|
+
*/
|
|
65934
|
+
async putClipAgentExecAccess(orgId, clipId, access) {
|
|
65935
|
+
return this.request("PUT", ENDPOINTS.ORG_CLIP_EXEC_ACCESS(orgId, clipId), access);
|
|
65936
|
+
}
|
|
65883
65937
|
// ---- Edge devices ----
|
|
65884
65938
|
async listEdgeDevices(orgId) {
|
|
65885
65939
|
return this.request("GET", ENDPOINTS.ORG_EDGE_DEVICES(orgId));
|
|
@@ -51511,6 +51511,8 @@ var ENDPOINTS = {
|
|
|
51511
51511
|
SLACK_HISTORY: (orgId) => `${API_BASE}/orgs/${orgId}/agents/me/slack/history`,
|
|
51512
51512
|
SLACK_MEMBERS: (orgId) => `${API_BASE}/orgs/${orgId}/agents/me/slack/members`,
|
|
51513
51513
|
SLACK_STATUS: (orgId) => `${API_BASE}/orgs/${orgId}/agents/me/slack/status`,
|
|
51514
|
+
// WeChat tier-B read verb (agent-only; internal research preview).
|
|
51515
|
+
WECHAT_CONTACTS: (orgId) => `${API_BASE}/orgs/${orgId}/agents/me/wechat/contacts`,
|
|
51514
51516
|
// Invitations (org-scoped, admin)
|
|
51515
51517
|
ORG_INVITATIONS: (orgId) => `${API_BASE}/orgs/${orgId}/invitations`,
|
|
51516
51518
|
ORG_INVITATION: (orgId, invId) => `${API_BASE}/orgs/${orgId}/invitations/${invId}`,
|
|
@@ -51672,8 +51674,6 @@ var ENDPOINTS = {
|
|
|
51672
51674
|
// Live viewer command — on api-server (API_BASE), not clip-service: it rides
|
|
51673
51675
|
// the machine control-plane request/reply bridge that lives in api-server.
|
|
51674
51676
|
BROWSER_PROFILE_VIEWER_COMMAND: (orgId, profileId) => `${API_BASE}/orgs/${orgId}/browser-profiles/${profileId}/viewer/command`,
|
|
51675
|
-
// Clip registry (global, served by clip-service → Pinix Hub proxy)
|
|
51676
|
-
CLIP_REGISTRY: () => `${CLIP_BASE}/registry/clips`,
|
|
51677
51677
|
// Edge device endpoints
|
|
51678
51678
|
ORG_EDGE: (orgId) => `/api/v1/orgs/${orgId}/edge`,
|
|
51679
51679
|
ORG_EDGE_DEVICES: (orgId) => `/api/v1/orgs/${orgId}/edge/devices`,
|
|
@@ -51690,15 +51690,20 @@ var ENDPOINTS = {
|
|
|
51690
51690
|
ORG_EDGE_VIEWER_COMMAND: (orgId, edgeId) => `/api/v1/orgs/${orgId}/edge/${edgeId}/viewer/command`,
|
|
51691
51691
|
CLIP_CONNECTIONS: (orgId, clipId) => `/api/v1/orgs/${orgId}/clip-registry/${clipId}/connections`,
|
|
51692
51692
|
CLIP_CONNECTION: (orgId, connId) => `/api/v1/orgs/${orgId}/clip-connections/${connId}`,
|
|
51693
|
-
// Clip registry (v3, org-scoped, served by api-server — `crg_` entries
|
|
51694
|
-
// Pinix Hub catalog proxy above is a different, id-less surface)
|
|
51693
|
+
// Clip registry (v3, org-scoped, served by api-server — `crg_` entries)
|
|
51695
51694
|
ORG_CLIP_REGISTRY: (orgId) => `/api/v1/orgs/${orgId}/clip-registry`,
|
|
51695
|
+
ORG_CLIP_REGISTRY_CLIP: (orgId, clipId) => `/api/v1/orgs/${orgId}/clip-registry/${clipId}`,
|
|
51696
|
+
ORG_CLIP_REGISTRY_PUBLISH: (orgId) => `/api/v1/orgs/${orgId}/clip-registry/publish`,
|
|
51696
51697
|
ORG_CLIP_INSTALL: (orgId) => `/api/v1/orgs/${orgId}/clips/install`,
|
|
51697
51698
|
ORG_CLIPS_INSTALLED: (orgId) => `/api/v1/orgs/${orgId}/clips/installed`,
|
|
51699
|
+
ORG_CLIP_UNINSTALL: (orgId, clipId) => `/api/v1/orgs/${orgId}/clips/${clipId}/uninstall`,
|
|
51700
|
+
// Per-org agent exec access for one clip (default all agents; PUT human-only)
|
|
51701
|
+
ORG_CLIP_EXEC_ACCESS: (orgId, clipId) => `/api/v1/orgs/${orgId}/clips/${clipId}/exec-access`,
|
|
51698
51702
|
// MCP clip server config (cap:clip-mcp; publisher-org only — cross-org gets
|
|
51699
51703
|
// 403 MCP_CROSS_ORG_DISABLED on the whole family, reads included)
|
|
51700
51704
|
ORG_CLIP_MCP_CONFIG: (orgId, clipId) => `/api/v1/orgs/${orgId}/clip-registry/${clipId}/mcp-config`,
|
|
51701
|
-
ORG_CLIP_MCP_TOOLS_REFRESH: (orgId, clipId) => `/api/v1/orgs/${orgId}/clip-registry/${clipId}/mcp-config/tools/refresh
|
|
51705
|
+
ORG_CLIP_MCP_TOOLS_REFRESH: (orgId, clipId) => `/api/v1/orgs/${orgId}/clip-registry/${clipId}/mcp-config/tools/refresh`,
|
|
51706
|
+
ORG_CLIP_MCP_OAUTH_DISCONNECT: (orgId, clipId) => `/api/v1/orgs/${orgId}/clip-registry/${clipId}/mcp-config/oauth/disconnect`
|
|
51702
51707
|
};
|
|
51703
51708
|
var WS_EVENTS = {
|
|
51704
51709
|
// Client -> Server
|
|
@@ -53194,6 +53199,14 @@ var ParallClient = class _ParallClient {
|
|
|
53194
53199
|
async setSlackStatus(orgId, input) {
|
|
53195
53200
|
await this.request("POST", ENDPOINTS.SLACK_STATUS(orgId), input);
|
|
53196
53201
|
}
|
|
53202
|
+
/**
|
|
53203
|
+
* WeChat tier-B read verb (agent-only; internal research preview): the
|
|
53204
|
+
* account's address book — friend wxids, saved group room ids, followed
|
|
53205
|
+
* official accounts. Same live gate as the send verb.
|
|
53206
|
+
*/
|
|
53207
|
+
async listWechatContacts(orgId) {
|
|
53208
|
+
return this.request("GET", ENDPOINTS.WECHAT_CONTACTS(orgId));
|
|
53209
|
+
}
|
|
53197
53210
|
async listChannelConversations(orgId, connectionId) {
|
|
53198
53211
|
return this.request("GET", ENDPOINTS.CHANNEL_CONNECTION_CONVERSATIONS(orgId, connectionId));
|
|
53199
53212
|
}
|
|
@@ -53732,17 +53745,11 @@ var ParallClient = class _ParallClient {
|
|
|
53732
53745
|
async revokeBrowserProfileConsent(orgId, profileId, clipId) {
|
|
53733
53746
|
await this.request("DELETE", ENDPOINTS.BROWSER_PROFILE_CONSENT(orgId, profileId, clipId));
|
|
53734
53747
|
}
|
|
53735
|
-
async listRegistryClips(q) {
|
|
53736
|
-
const url = ENDPOINTS.CLIP_REGISTRY() + (q ? `?q=${encodeURIComponent(q)}` : "");
|
|
53737
|
-
const resp = await this.request("GET", url);
|
|
53738
|
-
return resp.data;
|
|
53739
|
-
}
|
|
53740
53748
|
// ---- Clip registry (v3, api-server org registry — `crg_` entries) ----
|
|
53741
53749
|
/**
|
|
53742
53750
|
* List registry clips visible to the org: its own plus public+approved
|
|
53743
53751
|
* cross-org entries. This is the surface `installRegistryClip` and clip
|
|
53744
|
-
* connections operate on
|
|
53745
|
-
* ({@link listRegistryClips}), whose entries carry no `crg_` id.
|
|
53752
|
+
* connections operate on.
|
|
53746
53753
|
*/
|
|
53747
53754
|
async listOrgRegistryClips(orgId) {
|
|
53748
53755
|
const resp = await this.request("GET", `${ENDPOINTS.ORG_CLIP_REGISTRY(orgId)}?limit=100`);
|
|
@@ -53757,11 +53764,58 @@ var ParallClient = class _ParallClient {
|
|
|
53757
53764
|
async installRegistryClip(orgId, clipId) {
|
|
53758
53765
|
return this.request("POST", ENDPOINTS.ORG_CLIP_INSTALL(orgId), { clip_id: clipId });
|
|
53759
53766
|
}
|
|
53767
|
+
/**
|
|
53768
|
+
* Remove an org's install of a registry clip. Keyed by the REGISTRY id
|
|
53769
|
+
* (`crg_`), the same id {@link installRegistryClip} takes — the v2
|
|
53770
|
+
* `deleteClip` operates on a different table and cannot reach these.
|
|
53771
|
+
*/
|
|
53772
|
+
async uninstallRegistryClip(orgId, clipId) {
|
|
53773
|
+
await this.request("DELETE", ENDPOINTS.ORG_CLIP_UNINSTALL(orgId, clipId));
|
|
53774
|
+
}
|
|
53760
53775
|
/** List the org's installed registry clips (full entries). */
|
|
53761
53776
|
async listInstalledRegistryClips(orgId) {
|
|
53762
53777
|
const resp = await this.request("GET", ENDPOINTS.ORG_CLIPS_INSTALLED(orgId));
|
|
53763
53778
|
return resp ?? [];
|
|
53764
53779
|
}
|
|
53780
|
+
/**
|
|
53781
|
+
* Fetch one registry clip by its `crg_` id. For a clip OWNED by the calling
|
|
53782
|
+
* org the entry additionally carries `review_status`/`review_note` — the
|
|
53783
|
+
* state of the latest submitted version and the reviewer's rejection
|
|
53784
|
+
* feedback. This is the polling surface for "did platform review approve my
|
|
53785
|
+
* public publish yet"; cross-org callers see only public+approved entries
|
|
53786
|
+
* and never any review-state fields.
|
|
53787
|
+
*/
|
|
53788
|
+
async getRegistryClip(orgId, clipId) {
|
|
53789
|
+
return this.request("GET", ENDPOINTS.ORG_CLIP_REGISTRY_CLIP(orgId, clipId));
|
|
53790
|
+
}
|
|
53791
|
+
/**
|
|
53792
|
+
* Publish (create, or author-only update) a clip in the org registry,
|
|
53793
|
+
* replacing its whole file set. See {@link PublishRegistryClipRequest} for
|
|
53794
|
+
* the visibility/review semantics; the returned entry carries
|
|
53795
|
+
* `review_status` when a public publish queued a review submission — poll
|
|
53796
|
+
* {@link getRegistryClip} for the outcome.
|
|
53797
|
+
*/
|
|
53798
|
+
async publishRegistryClip(orgId, req) {
|
|
53799
|
+
return this.request("POST", ENDPOINTS.ORG_CLIP_REGISTRY_PUBLISH(orgId), req, void 0, false, {
|
|
53800
|
+
timeoutMs: 6e4
|
|
53801
|
+
});
|
|
53802
|
+
}
|
|
53803
|
+
/**
|
|
53804
|
+
* Read a clip's per-org agent exec access. Org-member readable (agents
|
|
53805
|
+
* included, so a denied agent can learn why exec answered
|
|
53806
|
+
* `CLIP_AGENT_NOT_ALLOWED`).
|
|
53807
|
+
*/
|
|
53808
|
+
async getClipAgentExecAccess(orgId, clipId) {
|
|
53809
|
+
return this.request("GET", ENDPOINTS.ORG_CLIP_EXEC_ACCESS(orgId, clipId));
|
|
53810
|
+
}
|
|
53811
|
+
/**
|
|
53812
|
+
* Replace a clip's per-org agent exec access. Human-only (agent principals
|
|
53813
|
+
* get 403); under `all_agents` the `agent_ids` must be empty. Every granted
|
|
53814
|
+
* id must be an active agent of this org (else `400 INVALID_INPUT`).
|
|
53815
|
+
*/
|
|
53816
|
+
async putClipAgentExecAccess(orgId, clipId, access) {
|
|
53817
|
+
return this.request("PUT", ENDPOINTS.ORG_CLIP_EXEC_ACCESS(orgId, clipId), access);
|
|
53818
|
+
}
|
|
53765
53819
|
// ---- Edge devices ----
|
|
53766
53820
|
async listEdgeDevices(orgId) {
|
|
53767
53821
|
return this.request("GET", ENDPOINTS.ORG_EDGE_DEVICES(orgId));
|
|
@@ -54511,10 +54565,16 @@ function buildSendMessageHint(event) {
|
|
|
54511
54565
|
const replyTo = event.channelExternalMessageId ? ` --reply-to "${event.channelExternalMessageId}"` : "";
|
|
54512
54566
|
return `
|
|
54513
54567
|
<system-reminder>To reply, use the platform verb: \`parall slack send${channelArg}${replyTo} --text <your reply>\`. In channels --reply-to is REQUIRED (the reply lands in that message's thread); in DMs it is optional (DMs are linear). \`parall slack send\` is the ONLY outbound path \u2014 your plain text output is NOT delivered to the external conversation.</system-reminder>`;
|
|
54568
|
+
}
|
|
54569
|
+
if (event.channelProvider === "wechat") {
|
|
54570
|
+
const toArg = event.channelExternalConversationId ? ` --to "${event.channelExternalConversationId}"` : " --to <wxid from this event>";
|
|
54571
|
+
const atArg = event.channelConversationType === "group" ? event.senderId && event.senderId !== "external" ? ` --at "${event.senderId}"` : " --at <wxid of the person you are answering>" : "";
|
|
54572
|
+
return `
|
|
54573
|
+
<system-reminder>To reply, use the platform verb: \`parall wechat send${toArg}${atArg} --text <your reply>\`. In group chats, --at @-mentions the person you are answering. \`parall wechat send\` is the ONLY outbound path \u2014 your plain text output is NOT delivered to the external conversation.</system-reminder>`;
|
|
54514
54574
|
}
|
|
54515
54575
|
if (!event.channelProvider) {
|
|
54516
54576
|
return `
|
|
54517
|
-
<system-reminder>To reply, use the channel capability granted in your system prompt \u2014 for Feishu conversations that is \`lark-cli im\`, for Slack it is \`parall slack send\` (pass the message id from this event as --reply-to)
|
|
54577
|
+
<system-reminder>To reply, use the channel capability granted in your system prompt \u2014 for Feishu conversations that is \`lark-cli im\`, for Slack it is \`parall slack send\` (pass the message id from this event as --reply-to), for WeChat it is \`parall wechat send\`. That capability is the ONLY outbound path \u2014 your plain text output is NOT delivered to the external conversation.</system-reminder>`;
|
|
54518
54578
|
}
|
|
54519
54579
|
const convRef = event.channelExternalConversationId ? `chat_id "${event.channelExternalConversationId}"` : "the conversation id named in this event";
|
|
54520
54580
|
const threadAlt = event.channelExternalMessageId ? ` To reply threaded to this specific message, reference message_id "${event.channelExternalMessageId}".` : "";
|
|
@@ -54993,13 +55053,33 @@ var LaneLedger = class {
|
|
|
54993
55053
|
};
|
|
54994
55054
|
|
|
54995
55055
|
// ts/agent-core/dist/gateway-lane-flow.js
|
|
55056
|
+
function shiftMainBufferGroup(host, groupKey, preserveInjectedFrameBoundary) {
|
|
55057
|
+
const events = [];
|
|
55058
|
+
while (host.dispatchState.mainBuffer[0] && host.dispatchGroupKey(host.dispatchState.mainBuffer[0]) === groupKey && (!preserveInjectedFrameBoundary || events.length === 0)) {
|
|
55059
|
+
events.push(host.dispatchState.mainBuffer.shift());
|
|
55060
|
+
}
|
|
55061
|
+
return events;
|
|
55062
|
+
}
|
|
55063
|
+
function hasUninjectedSameLaneEventAhead(host, event) {
|
|
55064
|
+
const eventIndex = host.dispatchState.mainBuffer.lastIndexOf(event);
|
|
55065
|
+
if (eventIndex <= 0)
|
|
55066
|
+
return false;
|
|
55067
|
+
const groupKey = host.dispatchGroupKey(event);
|
|
55068
|
+
return host.dispatchState.mainBuffer.slice(0, eventIndex).some((buffered) => host.dispatchGroupKey(buffered) === groupKey && !host.injectedMainBufferEvents.has(buffered));
|
|
55069
|
+
}
|
|
54996
55070
|
async function steerLaneMessage(host, event) {
|
|
54997
55071
|
const { laneLedger: ledger, opts } = host;
|
|
54998
55072
|
const adapter = opts.dispatchAdapter;
|
|
54999
55073
|
if (!ledger || !adapter.enqueueDuringDispatch)
|
|
55000
55074
|
return;
|
|
55075
|
+
if (hasUninjectedSameLaneEventAhead(host, event))
|
|
55076
|
+
return;
|
|
55001
55077
|
const folded = await ledger.steerLive(event);
|
|
55002
|
-
if (folded
|
|
55078
|
+
if (!folded)
|
|
55079
|
+
return;
|
|
55080
|
+
const injected = await adapter.enqueueDuringDispatch(opts.runtimeKey, buildEventBody(event), folded.inputLifecycle);
|
|
55081
|
+
if (injected) {
|
|
55082
|
+
host.injectedMainBufferEvents.add(event);
|
|
55003
55083
|
opts.log?.info(`steer folded+injected for ${event.messageId} (will drain for bookkeeping)`);
|
|
55004
55084
|
}
|
|
55005
55085
|
}
|
|
@@ -55615,6 +55695,22 @@ All three forms work \u2014 pick whichever fits:
|
|
|
55615
55695
|
Bare URIs and empty-context refs are preferred in most cases \u2014 the platform
|
|
55616
55696
|
resolves and renders the entity title automatically.
|
|
55617
55697
|
|
|
55698
|
+
### Mentioning people and agents
|
|
55699
|
+
|
|
55700
|
+
A real member mention is a \`prll://usr_...\` reference. Plain \`@Display Name\` is
|
|
55701
|
+
only text: it does not notify a human or trigger an agent.
|
|
55702
|
+
|
|
55703
|
+
When another member must be notified or an agent explicitly triggered, include
|
|
55704
|
+
their user reference in the message body. Prefer the empty-context form because
|
|
55705
|
+
the platform resolves the member's current display name:
|
|
55706
|
+
|
|
55707
|
+
[](prll://usr_xxx)
|
|
55708
|
+
|
|
55709
|
+
Use \`[Display Name](prll://usr_xxx)\` when the surrounding sentence needs an
|
|
55710
|
+
explicit label. Find the user ID in the incoming message or with
|
|
55711
|
+
\`parall members list\`. Never substitute plain \`@Display Name\` when notification
|
|
55712
|
+
or agent dispatch matters.
|
|
55713
|
+
|
|
55618
55714
|
### URI format
|
|
55619
55715
|
|
|
55620
55716
|
\`prll://\` follows standard URI structure: \`scheme://authority/path?query#fragment\`.
|
|
@@ -55919,9 +56015,12 @@ import * as path2 from "node:path";
|
|
|
55919
56015
|
import { fileURLToPath } from "node:url";
|
|
55920
56016
|
var CAPABILITY_FEISHU_CLI = "feishu-cli";
|
|
55921
56017
|
var CAPABILITY_SLACK_SEND = "slack-send";
|
|
56018
|
+
var CAPABILITY_WECHAT_SEND = "wechat-send";
|
|
55922
56019
|
function channelCapabilityKeyFor(provider) {
|
|
55923
56020
|
if (provider === "slack")
|
|
55924
56021
|
return CAPABILITY_SLACK_SEND;
|
|
56022
|
+
if (provider === "wechat")
|
|
56023
|
+
return CAPABILITY_WECHAT_SEND;
|
|
55925
56024
|
return `${provider}-cli`;
|
|
55926
56025
|
}
|
|
55927
56026
|
var CHANNEL_POINTER_MAGIC = "parall channel capability pointer";
|
|
@@ -57104,6 +57203,7 @@ var ParallAgentGateway = class {
|
|
|
57104
57203
|
// (stable mapping; avoids one connection fetch per inbound message).
|
|
57105
57204
|
channelConnectionProviders = /* @__PURE__ */ new Map();
|
|
57106
57205
|
dispatchedMessages = /* @__PURE__ */ new Set();
|
|
57206
|
+
injectedMainBufferEvents = /* @__PURE__ */ new WeakSet();
|
|
57107
57207
|
// Per-WorkItem failure backoff for typed dispatch consumption — see
|
|
57108
57208
|
// LaneFlowHost.typedRedriveBackoff in gateway-lane-flow.ts.
|
|
57109
57209
|
typedRedriveBackoff = /* @__PURE__ */ new Map();
|
|
@@ -58316,13 +58416,10 @@ var ParallAgentGateway = class {
|
|
|
58316
58416
|
break;
|
|
58317
58417
|
}
|
|
58318
58418
|
const groupKey = this.dispatchGroupKey(this.dispatchState.mainBuffer[0]);
|
|
58319
|
-
const
|
|
58320
|
-
|
|
58321
|
-
events.push(this.dispatchState.mainBuffer.shift());
|
|
58322
|
-
}
|
|
58419
|
+
const hasPendingInjections = this.opts.dispatchAdapter.hasPendingInjections?.(this.opts.runtimeKey) ?? false;
|
|
58420
|
+
const events = shiftMainBufferGroup(this.laneFlowHost(), groupKey, hasPendingInjections && this.opts.dispatchAdapter.inputLifecycleMode === "explicit");
|
|
58323
58421
|
const event = events[events.length - 1];
|
|
58324
58422
|
const earlier = events.slice(0, -1);
|
|
58325
|
-
const hasPendingInjections = this.opts.dispatchAdapter.hasPendingInjections?.(this.opts.runtimeKey) ?? false;
|
|
58326
58423
|
const pendingFork = hasPendingInjections ? [] : this.dispatchState.pendingForkResults.splice(0);
|
|
58327
58424
|
const forkPrefix = buildForkResultPrefix(pendingFork);
|
|
58328
58425
|
this.dispatchState.mainCurrentTargetId = event.targetId;
|
|
@@ -59035,7 +59132,7 @@ var ParallAgentGateway = class {
|
|
|
59035
59132
|
}
|
|
59036
59133
|
}
|
|
59037
59134
|
const keys = this.opts.getCapabilityKeys?.() ?? [];
|
|
59038
|
-
const cliCapable = provider ? keys.includes(channelCapabilityKeyFor(provider)) : keys.some((k) => k.endsWith("-cli") || k === CAPABILITY_SLACK_SEND);
|
|
59135
|
+
const cliCapable = provider ? keys.includes(channelCapabilityKeyFor(provider)) : keys.some((k) => k.endsWith("-cli") || k === CAPABILITY_SLACK_SEND || k === CAPABILITY_WECHAT_SEND);
|
|
59039
59136
|
const event = {
|
|
59040
59137
|
type: "channel_message",
|
|
59041
59138
|
targetId: conv.id,
|
|
@@ -60361,41 +60458,55 @@ CLI command results are JSON on stdout; mutation commands may emit auxiliary hin
|
|
|
60361
60458
|
var PARALL_CLIPS_SKILL = `# Parall Clips
|
|
60362
60459
|
|
|
60363
60460
|
Clips are packaged capabilities that let agents operate external systems \u2014
|
|
60364
|
-
APIs
|
|
60461
|
+
APIs, websites, remote tools \u2014 through named commands installed in the org.
|
|
60365
60462
|
|
|
60366
60463
|
## Discover
|
|
60367
60464
|
|
|
60368
60465
|
\`\`\`bash
|
|
60369
|
-
parall clip list
|
|
60370
|
-
parall clip info <
|
|
60466
|
+
parall clip list # installed clips + each clip's connections
|
|
60467
|
+
parall clip info <clip> # commands + per-command params (manifest)
|
|
60468
|
+
parall clip connections <clip> # one clip's connections, full rows
|
|
60469
|
+
parall clip tools <clip> # MCP clips only: live tool schemas
|
|
60371
60470
|
\`\`\`
|
|
60372
60471
|
|
|
60373
|
-
|
|
60374
|
-
|
|
60375
|
-
|
|
60376
|
-
parall clip invoke <alias> <command> [input] [--timeout <ms>] # timeout default 30s
|
|
60377
|
-
# input: JSON string or plain text, per the command's params in \`info\`
|
|
60378
|
-
parall clip invoke github-tools list-repos '{"org":"acme"}'
|
|
60379
|
-
\`\`\`
|
|
60472
|
+
\`clip list\` answers both discovery questions at once: WHICH clip (name,
|
|
60473
|
+
description, version) and WHERE it can run \u2014 every connection with its
|
|
60474
|
+
\`ccn_\u2026\` id, alias, and target kind:
|
|
60380
60475
|
|
|
60381
|
-
|
|
60476
|
+
- \`cloud\` \u2014 an org-shared cloud profile (a maintainer's signed-in browser)
|
|
60477
|
+
- \`desktop\` \u2014 a member's own device (only its owner can exec through it)
|
|
60478
|
+
- \`mcp\` \u2014 a remote MCP tool server
|
|
60479
|
+
- \`device\` \u2014 a device whose placement could not be resolved just now (the
|
|
60480
|
+
device list was unavailable); don't guess which kind it is \u2014 re-run
|
|
60481
|
+
discovery, and treat a persistent \`device\` like an unverified target
|
|
60482
|
+
- \`orphaned\` \u2014 the target device is gone; the connection is unusable
|
|
60382
60483
|
|
|
60383
|
-
|
|
60484
|
+
Pick the connection whose alias names the account/device the task needs
|
|
60485
|
+
(e.g. \`ins-nyc\` vs \`ins-boston\`). A row without an alias can only be
|
|
60486
|
+
referenced by \`ccn_\` id \u2014 when aliases are missing and several connections
|
|
60487
|
+
could match, ask a human to name them in the Clip Console rather than
|
|
60488
|
+
guessing which signed-in account you are about to act through.
|
|
60384
60489
|
|
|
60385
|
-
|
|
60386
|
-
profile. **Name the target explicitly.** A cloud profile has NO implicit
|
|
60387
|
-
route; omitting the target entirely is a desktop-only legacy form that
|
|
60388
|
-
reaches just YOUR OWN online desktop device \u2014 never a shared cloud profile.
|
|
60490
|
+
## Execute
|
|
60389
60491
|
|
|
60390
60492
|
\`\`\`bash
|
|
60391
|
-
parall clip exec <clip> <command> [args] --connection <
|
|
60493
|
+
parall clip exec <clip> <command> [args] --connection <ccn_|alias> # the normal form
|
|
60392
60494
|
parall clip exec browser-tools screenshot '{"url":"\u2026"}' --connection cloud-main
|
|
60393
60495
|
\`\`\`
|
|
60394
60496
|
|
|
60497
|
+
Build \`args\` as JSON per the command's params from \`clip info\` (or the
|
|
60498
|
+
tool's \`inputSchema\` from \`clip tools\` for MCP clips \u2014 tool names are NOT
|
|
60499
|
+
frozen in the manifest, so never guess a tool name or its argument shape).
|
|
60500
|
+
Results are JSON on stdout; failures print a typed error.
|
|
60501
|
+
|
|
60502
|
+
**Name the target explicitly.** A cloud profile has NO implicit route;
|
|
60503
|
+
omitting the target entirely is a desktop-only legacy form that reaches just
|
|
60504
|
+
YOUR OWN online desktop device \u2014 never a shared cloud profile.
|
|
60505
|
+
|
|
60395
60506
|
- A cloud (hosted) profile is reachable ONLY via \`--connection\` \u2014 the clip
|
|
60396
|
-
connection its maintainer bound
|
|
60397
|
-
|
|
60398
|
-
|
|
60507
|
+
connection its maintainer bound. That binding IS your authorization;
|
|
60508
|
+
without one the server answers \`HOSTED_CONNECTION_REQUIRED\` and the fix
|
|
60509
|
+
is to ask an owner/admin to bind the clip, never to retry.
|
|
60399
60510
|
- \`--edge <edgeId>\` targets only a desktop device YOU own.
|
|
60400
60511
|
- Waiting on a cloud profile is handled by the CLI: \`EDGE_ACTIVATING\` (cold
|
|
60401
60512
|
start), \`EDGE_BUSY\` (another exec is running) and
|
|
@@ -60407,19 +60518,10 @@ parall clip exec browser-tools screenshot '{"url":"\u2026"}' --connection cloud-
|
|
|
60407
60518
|
|
|
60408
60519
|
## MCP clips (remote tool servers)
|
|
60409
60520
|
|
|
60410
|
-
|
|
60411
|
-
|
|
60412
|
-
|
|
60413
|
-
|
|
60414
|
-
find the connection AND the tool schemas:
|
|
60415
|
-
|
|
60416
|
-
\`\`\`bash
|
|
60417
|
-
parall clip connections <alias> # the ccn_ id / alias to pass to --connection
|
|
60418
|
-
parall clip tools <alias> # tool names + descriptions + inputSchema (JSON)
|
|
60419
|
-
\`\`\`
|
|
60420
|
-
|
|
60421
|
-
Read each tool's \`inputSchema\` from \`clip tools\` to build valid args, then
|
|
60422
|
-
exec against that explicit target \u2014 same form as an Edge clip:
|
|
60521
|
+
A connection with target \`mcp\` routes to a remote MCP server; the command
|
|
60522
|
+
is an MCP tool name and the args are that tool's JSON arguments. Read each
|
|
60523
|
+
tool's \`inputSchema\` from \`clip tools\` first, then exec against the
|
|
60524
|
+
explicit target \u2014 the same form as any other clip:
|
|
60423
60525
|
|
|
60424
60526
|
\`\`\`bash
|
|
60425
60527
|
parall clip exec <clip> <tool> [json-args] --connection <ccn_|alias>
|
|
@@ -60437,13 +60539,11 @@ parall clip exec <clip> <tool> [json-args] --connection <ccn_|alias>
|
|
|
60437
60539
|
|
|
60438
60540
|
## Behavior rules
|
|
60439
60541
|
|
|
60440
|
-
- An authorization error (
|
|
60441
|
-
clip's
|
|
60442
|
-
|
|
60542
|
+
- An authorization error (\`HOSTED_CONNECTION_REQUIRED\`, \`FORBIDDEN\`) is a
|
|
60543
|
+
fail-fast: ask the clip's maintainer or an org admin to bind the clip or
|
|
60544
|
+
grant the connection \u2014 do not retry or work around it.
|
|
60545
|
+
- If the target device is offline or the call times out, report that
|
|
60443
60546
|
plainly; do not queue, and never fabricate a result for a run that errored.
|
|
60444
|
-
- Hosted browser activation is handled by the CLI: it waits (bounded) while a
|
|
60445
|
-
cold hosted browser starts, so if the invoke still fails, report the error \u2014
|
|
60446
|
-
do not blind-retry in a loop.
|
|
60447
60547
|
- **\`OUTCOME_UNKNOWN\` is never retryable.** It means the command was
|
|
60448
60548
|
dispatched and MAY HAVE EXECUTED even though no result came back. Retrying
|
|
60449
60549
|
could post, order or delete twice. Verify the effect through the system you
|
|
@@ -60459,6 +60559,8 @@ parall clip exec <clip> <tool> [json-args] --connection <ccn_|alias>
|
|
|
60459
60559
|
- A clip may act through a person's real logged-in account \u2014 outward,
|
|
60460
60560
|
irreversible, or spending actions (post, order, delete, pay) get the same
|
|
60461
60561
|
caution as any shared-state change: confirm when intent isn't explicit.
|
|
60562
|
+
The connection's alias/target tells you WHICH account you are acting as \u2014
|
|
60563
|
+
if that is ambiguous, resolve it with a human before acting, not after.
|
|
60462
60564
|
- Reach for \`parall clip list\` whenever a task needs capabilities beyond
|
|
60463
60565
|
built-in tools.
|
|
60464
60566
|
`;
|
|
@@ -60492,7 +60594,7 @@ var SKILLS = [
|
|
|
60492
60594
|
},
|
|
60493
60595
|
{
|
|
60494
60596
|
name: "parall-clips",
|
|
60495
|
-
description: "Parall clip operations: list installed clips,
|
|
60597
|
+
description: "Parall clip operations: list installed clips and their connections, inspect clip commands/tools, execute clip commands on an explicit connection. Use when: the task requires external capabilities (GitHub, web search, etc.), user asks about available tools/clips, or you need to call a clip command.",
|
|
60496
60598
|
content: PARALL_CLIPS_SKILL
|
|
60497
60599
|
}
|
|
60498
60600
|
];
|
|
@@ -61173,6 +61275,15 @@ var ClaudeInputRegistry = class {
|
|
|
61173
61275
|
getByCommand(commandUuid) {
|
|
61174
61276
|
return this.byCommand.get(commandUuid);
|
|
61175
61277
|
}
|
|
61278
|
+
findOverlapping(dispatchEventIds) {
|
|
61279
|
+
const ids = new Set(dispatchEventIds);
|
|
61280
|
+
for (const delivery of this.byKey.values()) {
|
|
61281
|
+
if (delivery.lifecycle?.dispatchEventIds.some((id) => ids.has(id))) {
|
|
61282
|
+
return delivery;
|
|
61283
|
+
}
|
|
61284
|
+
}
|
|
61285
|
+
return void 0;
|
|
61286
|
+
}
|
|
61176
61287
|
values() {
|
|
61177
61288
|
return this.byKey.values();
|
|
61178
61289
|
}
|
|
@@ -61799,6 +61910,12 @@ var ClaudeCodeAdapter = class {
|
|
|
61799
61910
|
return;
|
|
61800
61911
|
}
|
|
61801
61912
|
}
|
|
61913
|
+
if (existingState && inputLifecycle) {
|
|
61914
|
+
const overlap = existingState.inputs.findOverlapping(inputLifecycle.dispatchEventIds);
|
|
61915
|
+
if (overlap) {
|
|
61916
|
+
throw new Error(`buffered Claude delivery ${deliveryKey} overlaps active input ${overlap.deliveryKey}; refusing duplicate stdin write`);
|
|
61917
|
+
}
|
|
61918
|
+
}
|
|
61802
61919
|
let promptBody = bodyForAgent;
|
|
61803
61920
|
let releasePreparedAttachments = () => {
|
|
61804
61921
|
};
|
|
@@ -51511,6 +51511,8 @@ var ENDPOINTS = {
|
|
|
51511
51511
|
SLACK_HISTORY: (orgId) => `${API_BASE}/orgs/${orgId}/agents/me/slack/history`,
|
|
51512
51512
|
SLACK_MEMBERS: (orgId) => `${API_BASE}/orgs/${orgId}/agents/me/slack/members`,
|
|
51513
51513
|
SLACK_STATUS: (orgId) => `${API_BASE}/orgs/${orgId}/agents/me/slack/status`,
|
|
51514
|
+
// WeChat tier-B read verb (agent-only; internal research preview).
|
|
51515
|
+
WECHAT_CONTACTS: (orgId) => `${API_BASE}/orgs/${orgId}/agents/me/wechat/contacts`,
|
|
51514
51516
|
// Invitations (org-scoped, admin)
|
|
51515
51517
|
ORG_INVITATIONS: (orgId) => `${API_BASE}/orgs/${orgId}/invitations`,
|
|
51516
51518
|
ORG_INVITATION: (orgId, invId) => `${API_BASE}/orgs/${orgId}/invitations/${invId}`,
|
|
@@ -51672,8 +51674,6 @@ var ENDPOINTS = {
|
|
|
51672
51674
|
// Live viewer command — on api-server (API_BASE), not clip-service: it rides
|
|
51673
51675
|
// the machine control-plane request/reply bridge that lives in api-server.
|
|
51674
51676
|
BROWSER_PROFILE_VIEWER_COMMAND: (orgId, profileId) => `${API_BASE}/orgs/${orgId}/browser-profiles/${profileId}/viewer/command`,
|
|
51675
|
-
// Clip registry (global, served by clip-service → Pinix Hub proxy)
|
|
51676
|
-
CLIP_REGISTRY: () => `${CLIP_BASE}/registry/clips`,
|
|
51677
51677
|
// Edge device endpoints
|
|
51678
51678
|
ORG_EDGE: (orgId) => `/api/v1/orgs/${orgId}/edge`,
|
|
51679
51679
|
ORG_EDGE_DEVICES: (orgId) => `/api/v1/orgs/${orgId}/edge/devices`,
|
|
@@ -51690,15 +51690,20 @@ var ENDPOINTS = {
|
|
|
51690
51690
|
ORG_EDGE_VIEWER_COMMAND: (orgId, edgeId) => `/api/v1/orgs/${orgId}/edge/${edgeId}/viewer/command`,
|
|
51691
51691
|
CLIP_CONNECTIONS: (orgId, clipId) => `/api/v1/orgs/${orgId}/clip-registry/${clipId}/connections`,
|
|
51692
51692
|
CLIP_CONNECTION: (orgId, connId) => `/api/v1/orgs/${orgId}/clip-connections/${connId}`,
|
|
51693
|
-
// Clip registry (v3, org-scoped, served by api-server — `crg_` entries
|
|
51694
|
-
// Pinix Hub catalog proxy above is a different, id-less surface)
|
|
51693
|
+
// Clip registry (v3, org-scoped, served by api-server — `crg_` entries)
|
|
51695
51694
|
ORG_CLIP_REGISTRY: (orgId) => `/api/v1/orgs/${orgId}/clip-registry`,
|
|
51695
|
+
ORG_CLIP_REGISTRY_CLIP: (orgId, clipId) => `/api/v1/orgs/${orgId}/clip-registry/${clipId}`,
|
|
51696
|
+
ORG_CLIP_REGISTRY_PUBLISH: (orgId) => `/api/v1/orgs/${orgId}/clip-registry/publish`,
|
|
51696
51697
|
ORG_CLIP_INSTALL: (orgId) => `/api/v1/orgs/${orgId}/clips/install`,
|
|
51697
51698
|
ORG_CLIPS_INSTALLED: (orgId) => `/api/v1/orgs/${orgId}/clips/installed`,
|
|
51699
|
+
ORG_CLIP_UNINSTALL: (orgId, clipId) => `/api/v1/orgs/${orgId}/clips/${clipId}/uninstall`,
|
|
51700
|
+
// Per-org agent exec access for one clip (default all agents; PUT human-only)
|
|
51701
|
+
ORG_CLIP_EXEC_ACCESS: (orgId, clipId) => `/api/v1/orgs/${orgId}/clips/${clipId}/exec-access`,
|
|
51698
51702
|
// MCP clip server config (cap:clip-mcp; publisher-org only — cross-org gets
|
|
51699
51703
|
// 403 MCP_CROSS_ORG_DISABLED on the whole family, reads included)
|
|
51700
51704
|
ORG_CLIP_MCP_CONFIG: (orgId, clipId) => `/api/v1/orgs/${orgId}/clip-registry/${clipId}/mcp-config`,
|
|
51701
|
-
ORG_CLIP_MCP_TOOLS_REFRESH: (orgId, clipId) => `/api/v1/orgs/${orgId}/clip-registry/${clipId}/mcp-config/tools/refresh
|
|
51705
|
+
ORG_CLIP_MCP_TOOLS_REFRESH: (orgId, clipId) => `/api/v1/orgs/${orgId}/clip-registry/${clipId}/mcp-config/tools/refresh`,
|
|
51706
|
+
ORG_CLIP_MCP_OAUTH_DISCONNECT: (orgId, clipId) => `/api/v1/orgs/${orgId}/clip-registry/${clipId}/mcp-config/oauth/disconnect`
|
|
51702
51707
|
};
|
|
51703
51708
|
var WS_EVENTS = {
|
|
51704
51709
|
// Client -> Server
|
|
@@ -53194,6 +53199,14 @@ var ParallClient = class _ParallClient {
|
|
|
53194
53199
|
async setSlackStatus(orgId, input) {
|
|
53195
53200
|
await this.request("POST", ENDPOINTS.SLACK_STATUS(orgId), input);
|
|
53196
53201
|
}
|
|
53202
|
+
/**
|
|
53203
|
+
* WeChat tier-B read verb (agent-only; internal research preview): the
|
|
53204
|
+
* account's address book — friend wxids, saved group room ids, followed
|
|
53205
|
+
* official accounts. Same live gate as the send verb.
|
|
53206
|
+
*/
|
|
53207
|
+
async listWechatContacts(orgId) {
|
|
53208
|
+
return this.request("GET", ENDPOINTS.WECHAT_CONTACTS(orgId));
|
|
53209
|
+
}
|
|
53197
53210
|
async listChannelConversations(orgId, connectionId) {
|
|
53198
53211
|
return this.request("GET", ENDPOINTS.CHANNEL_CONNECTION_CONVERSATIONS(orgId, connectionId));
|
|
53199
53212
|
}
|
|
@@ -53732,17 +53745,11 @@ var ParallClient = class _ParallClient {
|
|
|
53732
53745
|
async revokeBrowserProfileConsent(orgId, profileId, clipId) {
|
|
53733
53746
|
await this.request("DELETE", ENDPOINTS.BROWSER_PROFILE_CONSENT(orgId, profileId, clipId));
|
|
53734
53747
|
}
|
|
53735
|
-
async listRegistryClips(q) {
|
|
53736
|
-
const url = ENDPOINTS.CLIP_REGISTRY() + (q ? `?q=${encodeURIComponent(q)}` : "");
|
|
53737
|
-
const resp = await this.request("GET", url);
|
|
53738
|
-
return resp.data;
|
|
53739
|
-
}
|
|
53740
53748
|
// ---- Clip registry (v3, api-server org registry — `crg_` entries) ----
|
|
53741
53749
|
/**
|
|
53742
53750
|
* List registry clips visible to the org: its own plus public+approved
|
|
53743
53751
|
* cross-org entries. This is the surface `installRegistryClip` and clip
|
|
53744
|
-
* connections operate on
|
|
53745
|
-
* ({@link listRegistryClips}), whose entries carry no `crg_` id.
|
|
53752
|
+
* connections operate on.
|
|
53746
53753
|
*/
|
|
53747
53754
|
async listOrgRegistryClips(orgId) {
|
|
53748
53755
|
const resp = await this.request("GET", `${ENDPOINTS.ORG_CLIP_REGISTRY(orgId)}?limit=100`);
|
|
@@ -53757,11 +53764,58 @@ var ParallClient = class _ParallClient {
|
|
|
53757
53764
|
async installRegistryClip(orgId, clipId) {
|
|
53758
53765
|
return this.request("POST", ENDPOINTS.ORG_CLIP_INSTALL(orgId), { clip_id: clipId });
|
|
53759
53766
|
}
|
|
53767
|
+
/**
|
|
53768
|
+
* Remove an org's install of a registry clip. Keyed by the REGISTRY id
|
|
53769
|
+
* (`crg_`), the same id {@link installRegistryClip} takes — the v2
|
|
53770
|
+
* `deleteClip` operates on a different table and cannot reach these.
|
|
53771
|
+
*/
|
|
53772
|
+
async uninstallRegistryClip(orgId, clipId) {
|
|
53773
|
+
await this.request("DELETE", ENDPOINTS.ORG_CLIP_UNINSTALL(orgId, clipId));
|
|
53774
|
+
}
|
|
53760
53775
|
/** List the org's installed registry clips (full entries). */
|
|
53761
53776
|
async listInstalledRegistryClips(orgId) {
|
|
53762
53777
|
const resp = await this.request("GET", ENDPOINTS.ORG_CLIPS_INSTALLED(orgId));
|
|
53763
53778
|
return resp ?? [];
|
|
53764
53779
|
}
|
|
53780
|
+
/**
|
|
53781
|
+
* Fetch one registry clip by its `crg_` id. For a clip OWNED by the calling
|
|
53782
|
+
* org the entry additionally carries `review_status`/`review_note` — the
|
|
53783
|
+
* state of the latest submitted version and the reviewer's rejection
|
|
53784
|
+
* feedback. This is the polling surface for "did platform review approve my
|
|
53785
|
+
* public publish yet"; cross-org callers see only public+approved entries
|
|
53786
|
+
* and never any review-state fields.
|
|
53787
|
+
*/
|
|
53788
|
+
async getRegistryClip(orgId, clipId) {
|
|
53789
|
+
return this.request("GET", ENDPOINTS.ORG_CLIP_REGISTRY_CLIP(orgId, clipId));
|
|
53790
|
+
}
|
|
53791
|
+
/**
|
|
53792
|
+
* Publish (create, or author-only update) a clip in the org registry,
|
|
53793
|
+
* replacing its whole file set. See {@link PublishRegistryClipRequest} for
|
|
53794
|
+
* the visibility/review semantics; the returned entry carries
|
|
53795
|
+
* `review_status` when a public publish queued a review submission — poll
|
|
53796
|
+
* {@link getRegistryClip} for the outcome.
|
|
53797
|
+
*/
|
|
53798
|
+
async publishRegistryClip(orgId, req) {
|
|
53799
|
+
return this.request("POST", ENDPOINTS.ORG_CLIP_REGISTRY_PUBLISH(orgId), req, void 0, false, {
|
|
53800
|
+
timeoutMs: 6e4
|
|
53801
|
+
});
|
|
53802
|
+
}
|
|
53803
|
+
/**
|
|
53804
|
+
* Read a clip's per-org agent exec access. Org-member readable (agents
|
|
53805
|
+
* included, so a denied agent can learn why exec answered
|
|
53806
|
+
* `CLIP_AGENT_NOT_ALLOWED`).
|
|
53807
|
+
*/
|
|
53808
|
+
async getClipAgentExecAccess(orgId, clipId) {
|
|
53809
|
+
return this.request("GET", ENDPOINTS.ORG_CLIP_EXEC_ACCESS(orgId, clipId));
|
|
53810
|
+
}
|
|
53811
|
+
/**
|
|
53812
|
+
* Replace a clip's per-org agent exec access. Human-only (agent principals
|
|
53813
|
+
* get 403); under `all_agents` the `agent_ids` must be empty. Every granted
|
|
53814
|
+
* id must be an active agent of this org (else `400 INVALID_INPUT`).
|
|
53815
|
+
*/
|
|
53816
|
+
async putClipAgentExecAccess(orgId, clipId, access) {
|
|
53817
|
+
return this.request("PUT", ENDPOINTS.ORG_CLIP_EXEC_ACCESS(orgId, clipId), access);
|
|
53818
|
+
}
|
|
53765
53819
|
// ---- Edge devices ----
|
|
53766
53820
|
async listEdgeDevices(orgId) {
|
|
53767
53821
|
return this.request("GET", ENDPOINTS.ORG_EDGE_DEVICES(orgId));
|
|
@@ -54511,10 +54565,16 @@ function buildSendMessageHint(event) {
|
|
|
54511
54565
|
const replyTo = event.channelExternalMessageId ? ` --reply-to "${event.channelExternalMessageId}"` : "";
|
|
54512
54566
|
return `
|
|
54513
54567
|
<system-reminder>To reply, use the platform verb: \`parall slack send${channelArg}${replyTo} --text <your reply>\`. In channels --reply-to is REQUIRED (the reply lands in that message's thread); in DMs it is optional (DMs are linear). \`parall slack send\` is the ONLY outbound path \u2014 your plain text output is NOT delivered to the external conversation.</system-reminder>`;
|
|
54568
|
+
}
|
|
54569
|
+
if (event.channelProvider === "wechat") {
|
|
54570
|
+
const toArg = event.channelExternalConversationId ? ` --to "${event.channelExternalConversationId}"` : " --to <wxid from this event>";
|
|
54571
|
+
const atArg = event.channelConversationType === "group" ? event.senderId && event.senderId !== "external" ? ` --at "${event.senderId}"` : " --at <wxid of the person you are answering>" : "";
|
|
54572
|
+
return `
|
|
54573
|
+
<system-reminder>To reply, use the platform verb: \`parall wechat send${toArg}${atArg} --text <your reply>\`. In group chats, --at @-mentions the person you are answering. \`parall wechat send\` is the ONLY outbound path \u2014 your plain text output is NOT delivered to the external conversation.</system-reminder>`;
|
|
54514
54574
|
}
|
|
54515
54575
|
if (!event.channelProvider) {
|
|
54516
54576
|
return `
|
|
54517
|
-
<system-reminder>To reply, use the channel capability granted in your system prompt \u2014 for Feishu conversations that is \`lark-cli im\`, for Slack it is \`parall slack send\` (pass the message id from this event as --reply-to)
|
|
54577
|
+
<system-reminder>To reply, use the channel capability granted in your system prompt \u2014 for Feishu conversations that is \`lark-cli im\`, for Slack it is \`parall slack send\` (pass the message id from this event as --reply-to), for WeChat it is \`parall wechat send\`. That capability is the ONLY outbound path \u2014 your plain text output is NOT delivered to the external conversation.</system-reminder>`;
|
|
54518
54578
|
}
|
|
54519
54579
|
const convRef = event.channelExternalConversationId ? `chat_id "${event.channelExternalConversationId}"` : "the conversation id named in this event";
|
|
54520
54580
|
const threadAlt = event.channelExternalMessageId ? ` To reply threaded to this specific message, reference message_id "${event.channelExternalMessageId}".` : "";
|
|
@@ -54993,13 +55053,33 @@ var LaneLedger = class {
|
|
|
54993
55053
|
};
|
|
54994
55054
|
|
|
54995
55055
|
// ts/agent-core/dist/gateway-lane-flow.js
|
|
55056
|
+
function shiftMainBufferGroup(host, groupKey, preserveInjectedFrameBoundary) {
|
|
55057
|
+
const events = [];
|
|
55058
|
+
while (host.dispatchState.mainBuffer[0] && host.dispatchGroupKey(host.dispatchState.mainBuffer[0]) === groupKey && (!preserveInjectedFrameBoundary || events.length === 0)) {
|
|
55059
|
+
events.push(host.dispatchState.mainBuffer.shift());
|
|
55060
|
+
}
|
|
55061
|
+
return events;
|
|
55062
|
+
}
|
|
55063
|
+
function hasUninjectedSameLaneEventAhead(host, event) {
|
|
55064
|
+
const eventIndex = host.dispatchState.mainBuffer.lastIndexOf(event);
|
|
55065
|
+
if (eventIndex <= 0)
|
|
55066
|
+
return false;
|
|
55067
|
+
const groupKey = host.dispatchGroupKey(event);
|
|
55068
|
+
return host.dispatchState.mainBuffer.slice(0, eventIndex).some((buffered) => host.dispatchGroupKey(buffered) === groupKey && !host.injectedMainBufferEvents.has(buffered));
|
|
55069
|
+
}
|
|
54996
55070
|
async function steerLaneMessage(host, event) {
|
|
54997
55071
|
const { laneLedger: ledger, opts } = host;
|
|
54998
55072
|
const adapter = opts.dispatchAdapter;
|
|
54999
55073
|
if (!ledger || !adapter.enqueueDuringDispatch)
|
|
55000
55074
|
return;
|
|
55075
|
+
if (hasUninjectedSameLaneEventAhead(host, event))
|
|
55076
|
+
return;
|
|
55001
55077
|
const folded = await ledger.steerLive(event);
|
|
55002
|
-
if (folded
|
|
55078
|
+
if (!folded)
|
|
55079
|
+
return;
|
|
55080
|
+
const injected = await adapter.enqueueDuringDispatch(opts.runtimeKey, buildEventBody(event), folded.inputLifecycle);
|
|
55081
|
+
if (injected) {
|
|
55082
|
+
host.injectedMainBufferEvents.add(event);
|
|
55003
55083
|
opts.log?.info(`steer folded+injected for ${event.messageId} (will drain for bookkeeping)`);
|
|
55004
55084
|
}
|
|
55005
55085
|
}
|
|
@@ -55615,6 +55695,22 @@ All three forms work \u2014 pick whichever fits:
|
|
|
55615
55695
|
Bare URIs and empty-context refs are preferred in most cases \u2014 the platform
|
|
55616
55696
|
resolves and renders the entity title automatically.
|
|
55617
55697
|
|
|
55698
|
+
### Mentioning people and agents
|
|
55699
|
+
|
|
55700
|
+
A real member mention is a \`prll://usr_...\` reference. Plain \`@Display Name\` is
|
|
55701
|
+
only text: it does not notify a human or trigger an agent.
|
|
55702
|
+
|
|
55703
|
+
When another member must be notified or an agent explicitly triggered, include
|
|
55704
|
+
their user reference in the message body. Prefer the empty-context form because
|
|
55705
|
+
the platform resolves the member's current display name:
|
|
55706
|
+
|
|
55707
|
+
[](prll://usr_xxx)
|
|
55708
|
+
|
|
55709
|
+
Use \`[Display Name](prll://usr_xxx)\` when the surrounding sentence needs an
|
|
55710
|
+
explicit label. Find the user ID in the incoming message or with
|
|
55711
|
+
\`parall members list\`. Never substitute plain \`@Display Name\` when notification
|
|
55712
|
+
or agent dispatch matters.
|
|
55713
|
+
|
|
55618
55714
|
### URI format
|
|
55619
55715
|
|
|
55620
55716
|
\`prll://\` follows standard URI structure: \`scheme://authority/path?query#fragment\`.
|
|
@@ -55919,9 +56015,12 @@ import * as path2 from "node:path";
|
|
|
55919
56015
|
import { fileURLToPath } from "node:url";
|
|
55920
56016
|
var CAPABILITY_FEISHU_CLI = "feishu-cli";
|
|
55921
56017
|
var CAPABILITY_SLACK_SEND = "slack-send";
|
|
56018
|
+
var CAPABILITY_WECHAT_SEND = "wechat-send";
|
|
55922
56019
|
function channelCapabilityKeyFor(provider) {
|
|
55923
56020
|
if (provider === "slack")
|
|
55924
56021
|
return CAPABILITY_SLACK_SEND;
|
|
56022
|
+
if (provider === "wechat")
|
|
56023
|
+
return CAPABILITY_WECHAT_SEND;
|
|
55925
56024
|
return `${provider}-cli`;
|
|
55926
56025
|
}
|
|
55927
56026
|
var CHANNEL_POINTER_MAGIC = "parall channel capability pointer";
|
|
@@ -57104,6 +57203,7 @@ var ParallAgentGateway = class {
|
|
|
57104
57203
|
// (stable mapping; avoids one connection fetch per inbound message).
|
|
57105
57204
|
channelConnectionProviders = /* @__PURE__ */ new Map();
|
|
57106
57205
|
dispatchedMessages = /* @__PURE__ */ new Set();
|
|
57206
|
+
injectedMainBufferEvents = /* @__PURE__ */ new WeakSet();
|
|
57107
57207
|
// Per-WorkItem failure backoff for typed dispatch consumption — see
|
|
57108
57208
|
// LaneFlowHost.typedRedriveBackoff in gateway-lane-flow.ts.
|
|
57109
57209
|
typedRedriveBackoff = /* @__PURE__ */ new Map();
|
|
@@ -58316,13 +58416,10 @@ var ParallAgentGateway = class {
|
|
|
58316
58416
|
break;
|
|
58317
58417
|
}
|
|
58318
58418
|
const groupKey = this.dispatchGroupKey(this.dispatchState.mainBuffer[0]);
|
|
58319
|
-
const
|
|
58320
|
-
|
|
58321
|
-
events.push(this.dispatchState.mainBuffer.shift());
|
|
58322
|
-
}
|
|
58419
|
+
const hasPendingInjections = this.opts.dispatchAdapter.hasPendingInjections?.(this.opts.runtimeKey) ?? false;
|
|
58420
|
+
const events = shiftMainBufferGroup(this.laneFlowHost(), groupKey, hasPendingInjections && this.opts.dispatchAdapter.inputLifecycleMode === "explicit");
|
|
58323
58421
|
const event = events[events.length - 1];
|
|
58324
58422
|
const earlier = events.slice(0, -1);
|
|
58325
|
-
const hasPendingInjections = this.opts.dispatchAdapter.hasPendingInjections?.(this.opts.runtimeKey) ?? false;
|
|
58326
58423
|
const pendingFork = hasPendingInjections ? [] : this.dispatchState.pendingForkResults.splice(0);
|
|
58327
58424
|
const forkPrefix = buildForkResultPrefix(pendingFork);
|
|
58328
58425
|
this.dispatchState.mainCurrentTargetId = event.targetId;
|
|
@@ -59035,7 +59132,7 @@ var ParallAgentGateway = class {
|
|
|
59035
59132
|
}
|
|
59036
59133
|
}
|
|
59037
59134
|
const keys = this.opts.getCapabilityKeys?.() ?? [];
|
|
59038
|
-
const cliCapable = provider ? keys.includes(channelCapabilityKeyFor(provider)) : keys.some((k) => k.endsWith("-cli") || k === CAPABILITY_SLACK_SEND);
|
|
59135
|
+
const cliCapable = provider ? keys.includes(channelCapabilityKeyFor(provider)) : keys.some((k) => k.endsWith("-cli") || k === CAPABILITY_SLACK_SEND || k === CAPABILITY_WECHAT_SEND);
|
|
59039
59136
|
const event = {
|
|
59040
59137
|
type: "channel_message",
|
|
59041
59138
|
targetId: conv.id,
|
|
@@ -60361,41 +60458,55 @@ CLI command results are JSON on stdout; mutation commands may emit auxiliary hin
|
|
|
60361
60458
|
var PARALL_CLIPS_SKILL = `# Parall Clips
|
|
60362
60459
|
|
|
60363
60460
|
Clips are packaged capabilities that let agents operate external systems \u2014
|
|
60364
|
-
APIs
|
|
60461
|
+
APIs, websites, remote tools \u2014 through named commands installed in the org.
|
|
60365
60462
|
|
|
60366
60463
|
## Discover
|
|
60367
60464
|
|
|
60368
60465
|
\`\`\`bash
|
|
60369
|
-
parall clip list
|
|
60370
|
-
parall clip info <
|
|
60466
|
+
parall clip list # installed clips + each clip's connections
|
|
60467
|
+
parall clip info <clip> # commands + per-command params (manifest)
|
|
60468
|
+
parall clip connections <clip> # one clip's connections, full rows
|
|
60469
|
+
parall clip tools <clip> # MCP clips only: live tool schemas
|
|
60371
60470
|
\`\`\`
|
|
60372
60471
|
|
|
60373
|
-
|
|
60374
|
-
|
|
60375
|
-
|
|
60376
|
-
parall clip invoke <alias> <command> [input] [--timeout <ms>] # timeout default 30s
|
|
60377
|
-
# input: JSON string or plain text, per the command's params in \`info\`
|
|
60378
|
-
parall clip invoke github-tools list-repos '{"org":"acme"}'
|
|
60379
|
-
\`\`\`
|
|
60472
|
+
\`clip list\` answers both discovery questions at once: WHICH clip (name,
|
|
60473
|
+
description, version) and WHERE it can run \u2014 every connection with its
|
|
60474
|
+
\`ccn_\u2026\` id, alias, and target kind:
|
|
60380
60475
|
|
|
60381
|
-
|
|
60476
|
+
- \`cloud\` \u2014 an org-shared cloud profile (a maintainer's signed-in browser)
|
|
60477
|
+
- \`desktop\` \u2014 a member's own device (only its owner can exec through it)
|
|
60478
|
+
- \`mcp\` \u2014 a remote MCP tool server
|
|
60479
|
+
- \`device\` \u2014 a device whose placement could not be resolved just now (the
|
|
60480
|
+
device list was unavailable); don't guess which kind it is \u2014 re-run
|
|
60481
|
+
discovery, and treat a persistent \`device\` like an unverified target
|
|
60482
|
+
- \`orphaned\` \u2014 the target device is gone; the connection is unusable
|
|
60382
60483
|
|
|
60383
|
-
|
|
60484
|
+
Pick the connection whose alias names the account/device the task needs
|
|
60485
|
+
(e.g. \`ins-nyc\` vs \`ins-boston\`). A row without an alias can only be
|
|
60486
|
+
referenced by \`ccn_\` id \u2014 when aliases are missing and several connections
|
|
60487
|
+
could match, ask a human to name them in the Clip Console rather than
|
|
60488
|
+
guessing which signed-in account you are about to act through.
|
|
60384
60489
|
|
|
60385
|
-
|
|
60386
|
-
profile. **Name the target explicitly.** A cloud profile has NO implicit
|
|
60387
|
-
route; omitting the target entirely is a desktop-only legacy form that
|
|
60388
|
-
reaches just YOUR OWN online desktop device \u2014 never a shared cloud profile.
|
|
60490
|
+
## Execute
|
|
60389
60491
|
|
|
60390
60492
|
\`\`\`bash
|
|
60391
|
-
parall clip exec <clip> <command> [args] --connection <
|
|
60493
|
+
parall clip exec <clip> <command> [args] --connection <ccn_|alias> # the normal form
|
|
60392
60494
|
parall clip exec browser-tools screenshot '{"url":"\u2026"}' --connection cloud-main
|
|
60393
60495
|
\`\`\`
|
|
60394
60496
|
|
|
60497
|
+
Build \`args\` as JSON per the command's params from \`clip info\` (or the
|
|
60498
|
+
tool's \`inputSchema\` from \`clip tools\` for MCP clips \u2014 tool names are NOT
|
|
60499
|
+
frozen in the manifest, so never guess a tool name or its argument shape).
|
|
60500
|
+
Results are JSON on stdout; failures print a typed error.
|
|
60501
|
+
|
|
60502
|
+
**Name the target explicitly.** A cloud profile has NO implicit route;
|
|
60503
|
+
omitting the target entirely is a desktop-only legacy form that reaches just
|
|
60504
|
+
YOUR OWN online desktop device \u2014 never a shared cloud profile.
|
|
60505
|
+
|
|
60395
60506
|
- A cloud (hosted) profile is reachable ONLY via \`--connection\` \u2014 the clip
|
|
60396
|
-
connection its maintainer bound
|
|
60397
|
-
|
|
60398
|
-
|
|
60507
|
+
connection its maintainer bound. That binding IS your authorization;
|
|
60508
|
+
without one the server answers \`HOSTED_CONNECTION_REQUIRED\` and the fix
|
|
60509
|
+
is to ask an owner/admin to bind the clip, never to retry.
|
|
60399
60510
|
- \`--edge <edgeId>\` targets only a desktop device YOU own.
|
|
60400
60511
|
- Waiting on a cloud profile is handled by the CLI: \`EDGE_ACTIVATING\` (cold
|
|
60401
60512
|
start), \`EDGE_BUSY\` (another exec is running) and
|
|
@@ -60407,19 +60518,10 @@ parall clip exec browser-tools screenshot '{"url":"\u2026"}' --connection cloud-
|
|
|
60407
60518
|
|
|
60408
60519
|
## MCP clips (remote tool servers)
|
|
60409
60520
|
|
|
60410
|
-
|
|
60411
|
-
|
|
60412
|
-
|
|
60413
|
-
|
|
60414
|
-
find the connection AND the tool schemas:
|
|
60415
|
-
|
|
60416
|
-
\`\`\`bash
|
|
60417
|
-
parall clip connections <alias> # the ccn_ id / alias to pass to --connection
|
|
60418
|
-
parall clip tools <alias> # tool names + descriptions + inputSchema (JSON)
|
|
60419
|
-
\`\`\`
|
|
60420
|
-
|
|
60421
|
-
Read each tool's \`inputSchema\` from \`clip tools\` to build valid args, then
|
|
60422
|
-
exec against that explicit target \u2014 same form as an Edge clip:
|
|
60521
|
+
A connection with target \`mcp\` routes to a remote MCP server; the command
|
|
60522
|
+
is an MCP tool name and the args are that tool's JSON arguments. Read each
|
|
60523
|
+
tool's \`inputSchema\` from \`clip tools\` first, then exec against the
|
|
60524
|
+
explicit target \u2014 the same form as any other clip:
|
|
60423
60525
|
|
|
60424
60526
|
\`\`\`bash
|
|
60425
60527
|
parall clip exec <clip> <tool> [json-args] --connection <ccn_|alias>
|
|
@@ -60437,13 +60539,11 @@ parall clip exec <clip> <tool> [json-args] --connection <ccn_|alias>
|
|
|
60437
60539
|
|
|
60438
60540
|
## Behavior rules
|
|
60439
60541
|
|
|
60440
|
-
- An authorization error (
|
|
60441
|
-
clip's
|
|
60442
|
-
|
|
60542
|
+
- An authorization error (\`HOSTED_CONNECTION_REQUIRED\`, \`FORBIDDEN\`) is a
|
|
60543
|
+
fail-fast: ask the clip's maintainer or an org admin to bind the clip or
|
|
60544
|
+
grant the connection \u2014 do not retry or work around it.
|
|
60545
|
+
- If the target device is offline or the call times out, report that
|
|
60443
60546
|
plainly; do not queue, and never fabricate a result for a run that errored.
|
|
60444
|
-
- Hosted browser activation is handled by the CLI: it waits (bounded) while a
|
|
60445
|
-
cold hosted browser starts, so if the invoke still fails, report the error \u2014
|
|
60446
|
-
do not blind-retry in a loop.
|
|
60447
60547
|
- **\`OUTCOME_UNKNOWN\` is never retryable.** It means the command was
|
|
60448
60548
|
dispatched and MAY HAVE EXECUTED even though no result came back. Retrying
|
|
60449
60549
|
could post, order or delete twice. Verify the effect through the system you
|
|
@@ -60459,6 +60559,8 @@ parall clip exec <clip> <tool> [json-args] --connection <ccn_|alias>
|
|
|
60459
60559
|
- A clip may act through a person's real logged-in account \u2014 outward,
|
|
60460
60560
|
irreversible, or spending actions (post, order, delete, pay) get the same
|
|
60461
60561
|
caution as any shared-state change: confirm when intent isn't explicit.
|
|
60562
|
+
The connection's alias/target tells you WHICH account you are acting as \u2014
|
|
60563
|
+
if that is ambiguous, resolve it with a human before acting, not after.
|
|
60462
60564
|
- Reach for \`parall clip list\` whenever a task needs capabilities beyond
|
|
60463
60565
|
built-in tools.
|
|
60464
60566
|
`;
|
|
@@ -60492,7 +60594,7 @@ var SKILLS = [
|
|
|
60492
60594
|
},
|
|
60493
60595
|
{
|
|
60494
60596
|
name: "parall-clips",
|
|
60495
|
-
description: "Parall clip operations: list installed clips,
|
|
60597
|
+
description: "Parall clip operations: list installed clips and their connections, inspect clip commands/tools, execute clip commands on an explicit connection. Use when: the task requires external capabilities (GitHub, web search, etc.), user asks about available tools/clips, or you need to call a clip command.",
|
|
60496
60598
|
content: PARALL_CLIPS_SKILL
|
|
60497
60599
|
}
|
|
60498
60600
|
];
|
|
@@ -62467,6 +62569,10 @@ var CodexAppServerAdapter = class {
|
|
|
62467
62569
|
const forkParams = {
|
|
62468
62570
|
threadId: parentThreadId,
|
|
62469
62571
|
ephemeral: true,
|
|
62572
|
+
// The fork still inherits the parent's model-visible history; omit
|
|
62573
|
+
// only the display turns from the JSON-RPC response. Large persisted
|
|
62574
|
+
// threads can otherwise produce an equally large one-line payload.
|
|
62575
|
+
excludeTurns: true,
|
|
62470
62576
|
// Forks must inherit the bridge's approval/sandbox contract. thread/fork
|
|
62471
62577
|
// does NOT inherit them from the parent thread — omitting them falls
|
|
62472
62578
|
// back to codex defaults (on-request approval, workspace-write), and an
|
|
@@ -62637,7 +62743,13 @@ var CodexAppServerAdapter = class {
|
|
|
62637
62743
|
try {
|
|
62638
62744
|
await client.sendRequest("initialize", {
|
|
62639
62745
|
clientInfo: { name: "parall-codex-agent", version: "1" },
|
|
62640
|
-
|
|
62746
|
+
// Required by thread/resume.excludeTurns and thread/fork.excludeTurns.
|
|
62747
|
+
// The bridge sends no other experimental request fields. It does not
|
|
62748
|
+
// consume thread status snapshots, so suppress them at the source.
|
|
62749
|
+
capabilities: {
|
|
62750
|
+
experimentalApi: true,
|
|
62751
|
+
optOutNotificationMethods: ["thread/status/changed"]
|
|
62752
|
+
}
|
|
62641
62753
|
});
|
|
62642
62754
|
client.sendNotification("initialized", {});
|
|
62643
62755
|
} catch (err) {
|
|
@@ -62696,7 +62808,13 @@ var CodexAppServerAdapter = class {
|
|
|
62696
62808
|
commonParams.config = { model_reasoning_effort: this.opts.reasoningEffort };
|
|
62697
62809
|
}
|
|
62698
62810
|
const method = opts.resumeId ? "thread/resume" : "thread/start";
|
|
62699
|
-
const params = opts.resumeId ? {
|
|
62811
|
+
const params = opts.resumeId ? {
|
|
62812
|
+
threadId: opts.resumeId,
|
|
62813
|
+
// Resume the complete model-visible history, but do not serialize
|
|
62814
|
+
// its display turns back across stdio. The bridge only needs the id.
|
|
62815
|
+
excludeTurns: true,
|
|
62816
|
+
...commonParams
|
|
62817
|
+
} : { cwd: this.opts.workspaceDir, ...commonParams };
|
|
62700
62818
|
const result = await client.sendRequest(method, params);
|
|
62701
62819
|
const threadId = extractThreadId(result) ?? opts.resumeId;
|
|
62702
62820
|
if (!threadId) {
|
package/bundle/parall-daemon.js
CHANGED
|
@@ -353,6 +353,8 @@ var init_constants = __esm({
|
|
|
353
353
|
SLACK_HISTORY: (orgId) => `${API_BASE}/orgs/${orgId}/agents/me/slack/history`,
|
|
354
354
|
SLACK_MEMBERS: (orgId) => `${API_BASE}/orgs/${orgId}/agents/me/slack/members`,
|
|
355
355
|
SLACK_STATUS: (orgId) => `${API_BASE}/orgs/${orgId}/agents/me/slack/status`,
|
|
356
|
+
// WeChat tier-B read verb (agent-only; internal research preview).
|
|
357
|
+
WECHAT_CONTACTS: (orgId) => `${API_BASE}/orgs/${orgId}/agents/me/wechat/contacts`,
|
|
356
358
|
// Invitations (org-scoped, admin)
|
|
357
359
|
ORG_INVITATIONS: (orgId) => `${API_BASE}/orgs/${orgId}/invitations`,
|
|
358
360
|
ORG_INVITATION: (orgId, invId) => `${API_BASE}/orgs/${orgId}/invitations/${invId}`,
|
|
@@ -514,8 +516,6 @@ var init_constants = __esm({
|
|
|
514
516
|
// Live viewer command — on api-server (API_BASE), not clip-service: it rides
|
|
515
517
|
// the machine control-plane request/reply bridge that lives in api-server.
|
|
516
518
|
BROWSER_PROFILE_VIEWER_COMMAND: (orgId, profileId) => `${API_BASE}/orgs/${orgId}/browser-profiles/${profileId}/viewer/command`,
|
|
517
|
-
// Clip registry (global, served by clip-service → Pinix Hub proxy)
|
|
518
|
-
CLIP_REGISTRY: () => `${CLIP_BASE}/registry/clips`,
|
|
519
519
|
// Edge device endpoints
|
|
520
520
|
ORG_EDGE: (orgId) => `/api/v1/orgs/${orgId}/edge`,
|
|
521
521
|
ORG_EDGE_DEVICES: (orgId) => `/api/v1/orgs/${orgId}/edge/devices`,
|
|
@@ -532,15 +532,20 @@ var init_constants = __esm({
|
|
|
532
532
|
ORG_EDGE_VIEWER_COMMAND: (orgId, edgeId) => `/api/v1/orgs/${orgId}/edge/${edgeId}/viewer/command`,
|
|
533
533
|
CLIP_CONNECTIONS: (orgId, clipId) => `/api/v1/orgs/${orgId}/clip-registry/${clipId}/connections`,
|
|
534
534
|
CLIP_CONNECTION: (orgId, connId) => `/api/v1/orgs/${orgId}/clip-connections/${connId}`,
|
|
535
|
-
// Clip registry (v3, org-scoped, served by api-server — `crg_` entries
|
|
536
|
-
// Pinix Hub catalog proxy above is a different, id-less surface)
|
|
535
|
+
// Clip registry (v3, org-scoped, served by api-server — `crg_` entries)
|
|
537
536
|
ORG_CLIP_REGISTRY: (orgId) => `/api/v1/orgs/${orgId}/clip-registry`,
|
|
537
|
+
ORG_CLIP_REGISTRY_CLIP: (orgId, clipId) => `/api/v1/orgs/${orgId}/clip-registry/${clipId}`,
|
|
538
|
+
ORG_CLIP_REGISTRY_PUBLISH: (orgId) => `/api/v1/orgs/${orgId}/clip-registry/publish`,
|
|
538
539
|
ORG_CLIP_INSTALL: (orgId) => `/api/v1/orgs/${orgId}/clips/install`,
|
|
539
540
|
ORG_CLIPS_INSTALLED: (orgId) => `/api/v1/orgs/${orgId}/clips/installed`,
|
|
541
|
+
ORG_CLIP_UNINSTALL: (orgId, clipId) => `/api/v1/orgs/${orgId}/clips/${clipId}/uninstall`,
|
|
542
|
+
// Per-org agent exec access for one clip (default all agents; PUT human-only)
|
|
543
|
+
ORG_CLIP_EXEC_ACCESS: (orgId, clipId) => `/api/v1/orgs/${orgId}/clips/${clipId}/exec-access`,
|
|
540
544
|
// MCP clip server config (cap:clip-mcp; publisher-org only — cross-org gets
|
|
541
545
|
// 403 MCP_CROSS_ORG_DISABLED on the whole family, reads included)
|
|
542
546
|
ORG_CLIP_MCP_CONFIG: (orgId, clipId) => `/api/v1/orgs/${orgId}/clip-registry/${clipId}/mcp-config`,
|
|
543
|
-
ORG_CLIP_MCP_TOOLS_REFRESH: (orgId, clipId) => `/api/v1/orgs/${orgId}/clip-registry/${clipId}/mcp-config/tools/refresh
|
|
547
|
+
ORG_CLIP_MCP_TOOLS_REFRESH: (orgId, clipId) => `/api/v1/orgs/${orgId}/clip-registry/${clipId}/mcp-config/tools/refresh`,
|
|
548
|
+
ORG_CLIP_MCP_OAUTH_DISCONNECT: (orgId, clipId) => `/api/v1/orgs/${orgId}/clip-registry/${clipId}/mcp-config/oauth/disconnect`
|
|
544
549
|
};
|
|
545
550
|
WS_EVENTS = {
|
|
546
551
|
// Client -> Server
|
|
@@ -2081,6 +2086,14 @@ var init_client = __esm({
|
|
|
2081
2086
|
async setSlackStatus(orgId, input) {
|
|
2082
2087
|
await this.request("POST", ENDPOINTS.SLACK_STATUS(orgId), input);
|
|
2083
2088
|
}
|
|
2089
|
+
/**
|
|
2090
|
+
* WeChat tier-B read verb (agent-only; internal research preview): the
|
|
2091
|
+
* account's address book — friend wxids, saved group room ids, followed
|
|
2092
|
+
* official accounts. Same live gate as the send verb.
|
|
2093
|
+
*/
|
|
2094
|
+
async listWechatContacts(orgId) {
|
|
2095
|
+
return this.request("GET", ENDPOINTS.WECHAT_CONTACTS(orgId));
|
|
2096
|
+
}
|
|
2084
2097
|
async listChannelConversations(orgId, connectionId) {
|
|
2085
2098
|
return this.request("GET", ENDPOINTS.CHANNEL_CONNECTION_CONVERSATIONS(orgId, connectionId));
|
|
2086
2099
|
}
|
|
@@ -2619,17 +2632,11 @@ var init_client = __esm({
|
|
|
2619
2632
|
async revokeBrowserProfileConsent(orgId, profileId, clipId) {
|
|
2620
2633
|
await this.request("DELETE", ENDPOINTS.BROWSER_PROFILE_CONSENT(orgId, profileId, clipId));
|
|
2621
2634
|
}
|
|
2622
|
-
async listRegistryClips(q) {
|
|
2623
|
-
const url = ENDPOINTS.CLIP_REGISTRY() + (q ? `?q=${encodeURIComponent(q)}` : "");
|
|
2624
|
-
const resp = await this.request("GET", url);
|
|
2625
|
-
return resp.data;
|
|
2626
|
-
}
|
|
2627
2635
|
// ---- Clip registry (v3, api-server org registry — `crg_` entries) ----
|
|
2628
2636
|
/**
|
|
2629
2637
|
* List registry clips visible to the org: its own plus public+approved
|
|
2630
2638
|
* cross-org entries. This is the surface `installRegistryClip` and clip
|
|
2631
|
-
* connections operate on
|
|
2632
|
-
* ({@link listRegistryClips}), whose entries carry no `crg_` id.
|
|
2639
|
+
* connections operate on.
|
|
2633
2640
|
*/
|
|
2634
2641
|
async listOrgRegistryClips(orgId) {
|
|
2635
2642
|
const resp = await this.request("GET", `${ENDPOINTS.ORG_CLIP_REGISTRY(orgId)}?limit=100`);
|
|
@@ -2644,11 +2651,58 @@ var init_client = __esm({
|
|
|
2644
2651
|
async installRegistryClip(orgId, clipId) {
|
|
2645
2652
|
return this.request("POST", ENDPOINTS.ORG_CLIP_INSTALL(orgId), { clip_id: clipId });
|
|
2646
2653
|
}
|
|
2654
|
+
/**
|
|
2655
|
+
* Remove an org's install of a registry clip. Keyed by the REGISTRY id
|
|
2656
|
+
* (`crg_`), the same id {@link installRegistryClip} takes — the v2
|
|
2657
|
+
* `deleteClip` operates on a different table and cannot reach these.
|
|
2658
|
+
*/
|
|
2659
|
+
async uninstallRegistryClip(orgId, clipId) {
|
|
2660
|
+
await this.request("DELETE", ENDPOINTS.ORG_CLIP_UNINSTALL(orgId, clipId));
|
|
2661
|
+
}
|
|
2647
2662
|
/** List the org's installed registry clips (full entries). */
|
|
2648
2663
|
async listInstalledRegistryClips(orgId) {
|
|
2649
2664
|
const resp = await this.request("GET", ENDPOINTS.ORG_CLIPS_INSTALLED(orgId));
|
|
2650
2665
|
return resp ?? [];
|
|
2651
2666
|
}
|
|
2667
|
+
/**
|
|
2668
|
+
* Fetch one registry clip by its `crg_` id. For a clip OWNED by the calling
|
|
2669
|
+
* org the entry additionally carries `review_status`/`review_note` — the
|
|
2670
|
+
* state of the latest submitted version and the reviewer's rejection
|
|
2671
|
+
* feedback. This is the polling surface for "did platform review approve my
|
|
2672
|
+
* public publish yet"; cross-org callers see only public+approved entries
|
|
2673
|
+
* and never any review-state fields.
|
|
2674
|
+
*/
|
|
2675
|
+
async getRegistryClip(orgId, clipId) {
|
|
2676
|
+
return this.request("GET", ENDPOINTS.ORG_CLIP_REGISTRY_CLIP(orgId, clipId));
|
|
2677
|
+
}
|
|
2678
|
+
/**
|
|
2679
|
+
* Publish (create, or author-only update) a clip in the org registry,
|
|
2680
|
+
* replacing its whole file set. See {@link PublishRegistryClipRequest} for
|
|
2681
|
+
* the visibility/review semantics; the returned entry carries
|
|
2682
|
+
* `review_status` when a public publish queued a review submission — poll
|
|
2683
|
+
* {@link getRegistryClip} for the outcome.
|
|
2684
|
+
*/
|
|
2685
|
+
async publishRegistryClip(orgId, req) {
|
|
2686
|
+
return this.request("POST", ENDPOINTS.ORG_CLIP_REGISTRY_PUBLISH(orgId), req, void 0, false, {
|
|
2687
|
+
timeoutMs: 6e4
|
|
2688
|
+
});
|
|
2689
|
+
}
|
|
2690
|
+
/**
|
|
2691
|
+
* Read a clip's per-org agent exec access. Org-member readable (agents
|
|
2692
|
+
* included, so a denied agent can learn why exec answered
|
|
2693
|
+
* `CLIP_AGENT_NOT_ALLOWED`).
|
|
2694
|
+
*/
|
|
2695
|
+
async getClipAgentExecAccess(orgId, clipId) {
|
|
2696
|
+
return this.request("GET", ENDPOINTS.ORG_CLIP_EXEC_ACCESS(orgId, clipId));
|
|
2697
|
+
}
|
|
2698
|
+
/**
|
|
2699
|
+
* Replace a clip's per-org agent exec access. Human-only (agent principals
|
|
2700
|
+
* get 403); under `all_agents` the `agent_ids` must be empty. Every granted
|
|
2701
|
+
* id must be an active agent of this org (else `400 INVALID_INPUT`).
|
|
2702
|
+
*/
|
|
2703
|
+
async putClipAgentExecAccess(orgId, clipId, access) {
|
|
2704
|
+
return this.request("PUT", ENDPOINTS.ORG_CLIP_EXEC_ACCESS(orgId, clipId), access);
|
|
2705
|
+
}
|
|
2652
2706
|
// ---- Edge devices ----
|
|
2653
2707
|
async listEdgeDevices(orgId) {
|
|
2654
2708
|
return this.request("GET", ENDPOINTS.ORG_EDGE_DEVICES(orgId));
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@parall/daemon",
|
|
3
|
-
"version": "1.52.
|
|
3
|
+
"version": "1.52.2",
|
|
4
4
|
"description": "Parall local agent runtime — daemon supervisor + bridge runtimes, bundled as standalone JS files",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -33,11 +33,11 @@
|
|
|
33
33
|
"@aws-sdk/client-s3": "3.984.0",
|
|
34
34
|
"@pinixai/bb-browser-pro": "0.15.0",
|
|
35
35
|
"ws": "^8.18.0",
|
|
36
|
-
"@parall/agent-core": "1.52.
|
|
37
|
-
"@parall/sdk": "1.52.
|
|
38
|
-
"@parall/claude-agent": "1.52.
|
|
39
|
-
"@parall/codex-agent": "1.52.
|
|
40
|
-
"@parall/openclaw-agent": "1.52.
|
|
36
|
+
"@parall/agent-core": "1.52.2",
|
|
37
|
+
"@parall/sdk": "1.52.2",
|
|
38
|
+
"@parall/claude-agent": "1.52.2",
|
|
39
|
+
"@parall/codex-agent": "1.52.2",
|
|
40
|
+
"@parall/openclaw-agent": "1.52.2"
|
|
41
41
|
},
|
|
42
42
|
"devDependencies": {
|
|
43
43
|
"@types/node": "^22.0.0",
|