@teamclaws/teamclaw 2026.3.21 → 2026.3.25
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 +19 -1
- package/api.ts +2 -2
- package/cli.mjs +1185 -0
- package/index.ts +24 -7
- package/openclaw.plugin.json +326 -2
- package/package.json +6 -9
- package/src/config.ts +29 -1
- package/src/controller/controller-service.ts +1 -0
- package/src/controller/controller-tools.ts +12 -1
- package/src/controller/http-server.ts +355 -10
- package/src/controller/local-worker-manager.ts +5 -3
- package/src/controller/prompt-injector.ts +6 -1
- package/src/controller/websocket.ts +1 -0
- package/src/controller/worker-provisioning.ts +93 -4
- package/src/install-defaults.ts +1 -0
- package/src/openclaw-workspace.ts +57 -1
- package/src/roles.ts +42 -7
- package/src/state.ts +6 -0
- package/src/task-executor.ts +1 -0
- package/src/types.ts +53 -1
- package/src/ui/app.js +138 -2
- package/src/ui/index.html +10 -0
- package/src/ui/style.css +148 -0
- package/src/worker/http-handler.ts +4 -0
- package/src/worker/prompt-injector.ts +1 -0
- package/src/worker/skill-installer.ts +302 -0
package/index.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type
|
|
1
|
+
import { definePluginEntry, type OpenClawPluginApi } from "./api.js";
|
|
2
2
|
import { parsePluginConfig } from "./src/types.js";
|
|
3
3
|
import type { TaskExecutionEventInput, WorkerIdentity } from "./src/types.js";
|
|
4
4
|
import { buildConfigSchema } from "./src/config.js";
|
|
@@ -13,16 +13,16 @@ import { LocalWorkerManager } from "./src/controller/local-worker-manager.js";
|
|
|
13
13
|
import { createControllerPromptInjector } from "./src/controller/prompt-injector.js";
|
|
14
14
|
import { createControllerTools } from "./src/controller/controller-tools.js";
|
|
15
15
|
import { publishWorkerRepo, syncWorkerRepo } from "./src/git-collaboration.js";
|
|
16
|
+
import { installRecommendedSkills } from "./src/worker/skill-installer.js";
|
|
16
17
|
|
|
17
|
-
|
|
18
|
+
export default definePluginEntry({
|
|
18
19
|
id: "teamclaw",
|
|
19
20
|
name: "TeamClaw",
|
|
20
21
|
description:
|
|
21
22
|
"Virtual team collaboration - multiple OpenClaw instances form a virtual software company with role-based task routing.",
|
|
22
|
-
configSchema: buildConfigSchema
|
|
23
|
+
configSchema: buildConfigSchema,
|
|
23
24
|
register(api: OpenClawPluginApi) {
|
|
24
25
|
const config = parsePluginConfig(api.pluginConfig as Record<string, unknown>);
|
|
25
|
-
const logger = api.logger;
|
|
26
26
|
|
|
27
27
|
if (config.mode === "controller") {
|
|
28
28
|
registerController(api, config);
|
|
@@ -30,9 +30,7 @@ const plugin = {
|
|
|
30
30
|
registerWorker(api, config);
|
|
31
31
|
}
|
|
32
32
|
},
|
|
33
|
-
};
|
|
34
|
-
|
|
35
|
-
export default plugin;
|
|
33
|
+
});
|
|
36
34
|
|
|
37
35
|
function registerController(api: OpenClawPluginApi, config: ReturnType<typeof parsePluginConfig>) {
|
|
38
36
|
const logger = api.logger;
|
|
@@ -146,6 +144,25 @@ function registerWorker(api: OpenClawPluginApi, config: ReturnType<typeof parseP
|
|
|
146
144
|
currentWorkerId = identity.workerId;
|
|
147
145
|
},
|
|
148
146
|
prepareTaskAssignment: async (assignment) => {
|
|
147
|
+
if (assignment.recommendedSkills?.length) {
|
|
148
|
+
try {
|
|
149
|
+
const skillInstall = await installRecommendedSkills(assignment, logger);
|
|
150
|
+
for (const event of skillInstall.events) {
|
|
151
|
+
await reportExecutionEvent(assignment.taskId, event);
|
|
152
|
+
}
|
|
153
|
+
} catch (err) {
|
|
154
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
155
|
+
await reportExecutionEvent(assignment.taskId, {
|
|
156
|
+
type: "error",
|
|
157
|
+
phase: "skills_preflight_failed",
|
|
158
|
+
source: "worker",
|
|
159
|
+
status: "running",
|
|
160
|
+
message,
|
|
161
|
+
});
|
|
162
|
+
logger.warn(`Worker: skill preflight failed for ${assignment.taskId}: ${message}`);
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
|
|
149
166
|
if (!assignment.repo?.enabled || !currentControllerUrl) {
|
|
150
167
|
return;
|
|
151
168
|
}
|
package/openclaw.plugin.json
CHANGED
|
@@ -1,13 +1,151 @@
|
|
|
1
1
|
{
|
|
2
2
|
"id": "teamclaw",
|
|
3
3
|
"name": "TeamClaw",
|
|
4
|
-
"description": "Virtual team collaboration
|
|
4
|
+
"description": "Virtual team collaboration - multiple OpenClaw instances form a virtual software company with role-based task routing.",
|
|
5
|
+
"version": "2026.3.25",
|
|
6
|
+
"uiHints": {
|
|
7
|
+
"mode": {
|
|
8
|
+
"label": "Mode",
|
|
9
|
+
"help": "controller manages the team, worker executes tasks"
|
|
10
|
+
},
|
|
11
|
+
"port": {
|
|
12
|
+
"label": "Port",
|
|
13
|
+
"help": "HTTP server port for this instance"
|
|
14
|
+
},
|
|
15
|
+
"role": {
|
|
16
|
+
"label": "Role",
|
|
17
|
+
"help": "Worker role (worker mode only)"
|
|
18
|
+
},
|
|
19
|
+
"controllerUrl": {
|
|
20
|
+
"label": "Controller URL",
|
|
21
|
+
"help": "Manual fallback if mDNS discovery fails"
|
|
22
|
+
},
|
|
23
|
+
"teamName": {
|
|
24
|
+
"label": "Team Name",
|
|
25
|
+
"help": "Team identifier for mDNS"
|
|
26
|
+
},
|
|
27
|
+
"heartbeatIntervalMs": {
|
|
28
|
+
"label": "Heartbeat Interval",
|
|
29
|
+
"help": "In milliseconds, minimum 1000"
|
|
30
|
+
},
|
|
31
|
+
"taskTimeoutMs": {
|
|
32
|
+
"label": "Task Timeout",
|
|
33
|
+
"help": "Maximum time to wait for a role task to finish before marking it failed (in milliseconds)"
|
|
34
|
+
},
|
|
35
|
+
"gitEnabled": {
|
|
36
|
+
"label": "Git Collaboration",
|
|
37
|
+
"help": "Enable automatic git-backed workspace bootstrapping and worker repo sync"
|
|
38
|
+
},
|
|
39
|
+
"gitRemoteUrl": {
|
|
40
|
+
"label": "Git Remote URL",
|
|
41
|
+
"help": "Optional remote repository URL; when empty, distributed workers use controller-hosted git bundles"
|
|
42
|
+
},
|
|
43
|
+
"gitDefaultBranch": {
|
|
44
|
+
"label": "Git Default Branch",
|
|
45
|
+
"help": "Default branch name for the TeamClaw workspace repository"
|
|
46
|
+
},
|
|
47
|
+
"gitAuthorName": {
|
|
48
|
+
"label": "Git Author Name",
|
|
49
|
+
"help": "Author name for TeamClaw-managed workspace commits"
|
|
50
|
+
},
|
|
51
|
+
"gitAuthorEmail": {
|
|
52
|
+
"label": "Git Author Email",
|
|
53
|
+
"help": "Author email for TeamClaw-managed workspace commits"
|
|
54
|
+
},
|
|
55
|
+
"localRoles": {
|
|
56
|
+
"label": "Local Roles",
|
|
57
|
+
"help": "Controller mode only: run these roles as local virtual workers inside the same OpenClaw instance"
|
|
58
|
+
},
|
|
59
|
+
"workerProvisioningType": {
|
|
60
|
+
"label": "On-demand Worker Provider",
|
|
61
|
+
"help": "Launch missing workers on demand using process, Docker, or Kubernetes"
|
|
62
|
+
},
|
|
63
|
+
"workerProvisioningControllerUrl": {
|
|
64
|
+
"label": "Provisioned Worker Controller URL",
|
|
65
|
+
"help": "URL that launched workers use to call back into the controller"
|
|
66
|
+
},
|
|
67
|
+
"workerProvisioningRoles": {
|
|
68
|
+
"label": "Provisioned Roles",
|
|
69
|
+
"help": "Only launch these roles on demand; leave empty for all roles"
|
|
70
|
+
},
|
|
71
|
+
"workerProvisioningMinPerRole": {
|
|
72
|
+
"label": "Warm Workers Per Role",
|
|
73
|
+
"help": "Minimum idle workers to keep warm per role"
|
|
74
|
+
},
|
|
75
|
+
"workerProvisioningMaxPerRole": {
|
|
76
|
+
"label": "Max Workers Per Role",
|
|
77
|
+
"help": "Maximum concurrent on-demand workers per role"
|
|
78
|
+
},
|
|
79
|
+
"workerProvisioningIdleTtlMs": {
|
|
80
|
+
"label": "Idle TTL",
|
|
81
|
+
"help": "Terminate an idle provisioned worker after this many milliseconds"
|
|
82
|
+
},
|
|
83
|
+
"workerProvisioningStartupTimeoutMs": {
|
|
84
|
+
"label": "Startup Timeout",
|
|
85
|
+
"help": "Fail a launch if the worker does not register in time"
|
|
86
|
+
},
|
|
87
|
+
"workerProvisioningImage": {
|
|
88
|
+
"label": "Provisioning Image",
|
|
89
|
+
"help": "Container image for docker/kubernetes provisioners"
|
|
90
|
+
},
|
|
91
|
+
"workerProvisioningPassEnv": {
|
|
92
|
+
"label": "Pass-through Env",
|
|
93
|
+
"help": "Environment variable names copied from controller to provisioned workers"
|
|
94
|
+
},
|
|
95
|
+
"workerProvisioningExtraEnv": {
|
|
96
|
+
"label": "Extra Env",
|
|
97
|
+
"help": "Static environment variables injected into provisioned workers"
|
|
98
|
+
},
|
|
99
|
+
"workerProvisioningDockerNetwork": {
|
|
100
|
+
"label": "Docker Network",
|
|
101
|
+
"help": "Optional Docker network for launched worker containers"
|
|
102
|
+
},
|
|
103
|
+
"workerProvisioningDockerMounts": {
|
|
104
|
+
"label": "Docker Mounts",
|
|
105
|
+
"help": "Optional Docker bind mounts for launched worker containers"
|
|
106
|
+
},
|
|
107
|
+
"workerProvisioningWorkspaceRoot": {
|
|
108
|
+
"label": "Workspace Root",
|
|
109
|
+
"help": "Optional persistent workspace root path inside docker/kubernetes workers; defaults to /workspace-root when persistence is configured"
|
|
110
|
+
},
|
|
111
|
+
"workerProvisioningDockerWorkspaceVolume": {
|
|
112
|
+
"label": "Docker Workspace Volume",
|
|
113
|
+
"help": "Optional Docker named volume or host path mounted as the persistent workspace root"
|
|
114
|
+
},
|
|
115
|
+
"workerProvisioningKubernetesNamespace": {
|
|
116
|
+
"label": "Kubernetes Namespace",
|
|
117
|
+
"help": "Namespace for launched worker pods"
|
|
118
|
+
},
|
|
119
|
+
"workerProvisioningKubernetesContext": {
|
|
120
|
+
"label": "Kubernetes Context",
|
|
121
|
+
"help": "Optional kubectl context for the Kubernetes provider"
|
|
122
|
+
},
|
|
123
|
+
"workerProvisioningKubernetesServiceAccount": {
|
|
124
|
+
"label": "Kubernetes Service Account",
|
|
125
|
+
"help": "Optional service account for launched worker pods"
|
|
126
|
+
},
|
|
127
|
+
"workerProvisioningKubernetesWorkspacePersistentVolumeClaim": {
|
|
128
|
+
"label": "Kubernetes Workspace PVC",
|
|
129
|
+
"help": "Optional PVC mounted as the persistent workspace root for launched worker pods"
|
|
130
|
+
},
|
|
131
|
+
"workerProvisioningKubernetesLabels": {
|
|
132
|
+
"label": "Kubernetes Labels",
|
|
133
|
+
"help": "Extra labels applied to launched worker pods"
|
|
134
|
+
},
|
|
135
|
+
"workerProvisioningKubernetesAnnotations": {
|
|
136
|
+
"label": "Kubernetes Annotations",
|
|
137
|
+
"help": "Extra annotations applied to launched worker pods"
|
|
138
|
+
}
|
|
139
|
+
},
|
|
5
140
|
"configSchema": {
|
|
6
141
|
"type": "object",
|
|
7
142
|
"properties": {
|
|
8
143
|
"mode": {
|
|
9
144
|
"type": "string",
|
|
10
|
-
"enum": [
|
|
145
|
+
"enum": [
|
|
146
|
+
"controller",
|
|
147
|
+
"worker"
|
|
148
|
+
],
|
|
11
149
|
"default": "worker",
|
|
12
150
|
"description": "Plugin mode: controller manages the team, worker executes tasks"
|
|
13
151
|
},
|
|
@@ -35,6 +173,192 @@
|
|
|
35
173
|
"type": "number",
|
|
36
174
|
"default": 10000,
|
|
37
175
|
"description": "Heartbeat interval in milliseconds"
|
|
176
|
+
},
|
|
177
|
+
"taskTimeoutMs": {
|
|
178
|
+
"type": "number",
|
|
179
|
+
"default": 1800000,
|
|
180
|
+
"description": "Maximum time in milliseconds to wait for a role task to finish"
|
|
181
|
+
},
|
|
182
|
+
"gitEnabled": {
|
|
183
|
+
"type": "boolean",
|
|
184
|
+
"default": true,
|
|
185
|
+
"description": "Enable TeamClaw git-backed workspace collaboration"
|
|
186
|
+
},
|
|
187
|
+
"gitRemoteUrl": {
|
|
188
|
+
"type": "string",
|
|
189
|
+
"default": "",
|
|
190
|
+
"description": "Optional remote repository URL for distributed worker clone/pull/push"
|
|
191
|
+
},
|
|
192
|
+
"gitDefaultBranch": {
|
|
193
|
+
"type": "string",
|
|
194
|
+
"default": "main",
|
|
195
|
+
"description": "Default branch name for the shared TeamClaw workspace repository"
|
|
196
|
+
},
|
|
197
|
+
"gitAuthorName": {
|
|
198
|
+
"type": "string",
|
|
199
|
+
"default": "TeamClaw",
|
|
200
|
+
"description": "Git author name used for TeamClaw-managed workspace commits"
|
|
201
|
+
},
|
|
202
|
+
"gitAuthorEmail": {
|
|
203
|
+
"type": "string",
|
|
204
|
+
"default": "teamclaw@local",
|
|
205
|
+
"description": "Git author email used for TeamClaw-managed workspace commits"
|
|
206
|
+
},
|
|
207
|
+
"localRoles": {
|
|
208
|
+
"type": "array",
|
|
209
|
+
"default": [],
|
|
210
|
+
"description": "Controller-local roles executed in this same OpenClaw instance",
|
|
211
|
+
"items": {
|
|
212
|
+
"type": "string",
|
|
213
|
+
"enum": [
|
|
214
|
+
"pm",
|
|
215
|
+
"architect",
|
|
216
|
+
"developer",
|
|
217
|
+
"qa",
|
|
218
|
+
"release-engineer",
|
|
219
|
+
"infra-engineer",
|
|
220
|
+
"devops",
|
|
221
|
+
"security-engineer",
|
|
222
|
+
"designer",
|
|
223
|
+
"marketing"
|
|
224
|
+
]
|
|
225
|
+
}
|
|
226
|
+
},
|
|
227
|
+
"workerProvisioningType": {
|
|
228
|
+
"type": "string",
|
|
229
|
+
"enum": [
|
|
230
|
+
"none",
|
|
231
|
+
"process",
|
|
232
|
+
"docker",
|
|
233
|
+
"kubernetes"
|
|
234
|
+
],
|
|
235
|
+
"default": "none",
|
|
236
|
+
"description": "Controller-only on-demand worker launch backend"
|
|
237
|
+
},
|
|
238
|
+
"workerProvisioningControllerUrl": {
|
|
239
|
+
"type": "string",
|
|
240
|
+
"default": "",
|
|
241
|
+
"description": "Controller URL injected into provisioned workers; required for docker/kubernetes"
|
|
242
|
+
},
|
|
243
|
+
"workerProvisioningRoles": {
|
|
244
|
+
"type": "array",
|
|
245
|
+
"default": [],
|
|
246
|
+
"description": "Restrict on-demand launches to specific roles; empty means all roles",
|
|
247
|
+
"items": {
|
|
248
|
+
"type": "string",
|
|
249
|
+
"enum": [
|
|
250
|
+
"pm",
|
|
251
|
+
"architect",
|
|
252
|
+
"developer",
|
|
253
|
+
"qa",
|
|
254
|
+
"release-engineer",
|
|
255
|
+
"infra-engineer",
|
|
256
|
+
"devops",
|
|
257
|
+
"security-engineer",
|
|
258
|
+
"designer",
|
|
259
|
+
"marketing"
|
|
260
|
+
]
|
|
261
|
+
}
|
|
262
|
+
},
|
|
263
|
+
"workerProvisioningMinPerRole": {
|
|
264
|
+
"type": "number",
|
|
265
|
+
"default": 0,
|
|
266
|
+
"description": "Minimum number of ready workers to keep warm per role"
|
|
267
|
+
},
|
|
268
|
+
"workerProvisioningMaxPerRole": {
|
|
269
|
+
"type": "number",
|
|
270
|
+
"default": 1,
|
|
271
|
+
"description": "Maximum on-demand workers to launch per role"
|
|
272
|
+
},
|
|
273
|
+
"workerProvisioningIdleTtlMs": {
|
|
274
|
+
"type": "number",
|
|
275
|
+
"default": 120000,
|
|
276
|
+
"description": "Terminate provisioned idle workers after this many milliseconds"
|
|
277
|
+
},
|
|
278
|
+
"workerProvisioningStartupTimeoutMs": {
|
|
279
|
+
"type": "number",
|
|
280
|
+
"default": 120000,
|
|
281
|
+
"description": "Fail a launch if the worker does not register within this many milliseconds"
|
|
282
|
+
},
|
|
283
|
+
"workerProvisioningImage": {
|
|
284
|
+
"type": "string",
|
|
285
|
+
"default": "ghcr.io/topcheer/teamclaw-openclaw:latest",
|
|
286
|
+
"description": "Container image used by docker/kubernetes provisioners"
|
|
287
|
+
},
|
|
288
|
+
"workerProvisioningPassEnv": {
|
|
289
|
+
"type": "array",
|
|
290
|
+
"default": [],
|
|
291
|
+
"description": "Environment variable names copied from the controller into provisioned workers",
|
|
292
|
+
"items": {
|
|
293
|
+
"type": "string"
|
|
294
|
+
}
|
|
295
|
+
},
|
|
296
|
+
"workerProvisioningExtraEnv": {
|
|
297
|
+
"type": "object",
|
|
298
|
+
"default": {},
|
|
299
|
+
"description": "Extra environment variables injected into provisioned workers",
|
|
300
|
+
"additionalProperties": {
|
|
301
|
+
"type": "string"
|
|
302
|
+
}
|
|
303
|
+
},
|
|
304
|
+
"workerProvisioningDockerNetwork": {
|
|
305
|
+
"type": "string",
|
|
306
|
+
"default": "",
|
|
307
|
+
"description": "Optional Docker network name for launched worker containers"
|
|
308
|
+
},
|
|
309
|
+
"workerProvisioningDockerMounts": {
|
|
310
|
+
"type": "array",
|
|
311
|
+
"default": [],
|
|
312
|
+
"description": "Optional Docker bind mounts for launched worker containers",
|
|
313
|
+
"items": {
|
|
314
|
+
"type": "string"
|
|
315
|
+
}
|
|
316
|
+
},
|
|
317
|
+
"workerProvisioningWorkspaceRoot": {
|
|
318
|
+
"type": "string",
|
|
319
|
+
"default": "",
|
|
320
|
+
"description": "Optional persistent workspace root path inside docker/kubernetes workers; defaults to /workspace-root when a Docker volume or PVC is configured"
|
|
321
|
+
},
|
|
322
|
+
"workerProvisioningDockerWorkspaceVolume": {
|
|
323
|
+
"type": "string",
|
|
324
|
+
"default": "",
|
|
325
|
+
"description": "Optional Docker named volume or host path mounted as the persistent workspace root"
|
|
326
|
+
},
|
|
327
|
+
"workerProvisioningKubernetesNamespace": {
|
|
328
|
+
"type": "string",
|
|
329
|
+
"default": "default",
|
|
330
|
+
"description": "Kubernetes namespace for launched worker pods"
|
|
331
|
+
},
|
|
332
|
+
"workerProvisioningKubernetesContext": {
|
|
333
|
+
"type": "string",
|
|
334
|
+
"default": "",
|
|
335
|
+
"description": "Optional kubectl context used by the Kubernetes provisioner"
|
|
336
|
+
},
|
|
337
|
+
"workerProvisioningKubernetesServiceAccount": {
|
|
338
|
+
"type": "string",
|
|
339
|
+
"default": "",
|
|
340
|
+
"description": "Optional service account name for launched worker pods"
|
|
341
|
+
},
|
|
342
|
+
"workerProvisioningKubernetesWorkspacePersistentVolumeClaim": {
|
|
343
|
+
"type": "string",
|
|
344
|
+
"default": "",
|
|
345
|
+
"description": "Optional PVC mounted as the persistent workspace root for launched worker pods"
|
|
346
|
+
},
|
|
347
|
+
"workerProvisioningKubernetesLabels": {
|
|
348
|
+
"type": "object",
|
|
349
|
+
"default": {},
|
|
350
|
+
"description": "Extra labels applied to launched worker pods",
|
|
351
|
+
"additionalProperties": {
|
|
352
|
+
"type": "string"
|
|
353
|
+
}
|
|
354
|
+
},
|
|
355
|
+
"workerProvisioningKubernetesAnnotations": {
|
|
356
|
+
"type": "object",
|
|
357
|
+
"default": {},
|
|
358
|
+
"description": "Extra annotations applied to launched worker pods",
|
|
359
|
+
"additionalProperties": {
|
|
360
|
+
"type": "string"
|
|
361
|
+
}
|
|
38
362
|
}
|
|
39
363
|
}
|
|
40
364
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@teamclaws/teamclaw",
|
|
3
|
-
"version": "2026.3.
|
|
3
|
+
"version": "2026.3.25",
|
|
4
4
|
"description": "OpenClaw virtual software team orchestration plugin",
|
|
5
5
|
"private": false,
|
|
6
6
|
"keywords": [
|
|
@@ -20,9 +20,13 @@
|
|
|
20
20
|
"directory": "src"
|
|
21
21
|
},
|
|
22
22
|
"type": "module",
|
|
23
|
+
"bin": {
|
|
24
|
+
"teamclaw": "./cli.mjs"
|
|
25
|
+
},
|
|
23
26
|
"files": [
|
|
24
27
|
"README.md",
|
|
25
28
|
"api.ts",
|
|
29
|
+
"cli.mjs",
|
|
26
30
|
"index.ts",
|
|
27
31
|
"openclaw.plugin.json",
|
|
28
32
|
"src/",
|
|
@@ -36,19 +40,12 @@
|
|
|
36
40
|
"@sinclair/typebox": "0.34.48",
|
|
37
41
|
"bonjour-service": "^1.3.0",
|
|
38
42
|
"json5": "^2.2.3",
|
|
43
|
+
"openclaw": "2026.3.23-2",
|
|
39
44
|
"ws": "^8.19.0"
|
|
40
45
|
},
|
|
41
46
|
"devDependencies": {
|
|
42
47
|
"typescript": "^5.9.0"
|
|
43
48
|
},
|
|
44
|
-
"peerDependencies": {
|
|
45
|
-
"openclaw": ">=2026.3.14"
|
|
46
|
-
},
|
|
47
|
-
"peerDependenciesMeta": {
|
|
48
|
-
"openclaw": {
|
|
49
|
-
"optional": true
|
|
50
|
-
}
|
|
51
|
-
},
|
|
52
49
|
"publishConfig": {
|
|
53
50
|
"access": "public"
|
|
54
51
|
},
|
package/src/config.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { PluginConfig } from "./types.js";
|
|
2
2
|
import { parsePluginConfig } from "./types.js";
|
|
3
3
|
import { ROLE_IDS } from "./roles.js";
|
|
4
|
+
import { TEAMCLAW_PUBLISHED_RUNTIME_IMAGE } from "./install-defaults.js";
|
|
4
5
|
|
|
5
6
|
function buildConfigSchema() {
|
|
6
7
|
return {
|
|
@@ -119,7 +120,7 @@ function buildConfigSchema() {
|
|
|
119
120
|
},
|
|
120
121
|
workerProvisioningImage: {
|
|
121
122
|
type: "string" as const,
|
|
122
|
-
default:
|
|
123
|
+
default: TEAMCLAW_PUBLISHED_RUNTIME_IMAGE,
|
|
123
124
|
description: "Container image used by docker/kubernetes provisioners",
|
|
124
125
|
},
|
|
125
126
|
workerProvisioningPassEnv: {
|
|
@@ -151,6 +152,16 @@ function buildConfigSchema() {
|
|
|
151
152
|
type: "string" as const,
|
|
152
153
|
},
|
|
153
154
|
},
|
|
155
|
+
workerProvisioningWorkspaceRoot: {
|
|
156
|
+
type: "string" as const,
|
|
157
|
+
default: "",
|
|
158
|
+
description: "Optional persistent workspace root path inside docker/kubernetes workers; defaults to /workspace-root when a Docker volume or PVC is configured",
|
|
159
|
+
},
|
|
160
|
+
workerProvisioningDockerWorkspaceVolume: {
|
|
161
|
+
type: "string" as const,
|
|
162
|
+
default: "",
|
|
163
|
+
description: "Optional Docker named volume or host path mounted as the persistent workspace root",
|
|
164
|
+
},
|
|
154
165
|
workerProvisioningKubernetesNamespace: {
|
|
155
166
|
type: "string" as const,
|
|
156
167
|
default: "default",
|
|
@@ -166,6 +177,11 @@ function buildConfigSchema() {
|
|
|
166
177
|
default: "",
|
|
167
178
|
description: "Optional service account name for launched worker pods",
|
|
168
179
|
},
|
|
180
|
+
workerProvisioningKubernetesWorkspacePersistentVolumeClaim: {
|
|
181
|
+
type: "string" as const,
|
|
182
|
+
default: "",
|
|
183
|
+
description: "Optional PVC mounted as the persistent workspace root for launched worker pods",
|
|
184
|
+
},
|
|
169
185
|
workerProvisioningKubernetesLabels: {
|
|
170
186
|
type: "object" as const,
|
|
171
187
|
default: {},
|
|
@@ -267,6 +283,14 @@ function buildConfigSchema() {
|
|
|
267
283
|
label: "Docker Mounts",
|
|
268
284
|
help: "Optional Docker bind mounts for launched worker containers",
|
|
269
285
|
},
|
|
286
|
+
workerProvisioningWorkspaceRoot: {
|
|
287
|
+
label: "Workspace Root",
|
|
288
|
+
help: "Optional persistent workspace root path inside docker/kubernetes workers; defaults to /workspace-root when persistence is configured",
|
|
289
|
+
},
|
|
290
|
+
workerProvisioningDockerWorkspaceVolume: {
|
|
291
|
+
label: "Docker Workspace Volume",
|
|
292
|
+
help: "Optional Docker named volume or host path mounted as the persistent workspace root",
|
|
293
|
+
},
|
|
270
294
|
workerProvisioningKubernetesNamespace: {
|
|
271
295
|
label: "Kubernetes Namespace",
|
|
272
296
|
help: "Namespace for launched worker pods",
|
|
@@ -279,6 +303,10 @@ function buildConfigSchema() {
|
|
|
279
303
|
label: "Kubernetes Service Account",
|
|
280
304
|
help: "Optional service account for launched worker pods",
|
|
281
305
|
},
|
|
306
|
+
workerProvisioningKubernetesWorkspacePersistentVolumeClaim: {
|
|
307
|
+
label: "Kubernetes Workspace PVC",
|
|
308
|
+
help: "Optional PVC mounted as the persistent workspace root for launched worker pods",
|
|
309
|
+
},
|
|
282
310
|
workerProvisioningKubernetesLabels: {
|
|
283
311
|
label: "Kubernetes Labels",
|
|
284
312
|
help: "Extra labels applied to launched worker pods",
|
|
@@ -31,6 +31,13 @@ export function createControllerTools(deps: ControllerToolsDeps) {
|
|
|
31
31
|
description: Type.String({ description: "Execution-ready task description with scope, expected deliverable, constraints, resolved clarifications, and no unmet predecessor dependency" }),
|
|
32
32
|
priority: Type.Optional(Type.String({ description: "Priority: low, medium, high, critical" })),
|
|
33
33
|
assignedRole: Type.Optional(Type.String({ description: "Exact target role ID (pm, architect, developer, qa, release-engineer, infra-engineer, devops, security-engineer, designer, marketing)" })),
|
|
34
|
+
recommendedSkills: Type.Optional(
|
|
35
|
+
Type.Array(
|
|
36
|
+
Type.String({
|
|
37
|
+
description: "Exact OpenClaw/ClawHub skill slug when known; otherwise a short skill-discovery query",
|
|
38
|
+
}),
|
|
39
|
+
),
|
|
40
|
+
),
|
|
34
41
|
}),
|
|
35
42
|
async execute(_id: string, params: Record<string, unknown>) {
|
|
36
43
|
const title = String(params.title ?? "");
|
|
@@ -58,6 +65,7 @@ export function createControllerTools(deps: ControllerToolsDeps) {
|
|
|
58
65
|
description,
|
|
59
66
|
priority: params.priority ?? "medium",
|
|
60
67
|
assignedRole: params.assignedRole ?? undefined,
|
|
68
|
+
recommendedSkills: Array.isArray(params.recommendedSkills) ? params.recommendedSkills : undefined,
|
|
61
69
|
createdBy: "controller",
|
|
62
70
|
}),
|
|
63
71
|
});
|
|
@@ -74,11 +82,14 @@ export function createControllerTools(deps: ControllerToolsDeps) {
|
|
|
74
82
|
: task.status === "pending"
|
|
75
83
|
? " (pending - no available worker)"
|
|
76
84
|
: "";
|
|
85
|
+
const recommended = Array.isArray(task.recommendedSkills) && task.recommendedSkills.length > 0
|
|
86
|
+
? ` | skills: ${task.recommendedSkills.join(", ")}`
|
|
87
|
+
: "";
|
|
77
88
|
|
|
78
89
|
return {
|
|
79
90
|
content: [{
|
|
80
91
|
type: "text" as const,
|
|
81
|
-
text: `Task created: ${task.title} [${task.id}] [${task.priority}]${assigned}`,
|
|
92
|
+
text: `Task created: ${task.title} [${task.id}] [${task.priority}]${assigned}${recommended}`,
|
|
82
93
|
}],
|
|
83
94
|
};
|
|
84
95
|
} catch (err) {
|