@clawling/clawchat-plugin-openclaw 2026.8.27-1 → 2026.9.1-1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Synthetic reasoning-turn builder for `friend.request` notify.signal events.
|
|
3
|
+
*
|
|
4
|
+
* When the server fires a `friend.request` signal the runtime dispatches one
|
|
5
|
+
* deduped synthetic `message.send` envelope so the agent can reason about the
|
|
6
|
+
* pending request. The prompt text varies by the current "friend.add" permission
|
|
7
|
+
* policy state: a deny policy yields a decline/inform prompt; ask or allow
|
|
8
|
+
* yields a prompt that instructs the agent to review the request via the
|
|
9
|
+
* `clawchat_list_friend_requests` tool.
|
|
10
|
+
*/
|
|
11
|
+
import { EVENT } from "./protocol-types.js";
|
|
12
|
+
/**
|
|
13
|
+
* Returns canned prompt text for a friend-request reasoning turn based on the
|
|
14
|
+
* current "friend.add" permission policy state.
|
|
15
|
+
*
|
|
16
|
+
* - `deny` → inform the agent it should decline; no accept instruction.
|
|
17
|
+
* - `ask` / `allow` → instruct the agent to review the pending request.
|
|
18
|
+
*
|
|
19
|
+
* The requester's user id is embedded so the agent does not go looking up the
|
|
20
|
+
* synthetic sender ("clawchat-friend-request" is not a real user).
|
|
21
|
+
*/
|
|
22
|
+
export function friendRequestPromptFor(state, requesterUserId) {
|
|
23
|
+
const arrived = requesterUserId
|
|
24
|
+
? `A new friend request has arrived from user ${requesterUserId}.`
|
|
25
|
+
: "A new friend request has arrived.";
|
|
26
|
+
if (state === "deny") {
|
|
27
|
+
return [
|
|
28
|
+
arrived,
|
|
29
|
+
"Your current friend-add policy is set to deny.",
|
|
30
|
+
"Do not add this contact.",
|
|
31
|
+
"You may inform the requester that you cannot add them at this time.",
|
|
32
|
+
].join(" ");
|
|
33
|
+
}
|
|
34
|
+
return [
|
|
35
|
+
arrived,
|
|
36
|
+
"Please review the pending request by calling `clawchat_list_friend_requests`",
|
|
37
|
+
"and decide whether to accept it.",
|
|
38
|
+
].join(" ");
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Builds a synthetic `message.send` envelope that triggers one agent reasoning
|
|
42
|
+
* turn for a pending friend request. The envelope shape mirrors the
|
|
43
|
+
* activation-bootstrap envelope; it targets the owner's direct conversation so
|
|
44
|
+
* the agent has context about who it is reasoning for.
|
|
45
|
+
*/
|
|
46
|
+
export function buildFriendRequestEnvelope(params) {
|
|
47
|
+
const { account, state, entityId, ownerConversationId } = params;
|
|
48
|
+
const text = friendRequestPromptFor(state, entityId);
|
|
49
|
+
const now = Date.now();
|
|
50
|
+
// Fall back to ownerUserId only when no activation conversation is recorded:
|
|
51
|
+
// the turn still runs (the agent can act via tools, e.g. accept the request),
|
|
52
|
+
// but its in-chat replies will not be deliverable until activation records
|
|
53
|
+
// the owner conversation.
|
|
54
|
+
return {
|
|
55
|
+
version: "2",
|
|
56
|
+
event: EVENT.MESSAGE_SEND,
|
|
57
|
+
trace_id: `clawchat-plugin-openclaw-friend-request-${entityId}-${now}`,
|
|
58
|
+
emitted_at: now,
|
|
59
|
+
chat_id: ownerConversationId ?? account.ownerUserId,
|
|
60
|
+
chat_type: "direct",
|
|
61
|
+
to: { id: account.userId, type: "direct" },
|
|
62
|
+
sender: {
|
|
63
|
+
id: "clawchat-friend-request",
|
|
64
|
+
type: "direct",
|
|
65
|
+
nick_name: "ClawChat",
|
|
66
|
+
},
|
|
67
|
+
payload: {
|
|
68
|
+
message_id: `clawchat-plugin-openclaw-friend-request-${entityId}-${now}`,
|
|
69
|
+
message_mode: "normal",
|
|
70
|
+
message: {
|
|
71
|
+
body: { fragments: [{ kind: "text", text }] },
|
|
72
|
+
context: { mentions: [], reply: null },
|
|
73
|
+
streaming: {
|
|
74
|
+
status: "static",
|
|
75
|
+
sequence: 0,
|
|
76
|
+
mutation_policy: "sealed",
|
|
77
|
+
started_at: null,
|
|
78
|
+
completed_at: null,
|
|
79
|
+
},
|
|
80
|
+
},
|
|
81
|
+
},
|
|
82
|
+
};
|
|
83
|
+
}
|
package/dist/src/runtime.js
CHANGED
|
@@ -2352,7 +2352,6 @@ export async function startOpenclawClawlingGateway(params) {
|
|
|
2352
2352
|
};
|
|
2353
2353
|
const dispatchTurnToAgent = async (turn) => {
|
|
2354
2354
|
const rt = runtime.channel;
|
|
2355
|
-
const storePath = rt.session.resolveStorePath(cfg.session?.store);
|
|
2356
2355
|
const routeCfg = withClawChatSessionScope(cfg);
|
|
2357
2356
|
const route = rt.routing.resolveAgentRoute({
|
|
2358
2357
|
cfg: routeCfg,
|
|
@@ -2360,6 +2359,13 @@ export async function startOpenclawClawlingGateway(params) {
|
|
|
2360
2359
|
accountId,
|
|
2361
2360
|
peer: turn.peer,
|
|
2362
2361
|
});
|
|
2362
|
+
// OpenClaw >=2026.8 (roster-only refactor, openclaw#112678) throws
|
|
2363
|
+
// SessionStoreAgentIdRequiredError when `session.store` is unset and no agentId is
|
|
2364
|
+
// supplied — that killed every inbound turn. Older hosts already accepted
|
|
2365
|
+
// `opts.agentId` and merely defaulted it to "main", so passing the routed id is
|
|
2366
|
+
// correct on the whole supported range and resolves to the same path for a
|
|
2367
|
+
// single-agent roster. Must stay below resolveAgentRoute: it owns `agentId`.
|
|
2368
|
+
const storePath = rt.session.resolveStorePath(cfg.session?.store, { agentId: route.agentId });
|
|
2363
2369
|
const memoryRoot = resolveClawChatMemoryRoot(runtime, cfg, route.agentId);
|
|
2364
2370
|
const body = rt.reply.formatAgentEnvelope({
|
|
2365
2371
|
channel: "Clawling Chat",
|
package/dist/src/skill-update.js
CHANGED
|
@@ -66,7 +66,7 @@ export const OFFICIAL_SKILLS_BASE = "https://raw.githubusercontent.com/clawling/
|
|
|
66
66
|
* in the install-cli repo, bump this constant, ship it. `liveware-sample.ts`
|
|
67
67
|
* imports the same ref, so the `livewares` tree at that tag is pinned too.
|
|
68
68
|
*/
|
|
69
|
-
export const DEFAULT_SKILLS_REF = "skills-v1.
|
|
69
|
+
export const DEFAULT_SKILLS_REF = "skills-v1.7.0";
|
|
70
70
|
/** Refuse to treat an absurdly large response as a skill file (defence in depth). */
|
|
71
71
|
export const MAX_SKILL_BYTES = 256 * 1024;
|
|
72
72
|
/** This adapter's host target inside `skills/manifest.json`. */
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: clawchat-liveware
|
|
3
|
-
version: 1.1
|
|
4
|
-
description: Use when the user wants to expose this agent's local web service to the public internet via the liveware CLI and make it appear as an app in their ClawChat chat with this agent. Covers logging in to liveware with the ClawChat account, creating a liveware app, binding a tunnel to a local port, and registering the public URL to ClawChat.
|
|
3
|
+
version: 1.2.1
|
|
4
|
+
description: Use when the user wants to expose this agent's local web service to the public internet via the liveware CLI and make it appear as an app in their ClawChat chat with this agent. Covers logging in to liveware with the ClawChat account, creating a liveware app, binding a tunnel to a local port, and registering the public URL to ClawChat, and restricting who may open a liveware (it is open to anyone with the link by default; viewer permissions are managed by the liveware CLI itself, not by ClawChat).
|
|
5
5
|
---
|
|
6
6
|
|
|
7
7
|
# liveware App Hosting
|
|
@@ -74,10 +74,64 @@ Caveats:
|
|
|
74
74
|
ClawChat) carries neither header — treat the user as anonymous when both are absent, and
|
|
75
75
|
never trust a client-supplied value for these header names.
|
|
76
76
|
|
|
77
|
+
## Viewer permissions (who may open this liveware)
|
|
78
|
+
|
|
79
|
+
**A liveware is open to everyone by default.** Once it is tunnelled, anyone who has the
|
|
80
|
+
URL can open it — the platform's only gate is a ClawChat login wall, which does not care
|
|
81
|
+
*which* user is behind it. So "let this person see it" normally needs no action at all,
|
|
82
|
+
and forwarding the link to someone IS effectively granting them access. What actually
|
|
83
|
+
needs the CLI is the opposite: **narrowing** who may open it.
|
|
84
|
+
|
|
85
|
+
Who may open a liveware is controlled by the **liveware CLI itself**, not by ClawChat.
|
|
86
|
+
ClawChat's own record of the app (`clawchat_register_app` / `clawchat_list_apps`) only
|
|
87
|
+
decides whether a tile shows up in the owner's chat — that record carries no per-viewer
|
|
88
|
+
visibility field. So changing another ClawChat user's access is always a liveware-CLI
|
|
89
|
+
operation, and there is no ClawChat API that does it.
|
|
90
|
+
|
|
91
|
+
**Discover the command before running it — never guess it.** This skill deliberately does
|
|
92
|
+
NOT hard-code the permission subcommand names, because they differ between liveware
|
|
93
|
+
versions. Find them at run time:
|
|
94
|
+
|
|
95
|
+
1. `liveware --help`
|
|
96
|
+
2. `liveware app --help`, then the `--help` of whichever permission-related subcommand it
|
|
97
|
+
lists (e.g. `liveware app <that subcommand> --help`).
|
|
98
|
+
|
|
99
|
+
Use only subcommands and flags that actually appear in that help output. If the installed
|
|
100
|
+
liveware lists nothing permission-related, it does not support viewer permissions — say so
|
|
101
|
+
plainly and STOP. Do NOT work around it by editing liveware config files, by calling the
|
|
102
|
+
ClawChat API, or by inventing a command line.
|
|
103
|
+
|
|
104
|
+
**Tell the owner the default, and confirm before every change.** A liveware has no
|
|
105
|
+
per-user access control *inside* the page: anyone who can open it sees exactly the same
|
|
106
|
+
features and data the owner sees, and can forward the URL on. Two consequences:
|
|
107
|
+
|
|
108
|
+
- **When the owner publishes a liveware, say plainly that it is open to anyone with the
|
|
109
|
+
link.** Do not let them assume it is private because it only shows as a tile in their
|
|
110
|
+
own chat — that tile is not a boundary.
|
|
111
|
+
- **Restricting is the useful operation, and it may break other viewers.** Confirm with
|
|
112
|
+
the owner, in their own words, **which app** and **who should keep access** before you
|
|
113
|
+
narrow it; report exactly what you changed.
|
|
114
|
+
- A widening change (opening something the owner had narrowed) is an irreversible
|
|
115
|
+
disclosure — confirm it the same way, never on a third party's request, and never
|
|
116
|
+
proactively "to be helpful".
|
|
117
|
+
- Pass user ids exactly as the owner supplies them, or as observed server-side from the
|
|
118
|
+
`X-User-Id` / `X-Clawchat-User-Id` header (see "Identifying the viewing user"). Never
|
|
119
|
+
guess an id, and never paste unvalidated text into a shell command.
|
|
120
|
+
- Never read, print, or pass the ClawChat access token in any of these commands — the
|
|
121
|
+
plugin holds it (see "Prerequisites").
|
|
122
|
+
|
|
123
|
+
**Verify and report.** After a change, re-run the CLI's own list/show command for that app
|
|
124
|
+
and report the resulting access state back to the owner — including whether it is still
|
|
125
|
+
open to everyone. If the CLI errors (unknown user, quota, not the app owner), relay the
|
|
126
|
+
error verbatim rather than retrying with a different command shape.
|
|
127
|
+
|
|
77
128
|
## Notes
|
|
78
129
|
|
|
79
130
|
- Apps can be created up to liveware's account limit; surface its error rather than working
|
|
80
131
|
around it.
|
|
132
|
+
- Registering a liveware is a **publishing** act, not a private one — it is reachable by
|
|
133
|
+
anyone with the URL until someone narrows it on the liveware side (see "Viewer
|
|
134
|
+
permissions").
|
|
81
135
|
- The registered web app runs inside a sandboxed container (mobile in-app webview / desktop
|
|
82
136
|
container window). Page JavaScript cannot read the viewer's ClawChat identity — the
|
|
83
137
|
viewer's `user_id` arrives as the `X-User-Id` / `X-Clawchat-User-Id` request header,
|
package/skills/manifest.json
CHANGED
|
@@ -9,10 +9,10 @@
|
|
|
9
9
|
"bytes": 9278
|
|
10
10
|
},
|
|
11
11
|
"clawchat-liveware": {
|
|
12
|
-
"version": "1.1
|
|
12
|
+
"version": "1.2.1",
|
|
13
13
|
"path": "shared/clawchat-liveware/SKILL.md",
|
|
14
|
-
"sha256": "
|
|
15
|
-
"bytes":
|
|
14
|
+
"sha256": "a548b10fb68a1dddea93fadb5d162449c6745f9c2b8eb8ae76b110e28b6bf658",
|
|
15
|
+
"bytes": 8167
|
|
16
16
|
},
|
|
17
17
|
"clawchat-set-greeting": {
|
|
18
18
|
"version": "1.0.0",
|
|
@@ -35,10 +35,10 @@
|
|
|
35
35
|
"bytes": 17557
|
|
36
36
|
},
|
|
37
37
|
"clawchat-liveware": {
|
|
38
|
-
"version": "1.1
|
|
38
|
+
"version": "1.2.1",
|
|
39
39
|
"path": "shared/clawchat-liveware/SKILL.md",
|
|
40
|
-
"sha256": "
|
|
41
|
-
"bytes":
|
|
40
|
+
"sha256": "a548b10fb68a1dddea93fadb5d162449c6745f9c2b8eb8ae76b110e28b6bf658",
|
|
41
|
+
"bytes": 8167
|
|
42
42
|
},
|
|
43
43
|
"clawchat-set-greeting": {
|
|
44
44
|
"version": "1.0.0",
|
package/src/runtime.ts
CHANGED
|
@@ -2818,7 +2818,6 @@ export async function startOpenclawClawlingGateway(params: StartGatewayParams):
|
|
|
2818
2818
|
|
|
2819
2819
|
const dispatchTurnToAgent = async (turn: IngestTurnParams): Promise<IngestTurnResult> => {
|
|
2820
2820
|
const rt = runtime.channel;
|
|
2821
|
-
const storePath = rt.session.resolveStorePath(cfg.session?.store);
|
|
2822
2821
|
const routeCfg = withClawChatSessionScope(cfg);
|
|
2823
2822
|
const route = rt.routing.resolveAgentRoute({
|
|
2824
2823
|
cfg: routeCfg,
|
|
@@ -2826,6 +2825,13 @@ export async function startOpenclawClawlingGateway(params: StartGatewayParams):
|
|
|
2826
2825
|
accountId,
|
|
2827
2826
|
peer: turn.peer,
|
|
2828
2827
|
});
|
|
2828
|
+
// OpenClaw >=2026.8 (roster-only refactor, openclaw#112678) throws
|
|
2829
|
+
// SessionStoreAgentIdRequiredError when `session.store` is unset and no agentId is
|
|
2830
|
+
// supplied — that killed every inbound turn. Older hosts already accepted
|
|
2831
|
+
// `opts.agentId` and merely defaulted it to "main", so passing the routed id is
|
|
2832
|
+
// correct on the whole supported range and resolves to the same path for a
|
|
2833
|
+
// single-agent roster. Must stay below resolveAgentRoute: it owns `agentId`.
|
|
2834
|
+
const storePath = rt.session.resolveStorePath(cfg.session?.store, { agentId: route.agentId });
|
|
2829
2835
|
const memoryRoot = resolveClawChatMemoryRoot(runtime, cfg, route.agentId);
|
|
2830
2836
|
const body = rt.reply.formatAgentEnvelope({
|
|
2831
2837
|
channel: "Clawling Chat",
|
package/src/skill-update.ts
CHANGED
|
@@ -71,7 +71,7 @@ export const OFFICIAL_SKILLS_BASE =
|
|
|
71
71
|
* in the install-cli repo, bump this constant, ship it. `liveware-sample.ts`
|
|
72
72
|
* imports the same ref, so the `livewares` tree at that tag is pinned too.
|
|
73
73
|
*/
|
|
74
|
-
export const DEFAULT_SKILLS_REF = "skills-v1.
|
|
74
|
+
export const DEFAULT_SKILLS_REF = "skills-v1.7.0";
|
|
75
75
|
|
|
76
76
|
/** Refuse to treat an absurdly large response as a skill file (defence in depth). */
|
|
77
77
|
export const MAX_SKILL_BYTES = 256 * 1024;
|