ofiere-openclaw-plugin 4.4.1 → 4.6.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/package.json +1 -1
- package/src/tools.ts +90 -9
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ofiere-openclaw-plugin",
|
|
3
|
-
"version": "4.
|
|
3
|
+
"version": "4.6.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "OpenClaw plugin for Ofiere PM - 10 meta-tools with 13-action workflow mastery covering tasks, agents, projects, scheduling, knowledge, workflows, notifications, memory, prompts, and constellation agent architecture",
|
|
6
6
|
"keywords": ["openclaw", "ofiere", "project-management", "agents", "plugin"],
|
package/src/tools.ts
CHANGED
|
@@ -311,7 +311,7 @@ async function handleListTasks(
|
|
|
311
311
|
.from("tasks")
|
|
312
312
|
.select(
|
|
313
313
|
"id, title, description, status, priority, agent_id, space_id, folder_id, " +
|
|
314
|
-
"start_date, due_date, progress, tags, custom_fields, created_at, updated_at",
|
|
314
|
+
"start_date, due_date, progress, tags, custom_fields, completed_at, created_at, updated_at",
|
|
315
315
|
)
|
|
316
316
|
.eq("user_id", userId)
|
|
317
317
|
.order("updated_at", { ascending: false });
|
|
@@ -325,16 +325,27 @@ async function handleListTasks(
|
|
|
325
325
|
const { data, error } = await query;
|
|
326
326
|
if (error) return err(error.message);
|
|
327
327
|
|
|
328
|
-
//
|
|
328
|
+
// BUG 1 fix: normalize legacy statuses to documented enum
|
|
329
|
+
const STATUS_NORMALIZE: Record<string, string> = {
|
|
330
|
+
NEW: "PENDING",
|
|
331
|
+
COMPLETED: "DONE",
|
|
332
|
+
CANCELLED: "FAILED",
|
|
333
|
+
};
|
|
334
|
+
|
|
335
|
+
// Unpack custom_fields for readability, then strip raw custom_fields (BUG 9)
|
|
329
336
|
const tasks = (data || []).map((t: any) => {
|
|
330
337
|
const cf = t.custom_fields || {};
|
|
338
|
+
const normalizedStatus = STATUS_NORMALIZE[t.status] || t.status;
|
|
339
|
+
const { custom_fields: _cf, ...rest } = t;
|
|
331
340
|
return {
|
|
332
|
-
...
|
|
341
|
+
...rest,
|
|
342
|
+
status: normalizedStatus,
|
|
333
343
|
execution_plan: cf.execution_plan || undefined,
|
|
334
344
|
goals: cf.goals || undefined,
|
|
335
345
|
constraints: cf.constraints || undefined,
|
|
336
346
|
system_prompt: cf.system_prompt || undefined,
|
|
337
|
-
instructions: cf.instructions ||
|
|
347
|
+
instructions: cf.instructions || undefined,
|
|
348
|
+
completed_at: t.completed_at || undefined,
|
|
338
349
|
};
|
|
339
350
|
});
|
|
340
351
|
|
|
@@ -515,14 +526,24 @@ async function handleCreateTask(
|
|
|
515
526
|
if (cf.goals) extras.push(`${(cf.goals as any[]).length} goals`);
|
|
516
527
|
if (cf.constraints) extras.push(`${(cf.constraints as any[]).length} constraints`);
|
|
517
528
|
if (cf.system_prompt) extras.push("custom system prompt");
|
|
518
|
-
|
|
529
|
+
|
|
530
|
+
// BUG 6 fix: surface recurrence fields in create response
|
|
531
|
+
const recurrenceInfo = (params.recurrence_type && params.recurrence_type !== "none")
|
|
532
|
+
? { recurrence_type: params.recurrence_type, recurrence_interval: (params.recurrence_interval as number) || 1 }
|
|
533
|
+
: undefined;
|
|
534
|
+
|
|
535
|
+
// BUG 7 fix: only claim scheduling when bridge actually fired
|
|
536
|
+
const didSchedule = !!(startDate && effectiveAgentId);
|
|
537
|
+
if (didSchedule) extras.push(`scheduled for ${startDate}`);
|
|
538
|
+
|
|
519
539
|
const extrasStr = extras.length > 0 ? ` with ${extras.join(", ")}` : "";
|
|
520
540
|
|
|
521
541
|
return ok({
|
|
522
542
|
id,
|
|
523
543
|
message: `Task "${params.title}" created and assigned to ${assignee || "no one"}${extrasStr}`,
|
|
524
544
|
task: insertData,
|
|
525
|
-
scheduledExecution:
|
|
545
|
+
scheduledExecution: didSchedule ? `Will auto-execute on ${startDate}` : undefined,
|
|
546
|
+
recurrence: recurrenceInfo,
|
|
526
547
|
});
|
|
527
548
|
} catch (e) {
|
|
528
549
|
return err(e instanceof Error ? e.message : String(e));
|
|
@@ -614,16 +635,30 @@ async function handleUpdateTask(
|
|
|
614
635
|
updates.custom_fields = mergedCf;
|
|
615
636
|
}
|
|
616
637
|
|
|
638
|
+
// BUG 2+4 fix: return ALL mutable fields including custom_fields and completed_at
|
|
617
639
|
const { data, error } = await supabase
|
|
618
640
|
.from("tasks")
|
|
619
641
|
.update(updates)
|
|
620
642
|
.eq("id", params.task_id as string)
|
|
621
643
|
.eq("user_id", userId)
|
|
622
|
-
.select("id, title, status, priority, agent_id, start_date, due_date, progress, updated_at")
|
|
644
|
+
.select("id, title, description, status, priority, agent_id, space_id, folder_id, start_date, due_date, progress, tags, custom_fields, completed_at, updated_at")
|
|
623
645
|
.single();
|
|
624
646
|
|
|
625
647
|
if (error) return err(error.message);
|
|
626
|
-
|
|
648
|
+
|
|
649
|
+
// Unpack custom_fields for readability in response, strip raw (BUG 9 consistency)
|
|
650
|
+
const cf = (data as any)?.custom_fields || {};
|
|
651
|
+
const { custom_fields: _cf, ...rest } = data as any;
|
|
652
|
+
const taskResponse = {
|
|
653
|
+
...rest,
|
|
654
|
+
execution_plan: cf.execution_plan || undefined,
|
|
655
|
+
goals: cf.goals || undefined,
|
|
656
|
+
constraints: cf.constraints || undefined,
|
|
657
|
+
system_prompt: cf.system_prompt || undefined,
|
|
658
|
+
instructions: cf.instructions || undefined,
|
|
659
|
+
};
|
|
660
|
+
|
|
661
|
+
return ok({ message: `Task "${data?.title}" updated`, task: taskResponse });
|
|
627
662
|
} catch (e) {
|
|
628
663
|
return err(e instanceof Error ? e.message : String(e));
|
|
629
664
|
}
|
|
@@ -956,7 +991,7 @@ function registerScheduleOps(
|
|
|
956
991
|
recurrence_type: { type: "string", enum: ["none", "hourly", "daily", "weekly", "monthly"] },
|
|
957
992
|
recurrence_interval: { type: "number", description: "Repeat every N periods" },
|
|
958
993
|
color: { type: "string", description: "Hex color" },
|
|
959
|
-
priority: { type: "number", description: "0-3" },
|
|
994
|
+
priority: { type: ["number", "string"], description: "0-3 (numeric) or 'low'/'medium'/'high'/'critical' (string)" },
|
|
960
995
|
status: { type: "string", enum: ["scheduled", "completed", "cancelled"] },
|
|
961
996
|
},
|
|
962
997
|
},
|
|
@@ -979,6 +1014,21 @@ function registerScheduleOps(
|
|
|
979
1014
|
const priorityMap: Record<string, number> = { low: 0, medium: 1, high: 2, critical: 3 };
|
|
980
1015
|
const pVal = typeof params.priority === "number" ? params.priority
|
|
981
1016
|
: priorityMap[String(params.priority || "").toLowerCase()] ?? 0;
|
|
1017
|
+
|
|
1018
|
+
// Compute next_run_at from scheduled_date + scheduled_time
|
|
1019
|
+
let nextRunAt: number | null = null;
|
|
1020
|
+
try {
|
|
1021
|
+
const dateStr = params.scheduled_date as string;
|
|
1022
|
+
const timeStr = (params.scheduled_time as string) || "09:00";
|
|
1023
|
+
const dt = new Date(`${dateStr}T${timeStr}:00Z`);
|
|
1024
|
+
if (!isNaN(dt.getTime())) {
|
|
1025
|
+
nextRunAt = Math.floor(dt.getTime() / 1000);
|
|
1026
|
+
// If in the past, bump to now + 60s
|
|
1027
|
+
const nowEpoch = Math.floor(Date.now() / 1000);
|
|
1028
|
+
if (nextRunAt <= nowEpoch) nextRunAt = nowEpoch + 60;
|
|
1029
|
+
}
|
|
1030
|
+
} catch { /* non-fatal */ }
|
|
1031
|
+
|
|
982
1032
|
const insertData: Record<string, any> = {
|
|
983
1033
|
id: evtId,
|
|
984
1034
|
user_id: userId,
|
|
@@ -992,6 +1042,7 @@ function registerScheduleOps(
|
|
|
992
1042
|
recurrence_type: (params.recurrence_type as string) || "none",
|
|
993
1043
|
recurrence_interval: (params.recurrence_interval as number) || 1,
|
|
994
1044
|
status: "scheduled",
|
|
1045
|
+
next_run_at: nextRunAt,
|
|
995
1046
|
run_count: 0,
|
|
996
1047
|
color: (params.color as string) || null,
|
|
997
1048
|
priority: pVal,
|
|
@@ -1007,6 +1058,36 @@ function registerScheduleOps(
|
|
|
1007
1058
|
"recurrence_type", "recurrence_interval", "status", "color", "priority", "agent_id"]) {
|
|
1008
1059
|
if ((params as any)[f] !== undefined) upd[f] = (params as any)[f];
|
|
1009
1060
|
}
|
|
1061
|
+
// Map string priority to number if provided
|
|
1062
|
+
if (upd.priority !== undefined && typeof upd.priority === "string") {
|
|
1063
|
+
const pMap: Record<string, number> = { low: 0, medium: 1, high: 2, critical: 3 };
|
|
1064
|
+
upd.priority = pMap[upd.priority.toLowerCase()] ?? 0;
|
|
1065
|
+
}
|
|
1066
|
+
// Recompute next_run_at when date/time/recurrence changes
|
|
1067
|
+
const dateChanged = params.scheduled_date !== undefined || params.scheduled_time !== undefined;
|
|
1068
|
+
const recurrenceChanged = params.recurrence_type !== undefined;
|
|
1069
|
+
if (dateChanged || recurrenceChanged) {
|
|
1070
|
+
try {
|
|
1071
|
+
// Fetch current event to merge with updates
|
|
1072
|
+
const { data: current } = await supabase.from("scheduler_events").select("scheduled_date, scheduled_time, status").eq("id", params.id).single();
|
|
1073
|
+
const effDate = (upd.scheduled_date || current?.scheduled_date) as string;
|
|
1074
|
+
const effTime = (upd.scheduled_time || current?.scheduled_time || "09:00") as string;
|
|
1075
|
+
const effStatus = (upd.status || current?.status) as string;
|
|
1076
|
+
if (effDate && effStatus !== "completed" && effStatus !== "cancelled") {
|
|
1077
|
+
const dt = new Date(`${effDate}T${effTime}:00Z`);
|
|
1078
|
+
if (!isNaN(dt.getTime())) {
|
|
1079
|
+
let nra = Math.floor(dt.getTime() / 1000);
|
|
1080
|
+
const nowEpoch = Math.floor(Date.now() / 1000);
|
|
1081
|
+
if (nra <= nowEpoch) nra = nowEpoch + 60;
|
|
1082
|
+
upd.next_run_at = nra;
|
|
1083
|
+
}
|
|
1084
|
+
}
|
|
1085
|
+
} catch { /* non-fatal */ }
|
|
1086
|
+
}
|
|
1087
|
+
// Clear next_run_at on completion/cancellation
|
|
1088
|
+
if (upd.status === "completed" || upd.status === "cancelled") {
|
|
1089
|
+
upd.next_run_at = null;
|
|
1090
|
+
}
|
|
1010
1091
|
const { error } = await supabase.from("scheduler_events").update(upd).eq("id", params.id);
|
|
1011
1092
|
if (error) return err(error.message);
|
|
1012
1093
|
return ok({ message: "Event updated", ok: true });
|