@teamclaws/teamclaw 2026.3.26-2 → 2026.4.2-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.
Files changed (46) hide show
  1. package/README.md +52 -8
  2. package/cli.mjs +538 -224
  3. package/index.ts +76 -27
  4. package/openclaw.plugin.json +53 -28
  5. package/package.json +5 -2
  6. package/skills/teamclaw/SKILL.md +213 -0
  7. package/skills/teamclaw/references/api-quick-ref.md +117 -0
  8. package/skills/teamclaw-setup/SKILL.md +81 -0
  9. package/skills/teamclaw-setup/references/install-modes.md +136 -0
  10. package/skills/teamclaw-setup/references/validation-checklist.md +73 -0
  11. package/src/config.ts +44 -16
  12. package/src/controller/controller-capacity.ts +2 -2
  13. package/src/controller/controller-service.ts +193 -47
  14. package/src/controller/controller-tools.ts +102 -2
  15. package/src/controller/delivery-report.ts +563 -0
  16. package/src/controller/http-server.ts +1907 -172
  17. package/src/controller/kickoff-orchestrator.ts +292 -0
  18. package/src/controller/managed-gateway-process.ts +330 -0
  19. package/src/controller/orchestration-manifest.ts +69 -1
  20. package/src/controller/preview-manager.ts +676 -0
  21. package/src/controller/prompt-injector.ts +116 -67
  22. package/src/controller/role-inference.ts +41 -0
  23. package/src/controller/websocket.ts +3 -1
  24. package/src/controller/worker-provisioning.ts +429 -74
  25. package/src/discovery.ts +1 -1
  26. package/src/git-collaboration.ts +198 -47
  27. package/src/identity.ts +12 -2
  28. package/src/interaction-contracts.ts +179 -3
  29. package/src/networking.ts +99 -0
  30. package/src/openclaw-workspace.ts +478 -11
  31. package/src/prompt-policy.ts +381 -0
  32. package/src/roles.ts +37 -36
  33. package/src/state.ts +40 -1
  34. package/src/task-executor.ts +282 -78
  35. package/src/types.ts +150 -7
  36. package/src/ui/app.js +1403 -175
  37. package/src/ui/assets/teamclaw-app-icon.png +0 -0
  38. package/src/ui/index.html +122 -40
  39. package/src/ui/style.css +829 -143
  40. package/src/worker/http-handler.ts +40 -4
  41. package/src/worker/prompt-injector.ts +9 -38
  42. package/src/worker/skill-installer.ts +2 -2
  43. package/src/worker/tools.ts +31 -5
  44. package/src/worker/worker-service.ts +49 -8
  45. package/src/workspace-browser.ts +20 -7
  46. package/src/controller/local-worker-manager.ts +0 -533
package/src/types.ts CHANGED
@@ -23,6 +23,10 @@ export type GitSyncMode = "shared" | "bundle" | "remote";
23
23
 
24
24
  export type WorkerProvisioningType = "none" | "process" | "docker" | "kubernetes";
25
25
 
26
+ export type ProcessModel = "multi";
27
+
28
+ export type AgentIsolationMode = "independent" | "main";
29
+
26
30
  export type ProvisionedWorkerStatus =
27
31
  | "launching"
28
32
  | "registered"
@@ -30,6 +34,11 @@ export type ProvisionedWorkerStatus =
30
34
  | "terminated"
31
35
  | "failed";
32
36
 
37
+ export type ProvisioningReadinessStatus =
38
+ | "checking"
39
+ | "ready"
40
+ | "degraded";
41
+
33
42
  export type GitRepoState = {
34
43
  enabled: boolean;
35
44
  mode: GitSyncMode;
@@ -82,7 +91,7 @@ export type WorkerInfo = {
82
91
  role: RoleId;
83
92
  label: string;
84
93
  status: WorkerStatus;
85
- transport?: "http" | "local";
94
+ transport?: "http";
86
95
  url: string;
87
96
  lastHeartbeat: number;
88
97
  capabilities: string[];
@@ -101,6 +110,7 @@ export type TaskInfo = {
101
110
  createdBy: string;
102
111
  recommendedSkills?: string[];
103
112
  controllerSessionKey?: string;
113
+ projectDir?: string;
104
114
  createdAt: number;
105
115
  updatedAt: number;
106
116
  startedAt?: number;
@@ -133,6 +143,7 @@ export type TaskAssignmentPayload = {
133
143
  description: string;
134
144
  priority?: TaskPriority;
135
145
  recommendedSkills?: string[];
146
+ projectDir?: string;
136
147
  executionSessionKey?: string;
137
148
  executionIdempotencyKey?: string;
138
149
  repo?: RepoSyncInfo;
@@ -146,6 +157,29 @@ export type WorkerTaskResultDeliverable = {
146
157
  kind: "file" | "directory" | "command" | "artifact" | "note";
147
158
  value: string;
148
159
  summary?: string;
160
+ artifactType?: "web-app" | "static-site" | "rest-api" | "binary" | "document";
161
+ previewCommand?: string;
162
+ previewCwd?: string;
163
+ previewReadyPath?: string;
164
+ liveUrl?: string;
165
+ };
166
+
167
+ export type DynamicPreviewRecord = {
168
+ id: string;
169
+ taskId: string;
170
+ deliverableIndex: number;
171
+ deliverableValue: string;
172
+ targetPort: number;
173
+ previewCommand: string;
174
+ previewCwd: string;
175
+ previewReadyPath: string;
176
+ liveUrl: string;
177
+ status: "launching" | "starting" | "healthy" | "stopped" | "failed";
178
+ pid?: number;
179
+ createdAt: number;
180
+ updatedAt: number;
181
+ lastHealthCheckAt?: number;
182
+ lastError?: string;
149
183
  };
150
184
 
151
185
  export type WorkerTaskResultFollowUp = {
@@ -164,6 +198,8 @@ export type WorkerTaskResultContract = {
164
198
  followUps: WorkerTaskResultFollowUp[];
165
199
  questions: string[];
166
200
  notes?: string;
201
+ /** Reusable codebase patterns discovered during this task (consolidated into workspace memory). */
202
+ discoveredPatterns?: string[];
167
203
  };
168
204
 
169
205
  export type WorkerProgressContract = {
@@ -204,6 +240,27 @@ export type TeamMessageContract = {
204
240
  references: string[];
205
241
  };
206
242
 
243
+ export type KickoffAssessment = {
244
+ role: RoleId;
245
+ needed: boolean;
246
+ scope: string;
247
+ suggestedTasks: string[];
248
+ dependencies: string[];
249
+ risks: string[];
250
+ questions: string[];
251
+ };
252
+
253
+ export type KickoffPlan = {
254
+ /** Complexity level determined by controller's initial analysis. */
255
+ complexity: "simple" | "medium" | "complex";
256
+ /** Roles invited to the kickoff meeting. */
257
+ candidateRoles: RoleId[];
258
+ /** Collected assessments from each role (populated after kickoff). */
259
+ assessments: KickoffAssessment[];
260
+ /** Whether the kickoff phase has completed. */
261
+ completed: boolean;
262
+ };
263
+
207
264
  export type ControllerManifestCreatedTask = {
208
265
  title: string;
209
266
  assignedRole?: RoleId;
@@ -217,16 +274,45 @@ export type ControllerManifestDeferredTask = {
217
274
  whenReady: string;
218
275
  };
219
276
 
277
+ export type ClarificationQuestionKind = "single-select" | "multi-select" | "number" | "text";
278
+
279
+ export type ClarificationQuestionOption = {
280
+ value: string;
281
+ label: string;
282
+ hint?: string;
283
+ };
284
+
285
+ export type ClarificationQuestionSchema = {
286
+ kind: ClarificationQuestionKind;
287
+ title: string;
288
+ description?: string;
289
+ required?: boolean;
290
+ options?: ClarificationQuestionOption[];
291
+ allowOther?: boolean;
292
+ placeholder?: string;
293
+ unit?: string;
294
+ min?: number;
295
+ max?: number;
296
+ step?: number;
297
+ };
298
+
220
299
  export type ControllerOrchestrationManifest = {
221
300
  version: string;
301
+ /** Short, filesystem-safe project name chosen by the controller (e.g. "todo-rest-api", "stripe-payment-integration"). */
302
+ projectName?: string;
222
303
  requirementSummary: string;
223
304
  requiredRoles: RoleId[];
224
305
  clarificationsNeeded: boolean;
225
306
  clarificationQuestions: string[];
307
+ clarificationSchemas?: ClarificationQuestionSchema[];
226
308
  createdTasks: ControllerManifestCreatedTask[];
227
309
  deferredTasks: ControllerManifestDeferredTask[];
228
310
  handoffPlan?: string;
229
311
  notes?: string;
312
+ /** Controller signals that the entire human requirement is fully satisfied — no more tasks or follow-ups needed. */
313
+ requirementFullyComplete?: boolean;
314
+ /** Team kickoff plan — populated when controller uses collaborative planning. */
315
+ kickoffPlan?: KickoffPlan;
230
316
  };
231
317
 
232
318
  export type ControllerRunInfo = {
@@ -240,6 +326,7 @@ export type ControllerRunInfo = {
240
326
  request: string;
241
327
  reply?: string;
242
328
  error?: string;
329
+ projectDir?: string;
243
330
  createdTaskIds: string[];
244
331
  manifest?: ControllerOrchestrationManifest;
245
332
  status: TaskExecutionStatus;
@@ -289,14 +376,21 @@ export type ClarificationStatus = "pending" | "answered";
289
376
  export type ClarificationRequest = {
290
377
  id: string;
291
378
  taskId: string;
379
+ controllerRunId?: string;
380
+ controllerSessionKey?: string;
292
381
  requestedBy: string;
293
382
  requestedByWorkerId?: string;
294
383
  requestedByRole?: RoleId;
295
384
  question: string;
385
+ questionSchema?: ClarificationQuestionSchema;
296
386
  blockingReason: string;
297
387
  context?: string;
298
388
  status: ClarificationStatus;
299
389
  answer?: string;
390
+ answerValue?: string;
391
+ answerValues?: string[];
392
+ answerNumber?: number;
393
+ answerComment?: string;
300
394
  answeredBy?: string;
301
395
  createdAt: number;
302
396
  updatedAt: number;
@@ -332,8 +426,19 @@ export type ProvisionedWorkerRecord = {
332
426
  lastError?: string;
333
427
  };
334
428
 
429
+ export type StartupProvisioningReadiness = {
430
+ status: ProvisioningReadinessStatus;
431
+ startedAt: number;
432
+ checkedAt: number;
433
+ attempts: number;
434
+ requiredRoles: RoleId[];
435
+ readyWorkerIds: string[];
436
+ message?: string;
437
+ };
438
+
335
439
  export type TeamProvisioningState = {
336
440
  workers: Record<string, ProvisionedWorkerRecord>;
441
+ startupReadiness?: StartupProvisioningReadiness;
337
442
  };
338
443
 
339
444
  export type PluginConfig = {
@@ -343,14 +448,16 @@ export type PluginConfig = {
343
448
  controllerUrl: string;
344
449
  teamName: string;
345
450
  heartbeatIntervalMs: number;
346
- localRoles: RoleId[];
451
+ processModel: ProcessModel;
347
452
  taskTimeoutMs: number;
348
453
  gitEnabled: boolean;
349
454
  gitRemoteUrl: string;
350
455
  gitDefaultBranch: string;
351
456
  gitAuthorName: string;
352
457
  gitAuthorEmail: string;
458
+ agentIsolationMode: AgentIsolationMode;
353
459
  workerProvisioningType: WorkerProvisioningType;
460
+ workerProvisioningDisabled: boolean;
354
461
  workerProvisioningControllerUrl: string;
355
462
  workerProvisioningRoles: RoleId[];
356
463
  workerProvisioningMinPerRole: number;
@@ -367,6 +474,7 @@ export type PluginConfig = {
367
474
  workerProvisioningKubernetesNamespace: string;
368
475
  workerProvisioningKubernetesContext: string;
369
476
  workerProvisioningKubernetesServiceAccount: string;
477
+ workerProvisioningKubernetesImagePullSecrets: string[];
370
478
  workerProvisioningKubernetesWorkspacePersistentVolumeClaim: string;
371
479
  workerProvisioningKubernetesLabels: Record<string, string>;
372
480
  workerProvisioningKubernetesAnnotations: Record<string, string>;
@@ -388,10 +496,24 @@ export type TeamState = {
388
496
  clarifications: Record<string, ClarificationRequest>;
389
497
  repo?: GitRepoState;
390
498
  provisioning?: TeamProvisioningState;
499
+ previews?: Record<string, DynamicPreviewRecord>;
500
+ reports?: Record<string, DeliveryReportRecord>;
391
501
  createdAt: number;
392
502
  updatedAt: number;
393
503
  };
394
504
 
505
+ export type DeliveryReportRecord = {
506
+ id: string;
507
+ sessionKey: string;
508
+ generatedAt: number;
509
+ projectName: string;
510
+ requirementSummary: string;
511
+ status: "completed" | "partial" | "failed";
512
+ taskCount: number;
513
+ deliverableCount: number;
514
+ previewCount: number;
515
+ };
516
+
395
517
  export type DiscoveryResult = {
396
518
  name: string;
397
519
  host: string;
@@ -434,13 +556,13 @@ export function parsePluginConfig(raw: Record<string, unknown> = {}): PluginConf
434
556
 
435
557
  const teamName = typeof raw.teamName === "string" && raw.teamName.trim()
436
558
  ? raw.teamName.trim()
437
- : "default";
559
+ : "TeamClaw";
438
560
 
439
561
  const heartbeatIntervalMs = typeof raw.heartbeatIntervalMs === "number" && raw.heartbeatIntervalMs >= 1000
440
562
  ? raw.heartbeatIntervalMs
441
563
  : 10000;
442
564
 
443
- const localRoles = parseRoleList(raw.localRoles);
565
+ const processModel: ProcessModel = "multi";
444
566
 
445
567
  const taskTimeoutMs = typeof raw.taskTimeoutMs === "number" && raw.taskTimeoutMs >= 1000
446
568
  ? raw.taskTimeoutMs
@@ -464,7 +586,24 @@ export function parsePluginConfig(raw: Record<string, unknown> = {}): PluginConf
464
586
  ? raw.gitAuthorEmail.trim()
465
587
  : "teamclaw@local";
466
588
 
467
- const workerProvisioningType = parseProvisioningType(raw.workerProvisioningType);
589
+ const agentIsolationMode: AgentIsolationMode =
590
+ typeof raw.agentIsolationMode === "string" && (raw.agentIsolationMode === "independent" || raw.agentIsolationMode === "main")
591
+ ? raw.agentIsolationMode
592
+ : "independent";
593
+
594
+ const rawWorkerProvisioningType = parseProvisioningType(raw.workerProvisioningType);
595
+ const workerProvisioningDisabled = raw.workerProvisioningDisabled === true;
596
+ // Legacy local installs often persisted workerProvisioningType="none" without
597
+ // distinguishing "manual/no provisioning" from "same-host local controller".
598
+ // Keep an explicit escape hatch via workerProvisioningDisabled, but otherwise
599
+ // default multi-process controllers back to process provisioning.
600
+ const workerProvisioningType: WorkerProvisioningType =
601
+ mode === "controller" &&
602
+ rawWorkerProvisioningType === "none" &&
603
+ processModel === "multi" &&
604
+ !workerProvisioningDisabled
605
+ ? "process"
606
+ : rawWorkerProvisioningType;
468
607
  const workerProvisioningControllerUrl = typeof raw.workerProvisioningControllerUrl === "string"
469
608
  ? raw.workerProvisioningControllerUrl.trim()
470
609
  : "";
@@ -474,7 +613,7 @@ export function parsePluginConfig(raw: Record<string, unknown> = {}): PluginConf
474
613
  : 0;
475
614
  const rawProvisioningMaxPerRole = typeof raw.workerProvisioningMaxPerRole === "number" && raw.workerProvisioningMaxPerRole >= 1
476
615
  ? Math.floor(raw.workerProvisioningMaxPerRole)
477
- : 1;
616
+ : 3;
478
617
  const workerProvisioningMaxPerRole = Math.max(rawProvisioningMaxPerRole, workerProvisioningMinPerRole);
479
618
  const workerProvisioningIdleTtlMs = typeof raw.workerProvisioningIdleTtlMs === "number" && raw.workerProvisioningIdleTtlMs >= 1000
480
619
  ? raw.workerProvisioningIdleTtlMs
@@ -512,6 +651,7 @@ export function parsePluginConfig(raw: Record<string, unknown> = {}): PluginConf
512
651
  const workerProvisioningKubernetesServiceAccount = typeof raw.workerProvisioningKubernetesServiceAccount === "string"
513
652
  ? raw.workerProvisioningKubernetesServiceAccount.trim()
514
653
  : "";
654
+ const workerProvisioningKubernetesImagePullSecrets = parseStringArray(raw.workerProvisioningKubernetesImagePullSecrets);
515
655
  const workerProvisioningKubernetesWorkspacePersistentVolumeClaim =
516
656
  typeof raw.workerProvisioningKubernetesWorkspacePersistentVolumeClaim === "string"
517
657
  ? raw.workerProvisioningKubernetesWorkspacePersistentVolumeClaim.trim()
@@ -530,14 +670,16 @@ export function parsePluginConfig(raw: Record<string, unknown> = {}): PluginConf
530
670
  controllerUrl,
531
671
  teamName,
532
672
  heartbeatIntervalMs,
533
- localRoles,
673
+ processModel,
534
674
  taskTimeoutMs,
535
675
  gitEnabled,
536
676
  gitRemoteUrl,
537
677
  gitDefaultBranch,
538
678
  gitAuthorName,
539
679
  gitAuthorEmail,
680
+ agentIsolationMode,
540
681
  workerProvisioningType,
682
+ workerProvisioningDisabled,
541
683
  workerProvisioningControllerUrl,
542
684
  workerProvisioningRoles,
543
685
  workerProvisioningMinPerRole,
@@ -554,6 +696,7 @@ export function parsePluginConfig(raw: Record<string, unknown> = {}): PluginConf
554
696
  workerProvisioningKubernetesNamespace,
555
697
  workerProvisioningKubernetesContext,
556
698
  workerProvisioningKubernetesServiceAccount,
699
+ workerProvisioningKubernetesImagePullSecrets,
557
700
  workerProvisioningKubernetesWorkspacePersistentVolumeClaim,
558
701
  workerProvisioningKubernetesLabels,
559
702
  workerProvisioningKubernetesAnnotations,