ofiere-openclaw-plugin 4.20.0 → 4.22.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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ofiere-openclaw-plugin",
3
- "version": "4.20.0",
3
+ "version": "4.22.0",
4
4
  "type": "module",
5
5
  "description": "OpenClaw plugin for Ofiere PM - 13 meta-tools covering tasks, agents, projects, scheduling, knowledge, workflows, notifications, memory, prompts, constellation, space file management, execution plan builder, and SOP management",
6
6
  "keywords": ["openclaw", "ofiere", "project-management", "agents", "plugin"],
package/src/prompt.ts CHANGED
@@ -67,11 +67,11 @@ const TOOL_DOCS: Record<string, string> = {
67
67
  - mark_read: Mark one notification read by ID
68
68
  - mark_all_read: Mark all as read
69
69
  - send_report: Send a PM progress report to YOUR connected channels (Telegram, Discord, Slack, etc.)
70
- - Required: scope_type (space|folder|project|task|all)
70
+ - Required: scope_type (space|folder|project|task|all), agent_id (YOUR name, e.g. "thalia")
71
71
  - Optional: scope_id, channel_types[] (filter to specific channels), include_completed
72
72
  - The report is automatically generated from current PM data and sent through YOUR channel bindings ONLY
73
73
  - schedule_report: Create a recurring/scheduled report
74
- - Required: scope_type, recurrence_type (hourly|daily|weekly|monthly)
74
+ - Required: scope_type, recurrence_type (hourly|daily|weekly|monthly), agent_id (YOUR name)
75
75
  - Optional: scope_id, scope_label, channel_types[], recurrence_time (HH:MM UTC, default 09:00), recurrence_interval, recurrence_days_of_week (e.g. "mon,wed,fri"), include_completed
76
76
  - list_schedules: View all your active report schedules
77
77
  - delete_schedule: Remove a scheduled report by schedule_id`,
@@ -202,8 +202,8 @@ ${toolDocs}
202
202
  - When task instructions or system prompts contain file references like @[filename](file:FILE_ID), use OFIERE_FILE_OPS action:"read_text_file" file_id:"FILE_ID" to read the file content. Do NOT ask the user for the file — retrieve it yourself.
203
203
  - Use OFIERE_FILE_OPS to create output files (reports, data, configs) in the Space Files explorer. Prefer create_text_file for text-based outputs.
204
204
  - To save task output as a file, call OFIERE_FILE_OPS action:"create_text_file" with the space_id from the task context.
205
- - CHANNEL REPORTS: When the user asks you to "send a report", "send progress", "update me on Telegram/Discord/Slack/WhatsApp", use OFIERE_NOTIFY_OPS action:"send_report". The report is generated from live PM data and sent through YOUR connected channels ONLY — not other agents' channels.
206
- - To set up recurring reports (e.g. "send me a daily report at 9am"), use OFIERE_NOTIFY_OPS action:"schedule_report" with scope_type and recurrence_type.
205
+ - CHANNEL REPORTS: When the user asks you to "send a report", "send progress", "update me on Telegram/Discord/Slack/WhatsApp", use OFIERE_NOTIFY_OPS action:"send_report" with agent_id set to YOUR name. ALWAYS include agent_id — without it the report will fail. The report is generated from live PM data and sent through YOUR connected channels ONLY — not other agents' channels.
206
+ - To set up recurring reports (e.g. "send me a daily report at 9am"), use OFIERE_NOTIFY_OPS action:"schedule_report" with scope_type, recurrence_type, and agent_id set to YOUR name.
207
207
  - If a report is too long for the channel's message limit, save the full report as a markdown file using OFIERE_FILE_OPS action:"create_text_file" and send a summary to the channel instead.
208
208
  - PLANNING WORKFLOW: Use OFIERE_PLAN_OPS to build complex multi-step execution flows BEFORE creating individual tasks. Build the plan → let the user review in the Planning Tab → execute when approved.
209
209
  - When creating a plan with nodes, nest children inside each node's children[] array. Sequential children execute in order; set parallel: true on a parent node to fork its children into parallel branches.
package/src/tools.ts CHANGED
@@ -2143,14 +2143,8 @@ function registerNotifyOps(
2143
2143
  api: any,
2144
2144
  supabase: SupabaseClient,
2145
2145
  userId: string,
2146
+ resolveAgent: (explicitId?: string) => Promise<string | null>,
2146
2147
  ): void {
2147
- // Helper: resolve the agent's own ID for agent-scoped operations
2148
- const resolveAgentId = (): string => {
2149
- try {
2150
- const state = api.getState?.() || {};
2151
- return state.agentId || process.env.OFIERE_AGENT_ID || "";
2152
- } catch { return process.env.OFIERE_AGENT_ID || ""; }
2153
- };
2154
2148
 
2155
2149
  api.registerTool({
2156
2150
  name: "OFIERE_NOTIFY_OPS",
@@ -2163,10 +2157,10 @@ function registerNotifyOps(
2163
2157
  `- "mark_all_read": Mark all as read\n` +
2164
2158
  `- "delete": Delete a notification. Required: id\n` +
2165
2159
  `- "send_report": Send a PM progress report to YOUR connected channels (Telegram, Discord, etc.)\n` +
2166
- ` Required: scope_type (space|folder|project|task|all)\n` +
2160
+ ` Required: scope_type (space|folder|project|task|all), agent_id (YOUR name e.g. "thalia")\n` +
2167
2161
  ` Optional: scope_id, channel_types[] (filter specific channels), include_completed (default true)\n` +
2168
2162
  `- "schedule_report": Create a recurring/scheduled report\n` +
2169
- ` Required: scope_type, recurrence_type (hourly|daily|weekly|monthly)\n` +
2163
+ ` Required: scope_type, recurrence_type (hourly|daily|weekly|monthly), agent_id (YOUR name)\n` +
2170
2164
  ` Optional: scope_id, scope_label, channel_types[], recurrence_time (HH:MM UTC, default 09:00),\n` +
2171
2165
  ` recurrence_interval (default 1), recurrence_days_of_week (e.g. "mon,wed,fri"), include_completed\n` +
2172
2166
  `- "list_schedules": List your active report schedules\n` +
@@ -2176,6 +2170,7 @@ function registerNotifyOps(
2176
2170
  required: ["action"],
2177
2171
  properties: {
2178
2172
  action: { type: "string", enum: ["list", "mark_read", "mark_all_read", "delete", "send_report", "schedule_report", "list_schedules", "delete_schedule"] },
2173
+ agent_id: { type: "string", description: "Your agent name or ID (required for send_report/schedule_report)" },
2179
2174
  id: { type: "string", description: "Notification ID" },
2180
2175
  schedule_id: { type: "string", description: "Schedule ID (for delete_schedule)" },
2181
2176
  unread_only: { type: "boolean", description: "Only show unread" },
@@ -2228,8 +2223,8 @@ function registerNotifyOps(
2228
2223
  const scopeId = params.scope_id as string | undefined;
2229
2224
  const channelTypes = (params.channel_types as string[]) || [];
2230
2225
  const includeCompleted = params.include_completed !== false;
2231
- const agentId = resolveAgentId();
2232
- if (!agentId) return err("Cannot resolve your agent ID. Ensure OFIERE_AGENT_ID is configured.");
2226
+ const agentId = await resolveAgent(params.agent_id as string | undefined);
2227
+ if (!agentId) return err("Cannot resolve your agent ID. Pass agent_id with your name (e.g. 'thalia', 'ivy').");
2233
2228
 
2234
2229
  // Call the dashboard API to generate + dispatch
2235
2230
  const supabaseUrl = (supabase as any).supabaseUrl || process.env.OFIERE_SUPABASE_URL || process.env.SUPABASE_URL || "";
@@ -2266,8 +2261,8 @@ function registerNotifyOps(
2266
2261
  case "schedule_report": {
2267
2262
  const scopeType = (params.scope_type as string) || "all";
2268
2263
  const recurrenceType = (params.recurrence_type as string) || "daily";
2269
- const agentId = resolveAgentId();
2270
- if (!agentId) return err("Cannot resolve your agent ID.");
2264
+ const agentId = await resolveAgent(params.agent_id as string | undefined);
2265
+ if (!agentId) return err("Cannot resolve your agent ID. Pass agent_id with your name (e.g. 'thalia', 'ivy').");
2271
2266
 
2272
2267
  const recurrenceTime = (params.recurrence_time as string) || "09:00";
2273
2268
  const recurrenceInterval = (params.recurrence_interval as number) || 1;
@@ -2356,6 +2351,9 @@ async function generatePMReportDirect(
2356
2351
  query = query.eq("project_id", scopeId);
2357
2352
  const { data: p } = await supabase.from("pm_folders").select("name").eq("id", scopeId).single();
2358
2353
  scopeLabel = p?.name || "Project";
2354
+ } else if (scopeType === "task" && scopeId) {
2355
+ query = query.eq("id", scopeId);
2356
+ scopeLabel = "Task Report";
2359
2357
  }
2360
2358
 
2361
2359
  const { data: tasks } = await query.order("priority", { ascending: false }).limit(40);
@@ -2430,7 +2428,7 @@ async function dispatchReportDirect(
2430
2428
  channelTypes: string[],
2431
2429
  ): Promise<{ sent: string[]; failed: string[] }> {
2432
2430
  // Query agent's active channel bindings
2433
- let query = supabase.from("channel_bindings").select("channel_type, channel_account_id, channel_config")
2431
+ let query = supabase.from("channel_bindings").select("channel_type, channel_account_id, agent_id, channel_config")
2434
2432
  .eq("user_id", userId)
2435
2433
  .eq("agent_id", agentId)
2436
2434
  .eq("notifications_enabled", true)
@@ -2449,6 +2447,10 @@ async function dispatchReportDirect(
2449
2447
  const sent: string[] = [];
2450
2448
  const failed: string[] = [];
2451
2449
 
2450
+ // Resolve dashboard URL + auth for sending
2451
+ const dashboardUrl = process.env.OFIERE_DASHBOARD_URL || "https://ofiere.com";
2452
+ const serviceRoleKey = (supabase as any).supabaseKey || process.env.OFIERE_SERVICE_ROLE_KEY || process.env.SUPABASE_SERVICE_ROLE_KEY || "";
2453
+
2452
2454
  for (const b of bindings) {
2453
2455
  const limit = LIMITS[b.channel_type] || 4000;
2454
2456
  let msg = report;
@@ -2456,24 +2458,29 @@ async function dispatchReportDirect(
2456
2458
  msg = msg.substring(0, limit - 80) + "\n\n... [Full report on dashboard]";
2457
2459
  }
2458
2460
 
2459
- // Use the Ofiere dashboard API to send via gateway
2460
- // The dashboard URL is derived from the Supabase URL
2461
- const dashboardUrl = process.env.OFIERE_DASHBOARD_URL || "https://ofiere.com";
2462
- const dispatchSecret = process.env.DISPATCH_SECRET || "";
2461
+ // accountId must match the key used during gateway sync (gatewaySync.ts:435),
2462
+ // which defaults to agentId when channel_account_id is null.
2463
+ const effectiveAccountId = b.channel_account_id || b.agent_id || agentId || "default";
2463
2464
 
2464
2465
  try {
2465
2466
  const res = await fetch(`${dashboardUrl}/api/channels/gateway-send`, {
2466
2467
  method: "POST",
2467
- headers: { "Content-Type": "application/json", "x-dispatch-secret": dispatchSecret },
2468
+ headers: {
2469
+ "Content-Type": "application/json",
2470
+ "Authorization": `Bearer ${serviceRoleKey}`,
2471
+ },
2468
2472
  body: JSON.stringify({
2469
2473
  userId,
2470
2474
  channelType: b.channel_type,
2471
- accountId: b.channel_account_id || null,
2475
+ accountId: effectiveAccountId,
2472
2476
  message: msg,
2473
2477
  }),
2474
2478
  });
2475
2479
  if (res.ok) sent.push(b.channel_type);
2476
- else failed.push(`${b.channel_type}: HTTP ${res.status}`);
2480
+ else {
2481
+ const errText = await res.text().catch(() => "");
2482
+ failed.push(`${b.channel_type}: HTTP ${res.status} ${errText.slice(0, 100)}`);
2483
+ }
2477
2484
  } catch (e: any) {
2478
2485
  failed.push(`${b.channel_type}: ${e.message || "fetch error"}`);
2479
2486
  }
@@ -4869,7 +4876,7 @@ export function registerTools(
4869
4876
  registerScheduleOps(api, supabase, userId); // 4
4870
4877
  registerKnowledgeOps(api, supabase, userId); // 5
4871
4878
  registerWorkflowOps(api, supabase, userId); // 6
4872
- registerNotifyOps(api, supabase, userId); // 7
4879
+ registerNotifyOps(api, supabase, userId, resolveAgent); // 7
4873
4880
  registerMemoryOps(api, supabase, userId); // 8
4874
4881
  registerPromptOps(api, supabase, userId); // 9
4875
4882
  registerConstellationOps(api, supabase, userId); // 10