@clawroom/openclaw 0.2.2 → 0.2.3
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/README.md +6 -6
- package/package.json +3 -3
- package/src/channel.ts +1 -1
- package/src/client.ts +9 -29
- package/src/task-executor.ts +12 -18
package/README.md
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
#
|
|
1
|
+
# ClawRoom
|
|
2
2
|
|
|
3
3
|
OpenClaw channel plugin for the ClawRoom task marketplace. Connects your OpenClaw gateway to ClawRoom so your lobsters can claim and execute tasks.
|
|
4
4
|
|
|
@@ -28,11 +28,11 @@ openclaw gateway restart
|
|
|
28
28
|
|
|
29
29
|
## Release
|
|
30
30
|
|
|
31
|
-
The repository includes a GitHub Actions workflow that publishes
|
|
31
|
+
The repository includes a GitHub Actions workflow that publishes `@clawroom/protocol`, `@clawroom/sdk`, and `@clawroom/openclaw` to npm when a release tag is pushed.
|
|
32
32
|
|
|
33
33
|
To publish a new version:
|
|
34
34
|
|
|
35
|
-
1. Update `
|
|
36
|
-
2.
|
|
37
|
-
|
|
38
|
-
|
|
35
|
+
1. Update the package versions in `protocol/package.json`, `sdk/package.json`, and `plugin/package.json`.
|
|
36
|
+
2. Commit and push the release commit to GitHub.
|
|
37
|
+
3. Push a release tag, for example `git tag plugin-0.2.3 && git push origin plugin-0.2.3`.
|
|
38
|
+
4. Watch `.github/workflows/release-plugin.yml` until all three publish jobs succeed.
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@clawroom/openclaw",
|
|
3
|
-
"version": "0.2.
|
|
4
|
-
"description": "OpenClaw channel plugin for the
|
|
3
|
+
"version": "0.2.3",
|
|
4
|
+
"description": "OpenClaw channel plugin for the ClawRoom task marketplace",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
7
7
|
"repository": {
|
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|
"openclaw.plugin.json"
|
|
21
21
|
],
|
|
22
22
|
"dependencies": {
|
|
23
|
-
"@clawroom/sdk": "^0.2.
|
|
23
|
+
"@clawroom/sdk": "^0.2.3"
|
|
24
24
|
},
|
|
25
25
|
"peerDependencies": {
|
|
26
26
|
"openclaw": "*"
|
package/src/channel.ts
CHANGED
|
@@ -268,7 +268,7 @@ export const clawroomPlugin: ChannelPlugin<ResolvedClawroomAccount> = {
|
|
|
268
268
|
* runtime environment when available, falling back to a random id.
|
|
269
269
|
*/
|
|
270
270
|
function resolveDeviceId(ctx: {
|
|
271
|
-
runtime
|
|
271
|
+
runtime?: unknown;
|
|
272
272
|
}): string {
|
|
273
273
|
// The RuntimeEnv may expose hostname or machineId depending on version
|
|
274
274
|
const r = ctx.runtime as Record<string, unknown>;
|
package/src/client.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { AgentMessage, ServerClaimAck,
|
|
1
|
+
import type { AgentMessage, ServerClaimAck, ServerTask } from "@clawroom/sdk";
|
|
2
2
|
|
|
3
3
|
const HEARTBEAT_INTERVAL_MS = 30_000;
|
|
4
4
|
const POLL_INTERVAL_MS = 10_000;
|
|
@@ -6,14 +6,10 @@ const POLL_INTERVAL_MS = 10_000;
|
|
|
6
6
|
// ── Types ─────────────────────────────────────────────────────────────
|
|
7
7
|
|
|
8
8
|
type TaskCallback = (task: ServerTask) => void;
|
|
9
|
-
type TaskListCallback = (tasks: ServerTask[]) => void;
|
|
10
9
|
type ClaimAckCallback = (ack: ServerClaimAck) => void;
|
|
11
|
-
type ClaimRequestCallback = (task: ServerTask) => void;
|
|
12
|
-
type ErrorCallback = (error: ServerMessage & { type: "server.error" }) => void;
|
|
13
10
|
type DisconnectCallback = () => void;
|
|
14
11
|
type WelcomeCallback = (agentId: string) => void;
|
|
15
|
-
type FatalCallback = (reason: string) => void;
|
|
16
|
-
type ModeChangeCallback = (mode: "sse" | "polling") => void;
|
|
12
|
+
type FatalCallback = (reason: string, code?: number) => void;
|
|
17
13
|
|
|
18
14
|
export type ClawroomClientOptions = {
|
|
19
15
|
endpoint: string;
|
|
@@ -21,14 +17,14 @@ export type ClawroomClientOptions = {
|
|
|
21
17
|
deviceId: string;
|
|
22
18
|
skills: string[];
|
|
23
19
|
log?: {
|
|
24
|
-
info?: (...args: unknown[]) => void;
|
|
25
|
-
warn?: (...args: unknown[]) => void;
|
|
26
|
-
error?: (...args: unknown[]) => void;
|
|
20
|
+
info?: (message: string, ...args: unknown[]) => void;
|
|
21
|
+
warn?: (message: string, ...args: unknown[]) => void;
|
|
22
|
+
error?: (message: string, ...args: unknown[]) => void;
|
|
27
23
|
};
|
|
28
24
|
};
|
|
29
25
|
|
|
30
26
|
/**
|
|
31
|
-
*
|
|
27
|
+
* ClawRoom agent client using HTTP polling.
|
|
32
28
|
*
|
|
33
29
|
* Agent→Server actions use HTTP POST:
|
|
34
30
|
* /api/agents/heartbeat, /poll, /complete, /fail, /progress, /claim
|
|
@@ -41,23 +37,13 @@ export class ClawroomClient {
|
|
|
41
37
|
private httpBase: string;
|
|
42
38
|
|
|
43
39
|
private taskCallbacks: TaskCallback[] = [];
|
|
44
|
-
private taskListCallbacks: TaskListCallback[] = [];
|
|
45
40
|
private claimAckCallbacks: ClaimAckCallback[] = [];
|
|
46
|
-
private claimRequestCallbacks: ClaimRequestCallback[] = [];
|
|
47
|
-
private errorCallbacks: ErrorCallback[] = [];
|
|
48
41
|
private disconnectCallbacks: DisconnectCallback[] = [];
|
|
49
42
|
private welcomeCallbacks: WelcomeCallback[] = [];
|
|
50
43
|
private fatalCallbacks: FatalCallback[] = [];
|
|
51
|
-
private modeChangeCallbacks: ModeChangeCallback[] = [];
|
|
52
44
|
|
|
53
45
|
constructor(private readonly options: ClawroomClientOptions) {
|
|
54
|
-
|
|
55
|
-
if (ep.includes("/api/agents")) {
|
|
56
|
-
this.httpBase = ep.replace(/\/stream\/?$/, "");
|
|
57
|
-
} else {
|
|
58
|
-
const httpUrl = ep.replace(/^wss:/, "https:").replace(/^ws:/, "http:");
|
|
59
|
-
this.httpBase = httpUrl.replace(/\/ws\/.*$/, "/api/agents");
|
|
60
|
-
}
|
|
46
|
+
this.httpBase = options.endpoint.replace(/\/+$/, "");
|
|
61
47
|
}
|
|
62
48
|
|
|
63
49
|
connect(): void {
|
|
@@ -83,19 +69,14 @@ export class ClawroomClient {
|
|
|
83
69
|
get isAlive(): boolean { return !this.stopped; }
|
|
84
70
|
get isConnected(): boolean { return this.connected; }
|
|
85
71
|
get isFatal(): boolean { return false; }
|
|
86
|
-
get currentMode(): "sse" | "polling" { return "polling"; }
|
|
87
72
|
|
|
88
73
|
onTask(cb: TaskCallback): void { this.taskCallbacks.push(cb); }
|
|
89
|
-
onTaskList(cb: TaskListCallback): void { this.taskListCallbacks.push(cb); }
|
|
90
74
|
onClaimAck(cb: ClaimAckCallback): void { this.claimAckCallbacks.push(cb); }
|
|
91
|
-
onClaimRequest(cb: ClaimRequestCallback): void { this.claimRequestCallbacks.push(cb); }
|
|
92
|
-
onError(cb: ErrorCallback): void { this.errorCallbacks.push(cb); }
|
|
93
75
|
onDisconnect(cb: DisconnectCallback): void { this.disconnectCallbacks.push(cb); }
|
|
94
76
|
onWelcome(cb: WelcomeCallback): void { this.welcomeCallbacks.push(cb); }
|
|
95
77
|
onFatal(cb: FatalCallback): void { this.fatalCallbacks.push(cb); }
|
|
96
|
-
onModeChange(cb: ModeChangeCallback): void { this.modeChangeCallbacks.push(cb); }
|
|
97
78
|
|
|
98
|
-
// ── Heartbeat (HTTP POST
|
|
79
|
+
// ── Heartbeat (HTTP POST) ───────────────────────────────────────
|
|
99
80
|
|
|
100
81
|
private startHeartbeat(): void {
|
|
101
82
|
this.stopHeartbeat();
|
|
@@ -113,7 +94,6 @@ export class ClawroomClient {
|
|
|
113
94
|
if (this.connected) return;
|
|
114
95
|
this.connected = true;
|
|
115
96
|
this.options.log?.info?.("[clawroom] polling connected");
|
|
116
|
-
for (const cb of this.modeChangeCallbacks) cb("polling");
|
|
117
97
|
if (agentId) {
|
|
118
98
|
for (const cb of this.welcomeCallbacks) cb(agentId);
|
|
119
99
|
}
|
|
@@ -218,7 +198,7 @@ export class ClawroomClient {
|
|
|
218
198
|
this.stopHeartbeat();
|
|
219
199
|
this.stopPolling();
|
|
220
200
|
this.markDisconnected();
|
|
221
|
-
for (const cb of this.fatalCallbacks) cb(`Unauthorized: ${text}
|
|
201
|
+
for (const cb of this.fatalCallbacks) cb(`Unauthorized: ${text}`, 401);
|
|
222
202
|
}
|
|
223
203
|
throw new Error(`HTTP ${res.status}: ${text}`);
|
|
224
204
|
}
|
package/src/task-executor.ts
CHANGED
|
@@ -12,7 +12,7 @@ const MAX_FILE_SIZE = 10 * 1024 * 1024;
|
|
|
12
12
|
|
|
13
13
|
/**
|
|
14
14
|
* Wire up the task execution pipeline:
|
|
15
|
-
* 1. On server.task
|
|
15
|
+
* 1. On server.task -> store as available
|
|
16
16
|
* 2. On claim_ack(ok) -> invoke subagent -> send result/fail
|
|
17
17
|
*
|
|
18
18
|
* Tasks arrive through the polling client, either because the agent auto-claimed
|
|
@@ -22,9 +22,9 @@ export function setupTaskExecutor(opts: {
|
|
|
22
22
|
client: ClawroomClient;
|
|
23
23
|
runtime: PluginRuntime;
|
|
24
24
|
log?: {
|
|
25
|
-
info?: (...args: unknown[]) => void;
|
|
26
|
-
warn?: (...args: unknown[]) => void;
|
|
27
|
-
error?: (...args: unknown[]) => void;
|
|
25
|
+
info?: (message: string, ...args: unknown[]) => void;
|
|
26
|
+
warn?: (message: string, ...args: unknown[]) => void;
|
|
27
|
+
error?: (message: string, ...args: unknown[]) => void;
|
|
28
28
|
};
|
|
29
29
|
}): void {
|
|
30
30
|
const { client, runtime, log } = opts;
|
|
@@ -39,15 +39,6 @@ export function setupTaskExecutor(opts: {
|
|
|
39
39
|
knownTasks.set(task.taskId, task);
|
|
40
40
|
});
|
|
41
41
|
|
|
42
|
-
// Task list on connect — store all
|
|
43
|
-
client.onTaskList((tasks: ServerTask[]) => {
|
|
44
|
-
log?.info?.(`[clawroom:executor] ${tasks.length} open task(s) available`);
|
|
45
|
-
for (const t of tasks) {
|
|
46
|
-
log?.info?.(`[clawroom:executor] - ${t.taskId}: ${t.title}`);
|
|
47
|
-
knownTasks.set(t.taskId, t);
|
|
48
|
-
}
|
|
49
|
-
});
|
|
50
|
-
|
|
51
42
|
// Claim ack — either from plugin-initiated claim or Dashboard-initiated claim
|
|
52
43
|
client.onClaimAck((ack: ServerClaimAck) => {
|
|
53
44
|
if (!ack.ok) {
|
|
@@ -90,8 +81,8 @@ async function executeTask(opts: {
|
|
|
90
81
|
runtime: PluginRuntime;
|
|
91
82
|
task: ServerTask;
|
|
92
83
|
log?: {
|
|
93
|
-
info?: (...args: unknown[]) => void;
|
|
94
|
-
error?: (...args: unknown[]) => void;
|
|
84
|
+
info?: (message: string, ...args: unknown[]) => void;
|
|
85
|
+
error?: (message: string, ...args: unknown[]) => void;
|
|
95
86
|
};
|
|
96
87
|
}): Promise<void> {
|
|
97
88
|
const { client, runtime, task, log } = opts;
|
|
@@ -107,7 +98,7 @@ async function executeTask(opts: {
|
|
|
107
98
|
idempotencyKey: `clawroom:${task.taskId}`,
|
|
108
99
|
message: agentMessage,
|
|
109
100
|
extraSystemPrompt:
|
|
110
|
-
"You are executing a task from the
|
|
101
|
+
"You are executing a task from the ClawRoom marketplace. " +
|
|
111
102
|
"Complete the task and provide a SHORT summary (2-3 sentences) of what you did. " +
|
|
112
103
|
"Do NOT include any local file paths, machine info, or internal details in your summary. " +
|
|
113
104
|
"If you create output files, list their absolute paths at the very end, " +
|
|
@@ -180,7 +171,7 @@ async function executeTask(opts: {
|
|
|
180
171
|
const reason = err instanceof Error ? err.message : String(err);
|
|
181
172
|
log?.error?.(`[clawroom:executor] unexpected error for task ${task.taskId}: ${reason}`);
|
|
182
173
|
client.send({
|
|
183
|
-
type: "agent.
|
|
174
|
+
type: "agent.fail",
|
|
184
175
|
taskId: task.taskId,
|
|
185
176
|
reason,
|
|
186
177
|
});
|
|
@@ -289,7 +280,10 @@ function tryParse(s: string): unknown {
|
|
|
289
280
|
*/
|
|
290
281
|
function readAllFiles(
|
|
291
282
|
paths: string[],
|
|
292
|
-
log?: {
|
|
283
|
+
log?: {
|
|
284
|
+
info?: (message: string, ...args: unknown[]) => void;
|
|
285
|
+
warn?: (message: string, ...args: unknown[]) => void;
|
|
286
|
+
},
|
|
293
287
|
): AgentResultFile[] {
|
|
294
288
|
const results: AgentResultFile[] = [];
|
|
295
289
|
for (const fp of paths) {
|