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