openclaw-remote 0.2.1 → 0.3.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.js +218 -20
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -2746,6 +2746,43 @@ async function getHeartbeat(account) {
|
|
|
2746
2746
|
}
|
|
2747
2747
|
);
|
|
2748
2748
|
}
|
|
2749
|
+
async function listRoles(account) {
|
|
2750
|
+
return apiFetch(
|
|
2751
|
+
buildUrl(account, "/api/v1/roles"),
|
|
2752
|
+
{
|
|
2753
|
+
method: "GET",
|
|
2754
|
+
headers: buildHeaders(account)
|
|
2755
|
+
}
|
|
2756
|
+
);
|
|
2757
|
+
}
|
|
2758
|
+
async function listEpics(account) {
|
|
2759
|
+
return apiFetch(
|
|
2760
|
+
buildUrl(account, "/api/v1/epics"),
|
|
2761
|
+
{
|
|
2762
|
+
method: "GET",
|
|
2763
|
+
headers: buildHeaders(account)
|
|
2764
|
+
}
|
|
2765
|
+
);
|
|
2766
|
+
}
|
|
2767
|
+
async function createEpic(account, epic) {
|
|
2768
|
+
return apiFetch(
|
|
2769
|
+
buildUrl(account, "/api/v1/epics"),
|
|
2770
|
+
{
|
|
2771
|
+
method: "POST",
|
|
2772
|
+
headers: buildHeaders(account),
|
|
2773
|
+
body: JSON.stringify(epic)
|
|
2774
|
+
}
|
|
2775
|
+
);
|
|
2776
|
+
}
|
|
2777
|
+
async function getBoardHealth(account) {
|
|
2778
|
+
return apiFetch(
|
|
2779
|
+
buildUrl(account, "/api/v1/board/health"),
|
|
2780
|
+
{
|
|
2781
|
+
method: "GET",
|
|
2782
|
+
headers: buildHeaders(account)
|
|
2783
|
+
}
|
|
2784
|
+
);
|
|
2785
|
+
}
|
|
2749
2786
|
|
|
2750
2787
|
// src/realtime-listener.ts
|
|
2751
2788
|
import { createClient } from "@supabase/supabase-js";
|
|
@@ -3205,6 +3242,9 @@ function createRemotePlugin() {
|
|
|
3205
3242
|
}),
|
|
3206
3243
|
assigned_role_id: Type.Optional(
|
|
3207
3244
|
Type.String({ description: "Role ID to assign the task to" })
|
|
3245
|
+
),
|
|
3246
|
+
epic_id: Type.Optional(
|
|
3247
|
+
Type.String({ description: "Epic ID to group the task under" })
|
|
3208
3248
|
)
|
|
3209
3249
|
}),
|
|
3210
3250
|
execute: async (_toolCallId, args) => {
|
|
@@ -3214,7 +3254,8 @@ function createRemotePlugin() {
|
|
|
3214
3254
|
description: args.description,
|
|
3215
3255
|
type: args.type,
|
|
3216
3256
|
priority: args.priority,
|
|
3217
|
-
assigned_role_id: args.assigned_role_id
|
|
3257
|
+
assigned_role_id: args.assigned_role_id,
|
|
3258
|
+
epic_id: args.epic_id
|
|
3218
3259
|
});
|
|
3219
3260
|
if (!result.ok) {
|
|
3220
3261
|
return {
|
|
@@ -3241,7 +3282,7 @@ function createRemotePlugin() {
|
|
|
3241
3282
|
{
|
|
3242
3283
|
name: "remote_update_task",
|
|
3243
3284
|
label: "Update a task on the Remote project board",
|
|
3244
|
-
description: "Update an existing task on the Remote project board. Specify the task_id and any fields to change: status (todo/in_progress/review/done), priority, assigned_to, title, or
|
|
3285
|
+
description: "Update an existing task on the Remote project board. Specify the task_id and any fields to change: status (todo/in_progress/review/done), priority, assigned_to, title, description, type, epic_id, or assigned_role_id.",
|
|
3245
3286
|
parameters: Type.Object({
|
|
3246
3287
|
task_id: Type.String({ description: "ID of the task to update" }),
|
|
3247
3288
|
status: optionalStringEnum(["todo", "in_progress", "review", "done"], {
|
|
@@ -3254,7 +3295,16 @@ function createRemotePlugin() {
|
|
|
3254
3295
|
Type.String({ description: "User or role to assign the task to" })
|
|
3255
3296
|
),
|
|
3256
3297
|
title: Type.Optional(Type.String({ description: "New task title" })),
|
|
3257
|
-
description: Type.Optional(Type.String({ description: "New task description" }))
|
|
3298
|
+
description: Type.Optional(Type.String({ description: "New task description" })),
|
|
3299
|
+
type: optionalStringEnum(["feature", "task", "bug"], {
|
|
3300
|
+
description: "New type: feature, task, or bug"
|
|
3301
|
+
}),
|
|
3302
|
+
epic_id: Type.Optional(
|
|
3303
|
+
Type.String({ description: "Epic ID to group the task under (or null to remove)" })
|
|
3304
|
+
),
|
|
3305
|
+
assigned_role_id: Type.Optional(
|
|
3306
|
+
Type.String({ description: "Role ID to assign the task to" })
|
|
3307
|
+
)
|
|
3258
3308
|
}),
|
|
3259
3309
|
execute: async (_toolCallId, args) => {
|
|
3260
3310
|
const account = resolveAccount(cfg ?? {});
|
|
@@ -3344,27 +3394,170 @@ function createRemotePlugin() {
|
|
|
3344
3394
|
parameters: Type.Object({}),
|
|
3345
3395
|
execute: async (_toolCallId, _args) => {
|
|
3346
3396
|
const account = resolveAccount(cfg ?? {});
|
|
3347
|
-
const result = await
|
|
3397
|
+
const result = await getBoardHealth(account);
|
|
3348
3398
|
if (!result.ok) {
|
|
3399
|
+
const legacyResult = await getHeartbeat(account);
|
|
3400
|
+
if (!legacyResult.ok) {
|
|
3401
|
+
return {
|
|
3402
|
+
content: [{ type: "text", text: `\u274C Failed to get board health: ${result.error}` }],
|
|
3403
|
+
details: { ok: false, error: result.error }
|
|
3404
|
+
};
|
|
3405
|
+
}
|
|
3406
|
+
const h2 = legacyResult.data;
|
|
3407
|
+
const text = [
|
|
3408
|
+
`\u{1F4CA} **Board Health Summary** (legacy)`,
|
|
3409
|
+
"",
|
|
3410
|
+
`- **Pending tasks**: ${h2.pending_tasks}`,
|
|
3411
|
+
`- **In progress**: ${h2.in_progress_tasks}`,
|
|
3412
|
+
`- **Unassigned**: ${h2.unassigned_tasks}`,
|
|
3413
|
+
`- **Activity (24h)**: ${h2.recent_activity_24h}`,
|
|
3414
|
+
`- **My roles**: ${h2.my_roles?.join(", ") || "none"}`
|
|
3415
|
+
].join("\n");
|
|
3349
3416
|
return {
|
|
3350
|
-
content: [{ type: "text", text
|
|
3351
|
-
details: { ok:
|
|
3417
|
+
content: [{ type: "text", text }],
|
|
3418
|
+
details: { ok: true, heartbeat: h2 }
|
|
3352
3419
|
};
|
|
3353
3420
|
}
|
|
3354
3421
|
const h = result.data;
|
|
3355
|
-
const
|
|
3356
|
-
|
|
3422
|
+
const s = h.stats;
|
|
3423
|
+
const lines = [
|
|
3424
|
+
`\u{1F4CA} **Board Health \u2014 ${h.project.name}**`,
|
|
3357
3425
|
"",
|
|
3358
|
-
|
|
3359
|
-
|
|
3360
|
-
|
|
3361
|
-
|
|
3362
|
-
|
|
3363
|
-
|
|
3364
|
-
|
|
3426
|
+
`**Tasks** (${s.total_tasks} total):`,
|
|
3427
|
+
` todo: ${s.by_status.todo} | in_progress: ${s.by_status.in_progress} | review: ${s.by_status.review} | done: ${s.by_status.done}`,
|
|
3428
|
+
` unassigned: ${s.unassigned}`,
|
|
3429
|
+
"",
|
|
3430
|
+
`**By priority**: urgent: ${s.by_priority.urgent} | high: ${s.by_priority.high} | medium: ${s.by_priority.medium} | low: ${s.by_priority.low}`
|
|
3431
|
+
];
|
|
3432
|
+
if (h.epics.length > 0) {
|
|
3433
|
+
lines.push("", "**Epics**:");
|
|
3434
|
+
for (const e of h.epics) {
|
|
3435
|
+
lines.push(` - ${e.name} (${e.task_count} tasks)`);
|
|
3436
|
+
}
|
|
3437
|
+
}
|
|
3438
|
+
if (h.roles.length > 0) {
|
|
3439
|
+
lines.push("", "**Roles**:");
|
|
3440
|
+
for (const r of h.roles) {
|
|
3441
|
+
const assignee = r.assigned_to ? `${r.assigned_to.type}: ${r.assigned_to.name}` : "vacant";
|
|
3442
|
+
lines.push(` - ${r.name} [${r.category}] \u2192 ${assignee}`);
|
|
3443
|
+
}
|
|
3444
|
+
}
|
|
3445
|
+
if (h.recent_activity.length > 0) {
|
|
3446
|
+
lines.push("", `**Recent activity** (last ${h.recent_activity.length}):`);
|
|
3447
|
+
for (const a of h.recent_activity.slice(0, 5)) {
|
|
3448
|
+
const meta = a.metadata;
|
|
3449
|
+
lines.push(` - ${a.action}: ${meta?.title || a.target_id} (${a.actor_type})`);
|
|
3450
|
+
}
|
|
3451
|
+
}
|
|
3452
|
+
return {
|
|
3453
|
+
content: [{ type: "text", text: lines.join("\n") }],
|
|
3454
|
+
details: { ok: true, health: h }
|
|
3455
|
+
};
|
|
3456
|
+
}
|
|
3457
|
+
},
|
|
3458
|
+
// 5. remote_list_roles
|
|
3459
|
+
{
|
|
3460
|
+
name: "remote_list_roles",
|
|
3461
|
+
label: "List project roles",
|
|
3462
|
+
description: "List project roles with assignment info. Use to find valid assigned_role_id values for task creation.",
|
|
3463
|
+
parameters: Type.Object({}),
|
|
3464
|
+
execute: async (_toolCallId, _args) => {
|
|
3465
|
+
const account = resolveAccount(cfg ?? {});
|
|
3466
|
+
const result = await listRoles(account);
|
|
3467
|
+
if (!result.ok) {
|
|
3468
|
+
return {
|
|
3469
|
+
content: [{ type: "text", text: `\u274C Failed to list roles: ${result.error}` }],
|
|
3470
|
+
details: { ok: false, error: result.error }
|
|
3471
|
+
};
|
|
3472
|
+
}
|
|
3473
|
+
const roles = result.data.roles;
|
|
3474
|
+
if (roles.length === 0) {
|
|
3475
|
+
return {
|
|
3476
|
+
content: [{ type: "text", text: "\u{1F4CB} No roles configured for this project." }],
|
|
3477
|
+
details: { ok: true, roles: [] }
|
|
3478
|
+
};
|
|
3479
|
+
}
|
|
3480
|
+
const lines = [`\u{1F465} **${roles.length} role(s):**`, ""];
|
|
3481
|
+
for (const r of roles) {
|
|
3482
|
+
const assignee = r.assigned_to ? `${r.assigned_to.type}: ${r.assigned_to.name}` : "\u{1F534} vacant";
|
|
3483
|
+
const mine = r.is_mine ? " \u2B50" : "";
|
|
3484
|
+
lines.push(`- **${r.name}** [${r.category}] \u2192 ${assignee}${mine} (id: ${r.id})`);
|
|
3485
|
+
}
|
|
3486
|
+
return {
|
|
3487
|
+
content: [{ type: "text", text: lines.join("\n") }],
|
|
3488
|
+
details: { ok: true, roles }
|
|
3489
|
+
};
|
|
3490
|
+
}
|
|
3491
|
+
},
|
|
3492
|
+
// 6. remote_list_epics
|
|
3493
|
+
{
|
|
3494
|
+
name: "remote_list_epics",
|
|
3495
|
+
label: "List epics",
|
|
3496
|
+
description: "List epics for the project. Use to find valid epic_id values for task grouping.",
|
|
3497
|
+
parameters: Type.Object({}),
|
|
3498
|
+
execute: async (_toolCallId, _args) => {
|
|
3499
|
+
const account = resolveAccount(cfg ?? {});
|
|
3500
|
+
const result = await listEpics(account);
|
|
3501
|
+
if (!result.ok) {
|
|
3502
|
+
return {
|
|
3503
|
+
content: [{ type: "text", text: `\u274C Failed to list epics: ${result.error}` }],
|
|
3504
|
+
details: { ok: false, error: result.error }
|
|
3505
|
+
};
|
|
3506
|
+
}
|
|
3507
|
+
const epics = result.data.epics;
|
|
3508
|
+
if (epics.length === 0) {
|
|
3509
|
+
return {
|
|
3510
|
+
content: [{ type: "text", text: "\u{1F4CB} No epics found. Use `remote_create_epic` to create one." }],
|
|
3511
|
+
details: { ok: true, epics: [] }
|
|
3512
|
+
};
|
|
3513
|
+
}
|
|
3514
|
+
const lines = [`\u{1F4E6} **${epics.length} epic(s):**`, ""];
|
|
3515
|
+
for (const e of epics) {
|
|
3516
|
+
lines.push(`- **${e.name}** (${e.task_count ?? 0} tasks) (id: ${e.id})`);
|
|
3517
|
+
if (e.description) {
|
|
3518
|
+
const desc = e.description.length > 80 ? e.description.slice(0, 80) + "\u2026" : e.description;
|
|
3519
|
+
lines.push(` ${desc}`);
|
|
3520
|
+
}
|
|
3521
|
+
}
|
|
3522
|
+
return {
|
|
3523
|
+
content: [{ type: "text", text: lines.join("\n") }],
|
|
3524
|
+
details: { ok: true, epics }
|
|
3525
|
+
};
|
|
3526
|
+
}
|
|
3527
|
+
},
|
|
3528
|
+
// 7. remote_create_epic
|
|
3529
|
+
{
|
|
3530
|
+
name: "remote_create_epic",
|
|
3531
|
+
label: "Create an epic",
|
|
3532
|
+
description: "Create a new epic on the Remote project board. Specify name, and optionally description and color.",
|
|
3533
|
+
parameters: Type.Object({
|
|
3534
|
+
name: Type.String({ description: "Epic name" }),
|
|
3535
|
+
description: Type.Optional(Type.String({ description: "Epic description" })),
|
|
3536
|
+
color: Type.Optional(Type.String({ description: "Epic color (hex, e.g. #6366f1)" }))
|
|
3537
|
+
}),
|
|
3538
|
+
execute: async (_toolCallId, args) => {
|
|
3539
|
+
const account = resolveAccount(cfg ?? {});
|
|
3540
|
+
const result = await createEpic(account, {
|
|
3541
|
+
name: args.name,
|
|
3542
|
+
description: args.description,
|
|
3543
|
+
color: args.color
|
|
3544
|
+
});
|
|
3545
|
+
if (!result.ok) {
|
|
3546
|
+
return {
|
|
3547
|
+
content: [{ type: "text", text: `\u274C Failed to create epic: ${result.error}` }],
|
|
3548
|
+
details: { ok: false, error: result.error }
|
|
3549
|
+
};
|
|
3550
|
+
}
|
|
3551
|
+
const epic = result.data.epic;
|
|
3552
|
+
const text = [
|
|
3553
|
+
`\u2705 Epic created!`,
|
|
3554
|
+
`- **Name**: ${epic.name}`,
|
|
3555
|
+
`- **ID**: ${epic.id}`,
|
|
3556
|
+
epic.color ? `- **Color**: ${epic.color}` : null
|
|
3557
|
+
].filter(Boolean).join("\n");
|
|
3365
3558
|
return {
|
|
3366
3559
|
content: [{ type: "text", text }],
|
|
3367
|
-
details: { ok: true,
|
|
3560
|
+
details: { ok: true, epic }
|
|
3368
3561
|
};
|
|
3369
3562
|
}
|
|
3370
3563
|
}
|
|
@@ -3379,10 +3572,13 @@ function createRemotePlugin() {
|
|
|
3379
3572
|
"**Replying**: When you reply to a task notification, your reply is posted as a comment on that task.",
|
|
3380
3573
|
"",
|
|
3381
3574
|
"**Available tools**:",
|
|
3382
|
-
"- `remote_create_task` \u2014 Create a new task (
|
|
3383
|
-
"- `remote_update_task` \u2014 Update a task (
|
|
3575
|
+
"- `remote_create_task` \u2014 Create a new task (title, type, priority, assigned_role_id, epic_id)",
|
|
3576
|
+
"- `remote_update_task` \u2014 Update a task (status, priority, title, description, type, epic_id, assigned_role_id)",
|
|
3384
3577
|
"- `remote_list_tasks` \u2014 List/filter tasks on the board",
|
|
3385
|
-
"- `remote_board_health` \u2014 Get board health stats (
|
|
3578
|
+
"- `remote_board_health` \u2014 Get board health stats (task counts, epics, roles, recent activity)",
|
|
3579
|
+
"- `remote_list_roles` \u2014 List project roles with vacancy info (find valid assigned_role_id values)",
|
|
3580
|
+
"- `remote_list_epics` \u2014 List epics with task counts (find valid epic_id values)",
|
|
3581
|
+
"- `remote_create_epic` \u2014 Create a new epic (name, description, color)",
|
|
3386
3582
|
"",
|
|
3387
3583
|
"**Task lifecycle**: todo \u2192 in_progress \u2192 review \u2192 done",
|
|
3388
3584
|
"**Task types**: feature, task, bug",
|
|
@@ -3392,7 +3588,9 @@ function createRemotePlugin() {
|
|
|
3392
3588
|
"- When assigned a task, acknowledge it and move to in_progress",
|
|
3393
3589
|
"- Use comments to communicate progress and blockers",
|
|
3394
3590
|
"- Move tasks to review when ready for review, done when complete",
|
|
3395
|
-
"- Keep task descriptions and comments clear and actionable"
|
|
3591
|
+
"- Keep task descriptions and comments clear and actionable",
|
|
3592
|
+
"- Use `remote_list_roles` before creating tasks to find valid role IDs for assignment",
|
|
3593
|
+
"- Use `remote_list_epics` before creating tasks to find valid epic IDs for grouping"
|
|
3396
3594
|
]
|
|
3397
3595
|
}
|
|
3398
3596
|
};
|