@parall/parall 1.46.0 → 1.48.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.bundle.mjs +161 -7
- package/package.json +3 -3
- package/skills/parall-clips/SKILL.md +27 -0
package/dist/index.bundle.mjs
CHANGED
|
@@ -51482,10 +51482,17 @@ var ENDPOINTS = {
|
|
|
51482
51482
|
CHANNEL_CONVERSATION_SESSION: (orgId, conversationId) => `${API_BASE}/orgs/${orgId}/channel-conversations/${conversationId}/session`,
|
|
51483
51483
|
CHANNEL_MESSAGE: (orgId, messageId) => `${API_BASE}/orgs/${orgId}/channel-messages/${messageId}`,
|
|
51484
51484
|
CHANNEL_PROVISIONING: (orgId) => `${API_BASE}/orgs/${orgId}/channel-provisioning`,
|
|
51485
|
+
CHANNEL_SLACK_MANIFEST_LINK: (orgId) => `${API_BASE}/orgs/${orgId}/channel-provisioning/slack/manifest-link`,
|
|
51485
51486
|
CHANNEL_PROVISIONING_SESSION: (orgId, sessionId) => `${API_BASE}/orgs/${orgId}/channel-provisioning/${sessionId}`,
|
|
51486
51487
|
CHANNEL_PROVISIONING_CANCEL: (orgId, sessionId) => `${API_BASE}/orgs/${orgId}/channel-provisioning/${sessionId}/cancel`,
|
|
51487
51488
|
// Tier-B platform verb (agent-only): send one message as the bound bot.
|
|
51488
51489
|
CHANNEL_SEND: (orgId) => `${API_BASE}/orgs/${orgId}/agents/me/channel-send`,
|
|
51490
|
+
// Tier-B read verbs (agent-only): workspace visibility as the bot sees it.
|
|
51491
|
+
SLACK_CHANNELS: (orgId) => `${API_BASE}/orgs/${orgId}/agents/me/slack/channels`,
|
|
51492
|
+
SLACK_USERS: (orgId) => `${API_BASE}/orgs/${orgId}/agents/me/slack/users`,
|
|
51493
|
+
SLACK_HISTORY: (orgId) => `${API_BASE}/orgs/${orgId}/agents/me/slack/history`,
|
|
51494
|
+
SLACK_MEMBERS: (orgId) => `${API_BASE}/orgs/${orgId}/agents/me/slack/members`,
|
|
51495
|
+
SLACK_STATUS: (orgId) => `${API_BASE}/orgs/${orgId}/agents/me/slack/status`,
|
|
51489
51496
|
// Invitations (org-scoped, admin)
|
|
51490
51497
|
ORG_INVITATIONS: (orgId) => `${API_BASE}/orgs/${orgId}/invitations`,
|
|
51491
51498
|
ORG_INVITATION: (orgId, invId) => `${API_BASE}/orgs/${orgId}/invitations/${invId}`,
|
|
@@ -51580,6 +51587,7 @@ var ENDPOINTS = {
|
|
|
51580
51587
|
ORG_UNREAD: (orgId) => `${API_BASE}/orgs/${orgId}/unread`,
|
|
51581
51588
|
CHAT_READ: (orgId, chatId) => `${API_BASE}/orgs/${orgId}/chats/${chatId}/read`,
|
|
51582
51589
|
THREAD_UNREAD: (orgId, chatId, threadRootId) => `${API_BASE}/orgs/${orgId}/chats/${chatId}/threads/${threadRootId}/unread`,
|
|
51590
|
+
THREAD_READ: (orgId, chatId, threadRootId) => `${API_BASE}/orgs/${orgId}/chats/${chatId}/threads/${threadRootId}/read`,
|
|
51583
51591
|
// References (org-scoped)
|
|
51584
51592
|
REFS_RESOLVE: (orgId) => `${API_BASE}/orgs/${orgId}/refs/resolve`,
|
|
51585
51593
|
REFS_BACKLINKS: (orgId) => `${API_BASE}/orgs/${orgId}/refs/backlinks`,
|
|
@@ -51641,10 +51649,17 @@ var ENDPOINTS = {
|
|
|
51641
51649
|
ORG_EDGE: (orgId) => `/api/v1/orgs/${orgId}/edge`,
|
|
51642
51650
|
ORG_EDGE_DEVICES: (orgId) => `/api/v1/orgs/${orgId}/edge/devices`,
|
|
51643
51651
|
ORG_EDGE_DEVICE: (orgId, edgeId) => `/api/v1/orgs/${orgId}/edge/${edgeId}`,
|
|
51652
|
+
ORG_EDGE_DEVICE_UNREGISTER: (orgId, edgeId) => `/api/v1/orgs/${orgId}/edge/${edgeId}/unregister`,
|
|
51644
51653
|
ORG_EDGE_ONBOARDING: (orgId) => `/api/v1/orgs/${orgId}/edge/onboarding`,
|
|
51645
51654
|
ORG_EDGE_PROFILES: (orgId, edgeId) => `/api/v1/orgs/${orgId}/edge/${edgeId}/profiles`,
|
|
51655
|
+
ORG_EDGE_EXEC: (orgId) => `/api/v1/orgs/${orgId}/edge/exec`,
|
|
51646
51656
|
CLIP_CONNECTIONS: (orgId, clipId) => `/api/v1/orgs/${orgId}/clip-registry/${clipId}/connections`,
|
|
51647
|
-
CLIP_CONNECTION: (orgId, connId) => `/api/v1/orgs/${orgId}/clip-connections/${connId}
|
|
51657
|
+
CLIP_CONNECTION: (orgId, connId) => `/api/v1/orgs/${orgId}/clip-connections/${connId}`,
|
|
51658
|
+
// Clip registry (v3, org-scoped, served by api-server — `crg_` entries; the
|
|
51659
|
+
// Pinix Hub catalog proxy above is a different, id-less surface)
|
|
51660
|
+
ORG_CLIP_REGISTRY: (orgId) => `/api/v1/orgs/${orgId}/clip-registry`,
|
|
51661
|
+
ORG_CLIP_INSTALL: (orgId) => `/api/v1/orgs/${orgId}/clips/install`,
|
|
51662
|
+
ORG_CLIPS_INSTALLED: (orgId) => `/api/v1/orgs/${orgId}/clips/installed`
|
|
51648
51663
|
};
|
|
51649
51664
|
var WS_EVENTS = {
|
|
51650
51665
|
// Client -> Server
|
|
@@ -52670,10 +52685,16 @@ var ParallClient = class _ParallClient {
|
|
|
52670
52685
|
async resizeMachine(orgId, machineId, spec) {
|
|
52671
52686
|
return this.request("PATCH", ENDPOINTS.MACHINE_SPEC(orgId, machineId), spec);
|
|
52672
52687
|
}
|
|
52673
|
-
/**
|
|
52688
|
+
/** @deprecated Retired server-side (daemon-control-authorization §4.2):
|
|
52689
|
+
* daemons update autonomously (CDN poll + platform release signal). The
|
|
52690
|
+
* endpoint now answers 409 LOCAL_UPDATE_NOT_SUPPORTED unconditionally. */
|
|
52674
52691
|
async requestMachineUpdate(orgId, machineId, mandatory = false) {
|
|
52675
52692
|
await this.request("POST", ENDPOINTS.MACHINE_REQUEST_UPDATE(orgId, machineId), { mandatory });
|
|
52676
52693
|
}
|
|
52694
|
+
/** @deprecated Retired server-side (daemon-control-authorization §4.2):
|
|
52695
|
+
* remote filesystem browse of a member's machine was remote device access.
|
|
52696
|
+
* The endpoint now answers 409 LOCAL_BROWSE_NOT_SUPPORTED unconditionally;
|
|
52697
|
+
* workspace paths are typed in (or picked on the machine's own Desktop). */
|
|
52677
52698
|
async browseMachineFilesystem(orgId, machineId, path9) {
|
|
52678
52699
|
return this.request("POST", ENDPOINTS.MACHINE_BROWSE(orgId, machineId), { path: path9 }, void 0, false, { timeoutMs: 15e3 });
|
|
52679
52700
|
}
|
|
@@ -52698,6 +52719,14 @@ var ParallClient = class _ParallClient {
|
|
|
52698
52719
|
async getThreadUnread(orgId, chatId, threadRootId) {
|
|
52699
52720
|
return this.request("GET", ENDPOINTS.THREAD_UNREAD(orgId, chatId, threadRootId));
|
|
52700
52721
|
}
|
|
52722
|
+
/** Advance the per-thread read cursor (forward-only). The server auto-clears
|
|
52723
|
+
* thread-scoped inbox items (thread_reply + in-thread mentions) the cursor
|
|
52724
|
+
* now covers. */
|
|
52725
|
+
async markThreadRead(orgId, chatId, threadRootId, messageId) {
|
|
52726
|
+
return this.request("POST", ENDPOINTS.THREAD_READ(orgId, chatId, threadRootId), {
|
|
52727
|
+
message_id: messageId
|
|
52728
|
+
});
|
|
52729
|
+
}
|
|
52701
52730
|
// ---- Inbox ----
|
|
52702
52731
|
async getInbox(orgId, params) {
|
|
52703
52732
|
return this.request("GET", ENDPOINTS.INBOX(orgId), void 0, params);
|
|
@@ -52721,9 +52750,12 @@ var ParallClient = class _ParallClient {
|
|
|
52721
52750
|
async archiveAllInbox(orgId) {
|
|
52722
52751
|
return this.request("POST", ENDPOINTS.INBOX_ARCHIVE_ALL(orgId));
|
|
52723
52752
|
}
|
|
52724
|
-
/** Mark
|
|
52725
|
-
|
|
52726
|
-
|
|
52753
|
+
/** Mark inbox items as read by their source (source_type + source_id) or by
|
|
52754
|
+
* group_key, rather than by inbox item ID. The group_key form clears a whole
|
|
52755
|
+
* group at once (e.g. `task:{taskId}` — task_assign/task_update/task_comment
|
|
52756
|
+
* share it), used by the task detail view's auto-ack on open. */
|
|
52757
|
+
async ackInbox(orgId, target) {
|
|
52758
|
+
return this.request("POST", ENDPOINTS.INBOX_ACK(orgId), target);
|
|
52727
52759
|
}
|
|
52728
52760
|
async deleteInboxItem(orgId, id) {
|
|
52729
52761
|
return this.request("DELETE", ENDPOINTS.INBOX_ITEM(orgId, id));
|
|
@@ -53005,6 +53037,15 @@ var ParallClient = class _ParallClient {
|
|
|
53005
53037
|
async initiateChannelProvisioning(orgId, input) {
|
|
53006
53038
|
return this.request("POST", ENDPOINTS.CHANNEL_PROVISIONING(orgId), input);
|
|
53007
53039
|
}
|
|
53040
|
+
/**
|
|
53041
|
+
* Mint a pending slack connection + api.slack.com manifest-prefill link
|
|
53042
|
+
* (guided manual path). Activate the returned connection_id with
|
|
53043
|
+
* deliverChannelCredentials once the user brings back the bot token +
|
|
53044
|
+
* signing secret.
|
|
53045
|
+
*/
|
|
53046
|
+
async createSlackManifestLink(orgId, input) {
|
|
53047
|
+
return this.request("POST", ENDPOINTS.CHANNEL_SLACK_MANIFEST_LINK(orgId), input);
|
|
53048
|
+
}
|
|
53008
53049
|
/**
|
|
53009
53050
|
* Lazy status poll — server-side this may forward one provider poll, so
|
|
53010
53051
|
* call it at the session's `poll_interval_seconds` cadence, not faster.
|
|
@@ -53023,6 +53064,38 @@ var ParallClient = class _ParallClient {
|
|
|
53023
53064
|
async sendChannelMessage(orgId, input) {
|
|
53024
53065
|
return this.request("POST", ENDPOINTS.CHANNEL_SEND(orgId), input);
|
|
53025
53066
|
}
|
|
53067
|
+
slackReadQuery(base, query, extra) {
|
|
53068
|
+
const params = new URLSearchParams();
|
|
53069
|
+
if (query?.cursor)
|
|
53070
|
+
params.set("cursor", query.cursor);
|
|
53071
|
+
if (query?.limit)
|
|
53072
|
+
params.set("limit", String(query.limit));
|
|
53073
|
+
for (const [k, v] of Object.entries(extra ?? {}))
|
|
53074
|
+
params.set(k, v);
|
|
53075
|
+
const qs = params.toString();
|
|
53076
|
+
return qs ? `${base}?${qs}` : base;
|
|
53077
|
+
}
|
|
53078
|
+
/**
|
|
53079
|
+
* Tier-B read verbs (agent-only): workspace visibility as the bot sees
|
|
53080
|
+
* it. Same live gate as the send verb; authorization beyond it is the
|
|
53081
|
+
* bot's own Slack permissions.
|
|
53082
|
+
*/
|
|
53083
|
+
async listSlackChannels(orgId, query) {
|
|
53084
|
+
return this.request("GET", this.slackReadQuery(ENDPOINTS.SLACK_CHANNELS(orgId), query));
|
|
53085
|
+
}
|
|
53086
|
+
async listSlackUsers(orgId, query) {
|
|
53087
|
+
return this.request("GET", this.slackReadQuery(ENDPOINTS.SLACK_USERS(orgId), query));
|
|
53088
|
+
}
|
|
53089
|
+
async slackHistory(orgId, conversationId, query) {
|
|
53090
|
+
return this.request("GET", this.slackReadQuery(ENDPOINTS.SLACK_HISTORY(orgId), query, { conversation: conversationId }));
|
|
53091
|
+
}
|
|
53092
|
+
async slackMembers(orgId, conversationId, query) {
|
|
53093
|
+
return this.request("GET", this.slackReadQuery(ENDPOINTS.SLACK_MEMBERS(orgId), query, { conversation: conversationId }));
|
|
53094
|
+
}
|
|
53095
|
+
/** Set/clear the Agents-pane "typing…" indicator (best-effort cosmetic). */
|
|
53096
|
+
async setSlackStatus(orgId, input) {
|
|
53097
|
+
await this.request("POST", ENDPOINTS.SLACK_STATUS(orgId), input);
|
|
53098
|
+
}
|
|
53026
53099
|
async listChannelConversations(orgId, connectionId) {
|
|
53027
53100
|
return this.request("GET", ENDPOINTS.CHANNEL_CONNECTION_CONVERSATIONS(orgId, connectionId));
|
|
53028
53101
|
}
|
|
@@ -53527,6 +53600,31 @@ var ParallClient = class _ParallClient {
|
|
|
53527
53600
|
const resp = await this.request("GET", url);
|
|
53528
53601
|
return resp.data;
|
|
53529
53602
|
}
|
|
53603
|
+
// ---- Clip registry (v3, api-server org registry — `crg_` entries) ----
|
|
53604
|
+
/**
|
|
53605
|
+
* List registry clips visible to the org: its own plus public+approved
|
|
53606
|
+
* cross-org entries. This is the surface `installRegistryClip` and clip
|
|
53607
|
+
* connections operate on — NOT the Pinix catalog proxy
|
|
53608
|
+
* ({@link listRegistryClips}), whose entries carry no `crg_` id.
|
|
53609
|
+
*/
|
|
53610
|
+
async listOrgRegistryClips(orgId) {
|
|
53611
|
+
const resp = await this.request("GET", `${ENDPOINTS.ORG_CLIP_REGISTRY(orgId)}?limit=100`);
|
|
53612
|
+
return resp ?? [];
|
|
53613
|
+
}
|
|
53614
|
+
/**
|
|
53615
|
+
* Install a registry clip into the org (a reference in `clip_installs`, not a
|
|
53616
|
+
* copy). Idempotent: installing an already-installed clip returns the same
|
|
53617
|
+
* `200 {ok:true}`. Fails closed with `403 CLIP_NOT_APPROVED` when the clip is
|
|
53618
|
+
* not eligible (cross-org requires public + approved).
|
|
53619
|
+
*/
|
|
53620
|
+
async installRegistryClip(orgId, clipId) {
|
|
53621
|
+
return this.request("POST", ENDPOINTS.ORG_CLIP_INSTALL(orgId), { clip_id: clipId });
|
|
53622
|
+
}
|
|
53623
|
+
/** List the org's installed registry clips (full entries). */
|
|
53624
|
+
async listInstalledRegistryClips(orgId) {
|
|
53625
|
+
const resp = await this.request("GET", ENDPOINTS.ORG_CLIPS_INSTALLED(orgId));
|
|
53626
|
+
return resp ?? [];
|
|
53627
|
+
}
|
|
53530
53628
|
// ---- Edge devices ----
|
|
53531
53629
|
async listEdgeDevices(orgId) {
|
|
53532
53630
|
return this.request("GET", ENDPOINTS.ORG_EDGE_DEVICES(orgId));
|
|
@@ -53544,8 +53642,8 @@ var ParallClient = class _ParallClient {
|
|
|
53544
53642
|
return this.request("POST", ENDPOINTS.ORG_EDGE(orgId), input);
|
|
53545
53643
|
}
|
|
53546
53644
|
/**
|
|
53547
|
-
* Delete a hosted Cloud Profile. Hosted only —
|
|
53548
|
-
*
|
|
53645
|
+
* Delete a hosted Cloud Profile. Hosted only — use {@link unregisterEdgeDevice}
|
|
53646
|
+
* for an offline BYOC registration (`400 EDGE_PLACEMENT_UNSUPPORTED` here).
|
|
53549
53647
|
*
|
|
53550
53648
|
* Idempotent and ASYNC: returns `202` with `hosted_state: 'deleting'` on the first
|
|
53551
53649
|
* call and on every repeat. The device stops being usable immediately (no exec, no
|
|
@@ -53555,12 +53653,68 @@ var ParallClient = class _ParallClient {
|
|
|
53555
53653
|
async deleteEdgeDevice(orgId, edgeId) {
|
|
53556
53654
|
return this.request("DELETE", ENDPOINTS.ORG_EDGE_DEVICE(orgId, edgeId));
|
|
53557
53655
|
}
|
|
53656
|
+
/**
|
|
53657
|
+
* Remove the interactive human caller's own offline BYOC registration.
|
|
53658
|
+
*
|
|
53659
|
+
* Synchronous and idempotent: a committed removal and a repeat after removal
|
|
53660
|
+
* both resolve with no response body. A live connection returns `EDGE_ONLINE`;
|
|
53661
|
+
* callers must not clear local device identity until this method resolves.
|
|
53662
|
+
*/
|
|
53663
|
+
async unregisterEdgeDevice(orgId, edgeId) {
|
|
53664
|
+
await this.request("DELETE", ENDPOINTS.ORG_EDGE_DEVICE_UNREGISTER(orgId, edgeId));
|
|
53665
|
+
}
|
|
53558
53666
|
async getEdgeOnboarding(orgId) {
|
|
53559
53667
|
return this.request("GET", ENDPOINTS.ORG_EDGE_ONBOARDING(orgId));
|
|
53560
53668
|
}
|
|
53561
53669
|
async listEdgeProfiles(orgId, edgeId) {
|
|
53562
53670
|
return this.request("GET", ENDPOINTS.ORG_EDGE_PROFILES(orgId, edgeId));
|
|
53563
53671
|
}
|
|
53672
|
+
/**
|
|
53673
|
+
* Execute a registry clip command on an Edge device.
|
|
53674
|
+
*
|
|
53675
|
+
* A hosted (Cloud Profile) device is reachable ONLY through an explicit
|
|
53676
|
+
* `connection` (id `ccn_…` or alias) — there is no implicit route to an
|
|
53677
|
+
* org-shared browser login. BYOC keeps its legacy selectors (`edge_id`, or
|
|
53678
|
+
* nothing for the caller's own online device).
|
|
53679
|
+
*
|
|
53680
|
+
* Returns the result envelope on completion (`success` may be false when the
|
|
53681
|
+
* command RAN and failed — `error`/`error_code` describe why). Everything
|
|
53682
|
+
* else throws a typed {@link ApiError}; match on `err.code`:
|
|
53683
|
+
*
|
|
53684
|
+
* Safe to retry (guaranteed nothing was dispatched):
|
|
53685
|
+
* - `EDGE_ACTIVATING` 503 + `Retry-After` — cold cloud profile is starting.
|
|
53686
|
+
* Bounded backoff, same `correlation_id` across the loop.
|
|
53687
|
+
* - `EDGE_BUSY` 409 — the device is executing another request.
|
|
53688
|
+
* - `EDGE_CONCURRENCY_LIMIT` 429 — org at its concurrent-session limit.
|
|
53689
|
+
* - `EDGE_UNAVAILABLE` 503 — session torn down / replaced mid-dispatch.
|
|
53690
|
+
*
|
|
53691
|
+
* NOT retryable:
|
|
53692
|
+
* - `OUTCOME_UNKNOWN` 504 — dispatched, but no result arrived. The command
|
|
53693
|
+
* MAY HAVE EXECUTED (posted, ordered, deleted…). Never retry
|
|
53694
|
+
* automatically: verify the effect first, then decide. The message carries
|
|
53695
|
+
* the request id for audit.
|
|
53696
|
+
* - `EDGE_DEADLINE_EXCEEDED` 504 — arrived late, provably NOT executed.
|
|
53697
|
+
* - `EDGE_HOSTED_DISABLED_FOR_ORG` 403, `EDGE_REPAIR` 503 (operator-held),
|
|
53698
|
+
* `EDGE_RUNTIME_UNAVAILABLE` 503 (deployment has no hosted runtime).
|
|
53699
|
+
* - Routing errors: `HOSTED_CONNECTION_REQUIRED`, `CONNECTION_NOT_FOUND`,
|
|
53700
|
+
* `CONNECTION_CLIP_MISMATCH`, `CONNECTION_TARGET_GONE`,
|
|
53701
|
+
* `CONNECTION_PROFILE_MISMATCH`, `EDGE_DELETING`, `DEVICE_OFFLINE`.
|
|
53702
|
+
*/
|
|
53703
|
+
async execEdgeClip(orgId, req) {
|
|
53704
|
+
const t = req.timeout;
|
|
53705
|
+
const serverTimeout = t !== void 0 && t > 0 && t <= 12e4 ? t : 3e4;
|
|
53706
|
+
const timeoutMs = serverTimeout + 1e4;
|
|
53707
|
+
try {
|
|
53708
|
+
return await this.request("POST", ENDPOINTS.ORG_EDGE_EXEC(orgId), req, void 0, false, {
|
|
53709
|
+
timeoutMs
|
|
53710
|
+
});
|
|
53711
|
+
} catch (err) {
|
|
53712
|
+
if (err instanceof ApiError && err.status === 422 && !err.code && typeof err.extras?.error_code === "string") {
|
|
53713
|
+
err.code = err.extras.error_code;
|
|
53714
|
+
}
|
|
53715
|
+
throw err;
|
|
53716
|
+
}
|
|
53717
|
+
}
|
|
53564
53718
|
// ---- Clip connections ----
|
|
53565
53719
|
async listClipConnections(orgId, clipId) {
|
|
53566
53720
|
return this.request("GET", ENDPOINTS.CLIP_CONNECTIONS(orgId, clipId));
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@parall/parall",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.48.0",
|
|
4
4
|
"description": "OpenClaw channel plugin for Parall IM",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -16,8 +16,8 @@
|
|
|
16
16
|
"openclaw.plugin.json"
|
|
17
17
|
],
|
|
18
18
|
"dependencies": {
|
|
19
|
-
"@parall/sdk": "1.
|
|
20
|
-
"@parall/agent-core": "1.
|
|
19
|
+
"@parall/sdk": "1.48.0",
|
|
20
|
+
"@parall/agent-core": "1.48.0"
|
|
21
21
|
},
|
|
22
22
|
"devDependencies": {
|
|
23
23
|
"@types/node": "^22.0.0",
|
|
@@ -25,6 +25,27 @@ parall clip invoke github-tools list-repos '{"org":"acme"}'
|
|
|
25
25
|
|
|
26
26
|
Results are JSON on stdout; failures print an error.
|
|
27
27
|
|
|
28
|
+
## Execute on an Edge device (registry clips)
|
|
29
|
+
|
|
30
|
+
Registry clips run on an Edge — a member's desktop, or an org-shared cloud
|
|
31
|
+
profile. **Name the target explicitly.** A cloud profile has NO implicit
|
|
32
|
+
route; omitting the target entirely is a desktop-only legacy form that
|
|
33
|
+
reaches just YOUR OWN online desktop device — never a shared cloud profile.
|
|
34
|
+
|
|
35
|
+
```bash
|
|
36
|
+
parall clip exec <clip> <command> [args] --connection <id|alias> # the normal form
|
|
37
|
+
parall clip exec browser-tools screenshot '{"url":"…"}' --connection cloud-main
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
- A cloud (hosted) profile is reachable ONLY via `--connection` — the clip
|
|
41
|
+
connection its maintainer bound (`ccn_…` id or alias). That binding IS your
|
|
42
|
+
authorization; without one the server answers `HOSTED_CONNECTION_REQUIRED`
|
|
43
|
+
and the fix is to ask an owner/admin to bind the clip, never to retry.
|
|
44
|
+
- `--edge <edgeId>` targets only a desktop device YOU own.
|
|
45
|
+
- Cold cloud profiles are handled by the CLI: it absorbs `EDGE_ACTIVATING`
|
|
46
|
+
with a bounded wait (~60s) while the profile starts. If the command still
|
|
47
|
+
fails, report the error — do not blind-retry in a loop.
|
|
48
|
+
|
|
28
49
|
## Behavior rules
|
|
29
50
|
|
|
30
51
|
- An authorization error (clip not bound to you) is a fail-fast: ask the
|
|
@@ -34,6 +55,12 @@ Results are JSON on stdout; failures print an error.
|
|
|
34
55
|
- Hosted browser activation is handled by the CLI: it waits (bounded) while a
|
|
35
56
|
cold hosted browser starts, so if the invoke still fails, report the error —
|
|
36
57
|
do not blind-retry in a loop.
|
|
58
|
+
- **`OUTCOME_UNKNOWN` is never retryable.** It means the command was
|
|
59
|
+
dispatched and MAY HAVE EXECUTED even though no result came back. Retrying
|
|
60
|
+
could post, order or delete twice. Verify the effect through the system you
|
|
61
|
+
acted on (or tell the human, quoting the request id from the error) before
|
|
62
|
+
ever re-running. `EDGE_BUSY` is the opposite: guaranteed-unexecuted — wait
|
|
63
|
+
briefly, then one retry is safe.
|
|
37
64
|
- A clip may act through a person's real logged-in account — outward,
|
|
38
65
|
irreversible, or spending actions (post, order, delete, pay) get the same
|
|
39
66
|
caution as any shared-state change: confirm when intent isn't explicit.
|