ofiere-openclaw-plugin 4.7.0 → 4.8.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.
Files changed (2) hide show
  1. package/package.json +1 -1
  2. package/src/tools.ts +58 -16
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ofiere-openclaw-plugin",
3
- "version": "4.7.0",
3
+ "version": "4.8.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
@@ -190,7 +190,8 @@ function registerTaskOps(
190
190
  description:
191
191
  `Manage tasks in the Ofiere PM dashboard. All task operations go through this tool.\n\n` +
192
192
  `Actions:\n` +
193
- `- "list": List/filter tasks. Optional: status, agent_id, space_id, folder_id, limit\n` +
193
+ `- "list": List/filter tasks. Optional: status, agent_id, space_id, folder_id, task_id, limit\n` +
194
+ `- "get": Get a single task by ID. Required: task_id\n` +
194
195
  `- "create": Create a task. Required: title. Optional: agent_id, description, status, priority, space_id, folder_id, start_date, due_date, tags, instructions, execution_plan, goals, constraints, system_prompt, recurrence_type, recurrence_interval, scheduled_time\n` +
195
196
  `- "update": Update a task. Required: task_id. Optional: all create fields + progress\n` +
196
197
  `- "delete": Delete task + subtasks. Required: task_id\n\n` +
@@ -212,6 +213,10 @@ function registerTaskOps(
212
213
  title: { type: "string", description: "Task title (required for create)" },
213
214
  description: { type: "string", description: "Task description" },
214
215
  instructions: { type: "string", description: "Detailed instructions for the agent executing this task" },
216
+ task_id: {
217
+ type: "string",
218
+ description: "Task ID — use with 'list' to filter or 'get' to fetch a single task",
219
+ },
215
220
  agent_id: {
216
221
  type: "string",
217
222
  description: "Agent name or ID. Your name to self-assign, 'none' for unassigned.",
@@ -284,6 +289,9 @@ function registerTaskOps(
284
289
  switch (action) {
285
290
  case "list":
286
291
  return handleListTasks(supabase, userId, params);
292
+ case "get":
293
+ if (!params.task_id) return err("Missing required field: task_id");
294
+ return handleListTasks(supabase, userId, { ...params, limit: 1 });
287
295
  case "create":
288
296
  return handleCreateTask(supabase, userId, resolveAgent, params);
289
297
  case "update":
@@ -292,7 +300,7 @@ function registerTaskOps(
292
300
  return handleDeleteTask(supabase, userId, params);
293
301
  default:
294
302
  return err(
295
- `Unknown action "${action}". Valid actions: list, create, update, delete`,
303
+ `Unknown action "${action}". Valid actions: list, get, create, update, delete`,
296
304
  );
297
305
  }
298
306
  },
@@ -316,6 +324,7 @@ async function handleListTasks(
316
324
  .eq("user_id", userId)
317
325
  .order("updated_at", { ascending: false });
318
326
 
327
+ if (params.task_id) query = query.eq("id", params.task_id as string);
319
328
  if (params.space_id) query = query.eq("space_id", params.space_id as string);
320
329
  if (params.folder_id) query = query.eq("folder_id", params.folder_id as string);
321
330
  if (params.agent_id) query = query.eq("agent_id", params.agent_id as string);
@@ -600,33 +609,45 @@ async function handleUpdateTask(
600
609
  const mergedCf = { ...existingCf };
601
610
 
602
611
  if (params.execution_plan !== undefined) {
603
- mergedCf.execution_plan = Array.isArray(params.execution_plan)
612
+ const existingSteps = (existingCf.execution_plan || []) as any[];
613
+ const newSteps = Array.isArray(params.execution_plan)
604
614
  ? (params.execution_plan as any[]).map((step: any, i: number) => ({
605
615
  id: step.id || `step-${Date.now()}-${i}`,
606
616
  text: typeof step === "string" ? step : step.text || String(step),
607
- order: i,
617
+ order: existingSteps.length + i,
608
618
  }))
609
619
  : [];
620
+ // Merge: concat existing + new, dedup by id
621
+ const stepIds = new Set(existingSteps.map((s: any) => s.id));
622
+ mergedCf.execution_plan = [...existingSteps, ...newSteps.filter((s: any) => !stepIds.has(s.id))];
610
623
  }
611
624
 
612
625
  if (params.goals !== undefined) {
613
- mergedCf.goals = Array.isArray(params.goals)
626
+ const existingGoals = (existingCf.goals || []) as any[];
627
+ const newGoals = Array.isArray(params.goals)
614
628
  ? (params.goals as any[]).map((g: any, i: number) => ({
615
629
  id: g.id || `goal-${Date.now()}-${i}`,
616
630
  type: g.type || "custom",
617
631
  label: typeof g === "string" ? g : g.label || String(g),
618
632
  }))
619
633
  : [];
634
+ // Merge: concat existing + new, dedup by id
635
+ const goalIds = new Set(existingGoals.map((g: any) => g.id));
636
+ mergedCf.goals = [...existingGoals, ...newGoals.filter((g: any) => !goalIds.has(g.id))];
620
637
  }
621
638
 
622
639
  if (params.constraints !== undefined) {
623
- mergedCf.constraints = Array.isArray(params.constraints)
640
+ const existingConstraints = (existingCf.constraints || []) as any[];
641
+ const newConstraints = Array.isArray(params.constraints)
624
642
  ? (params.constraints as any[]).map((c: any, i: number) => ({
625
643
  id: c.id || `cstr-${Date.now()}-${i}`,
626
644
  type: c.type || "custom",
627
645
  label: typeof c === "string" ? c : c.label || String(c),
628
646
  }))
629
647
  : [];
648
+ // Merge: concat existing + new, dedup by id
649
+ const cstrIds = new Set(existingConstraints.map((c: any) => c.id));
650
+ mergedCf.constraints = [...existingConstraints, ...newConstraints.filter((c: any) => !cstrIds.has(c.id))];
630
651
  }
631
652
 
632
653
  if (params.system_prompt !== undefined) mergedCf.system_prompt = params.system_prompt;
@@ -753,15 +774,6 @@ async function handleListAgents(
753
774
  fallbackAgentId: string,
754
775
  ): Promise<ToolResult> {
755
776
  try {
756
- // Resolve calling agent's ID for the "your_agent_id" hint
757
- const callerName = getCallingAgentName(api);
758
- let yourAgentId = fallbackAgentId || "";
759
- if (callerName && !yourAgentId) {
760
- try {
761
- yourAgentId = await resolveAgentId(callerName, userId, supabase);
762
- } catch { /* ignore */ }
763
- }
764
-
765
777
  const { data, error } = await supabase
766
778
  .from("agents")
767
779
  .select("id, name, codename, role, status")
@@ -769,10 +781,40 @@ async function handleListAgents(
769
781
  .order("name");
770
782
 
771
783
  if (error) return err(error.message);
784
+
785
+ // BUG 1 fix: resolve your_agent_id to the agent NAME (e.g. "celia")
786
+ // so callers can use it directly for task assignment.
787
+ // Previous behavior returned an internal UUID/auto-generated ID that
788
+ // didn't match any assignable agent in the list.
789
+ let yourAgentName: string | null = null;
790
+
791
+ // Try fallbackAgentId first (env var OFIERE_AGENT_ID)
792
+ if (fallbackAgentId) {
793
+ // If fallback is a UUID, find the matching agent name
794
+ const match = (data || []).find((a: any) => a.id === fallbackAgentId);
795
+ yourAgentName = match?.name || null;
796
+ }
797
+
798
+ // Try runtime detection
799
+ if (!yourAgentName) {
800
+ const callerName = getCallingAgentName(api);
801
+ if (callerName && !isSystemName(callerName)) {
802
+ // Check if callerName matches any agent name (case-insensitive)
803
+ const match = (data || []).find(
804
+ (a: any) => a.name?.toLowerCase() === callerName.toLowerCase() ||
805
+ a.codename?.toLowerCase() === callerName.toLowerCase()
806
+ );
807
+ yourAgentName = match?.name || null;
808
+ }
809
+ }
810
+
772
811
  return ok({
773
812
  agents: data || [],
774
813
  count: (data || []).length,
775
- your_agent_id: yourAgentId,
814
+ your_agent_id: yourAgentName,
815
+ hint: !yourAgentName
816
+ ? "Could not auto-detect your agent. Use an agent name from the list above (e.g. 'celia') when creating tasks."
817
+ : undefined,
776
818
  });
777
819
  } catch (e) {
778
820
  return err(e instanceof Error ? e.message : String(e));