ofiere-openclaw-plugin 4.25.0 → 4.26.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.25.0",
3
+ "version": "4.26.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
@@ -222,6 +222,13 @@ ${toolDocs}
222
222
  - When creating SOPs for department chiefs (Thalia=CMO, Ivy=COO, Daisy=CTO-Intel, Celia=CTO-Eng), tailor content to their domain expertise.
223
223
  - Prerequisites should be actionable checklist items. Success criteria should be measurable outcomes.
224
224
  - After creating an SOP, suggest the agent set it to "active" status when ready for execution.
225
+ - PLANNING GATE: Before creating ANY task with 3+ execution steps, a due_date, or when the user describes a multi-phase project, ALWAYS ask: "Should I create a Plan first so you can review the structure before I create individual tasks?" If the user says yes, use OFIERE_PLAN_OPS. If they say no or it's a simple one-shot task, proceed directly with OFIERE_TASK_OPS.
226
+ - TASK PLACEMENT — SOP-AWARE ROUTING: When creating a task, the system auto-assigns a PM space. But for FOLDER placement, follow this protocol:
227
+ 1. If the user explicitly provides space_id or folder_id, use those directly.
228
+ 2. If not, and you have active SOPs (loaded via 🔴 COMPLEX assessment), check if any SOP defines an operating structure or folder routing (e.g. "place marketing tasks in Marketing/Campaigns"). Follow the SOP's structure.
229
+ 3. If no SOP guidance exists, check the Space Files tab for an operating map/structure document using OFIERE_FILE_OPS action:"list_files". If found, read it with "read_text_file" and follow its routing rules.
230
+ 4. If no routing guidance exists at all, ask the user: "I can place this task in your default space root, or create a new folder/project for it. Which do you prefer?"
231
+ 5. Do NOT blindly dump all SOPs to check routing — smart-select only SOPs whose title/department matches the task domain.
225
232
 
226
233
  ## SOP PROTOCOL — Adaptive Complexity Assessment
227
234
 
package/src/tools.ts CHANGED
@@ -441,6 +441,61 @@ async function handleCreateTask(
441
441
  cf.assignees = [{ id: assignee, type: "agent" }];
442
442
  }
443
443
 
444
+ // ── Intelligent space_id resolution ──────────────────────────────────
445
+ // Priority: explicit param > agent's default_space_id > first existing space > auto-create
446
+ let resolvedSpaceId = (params.space_id as string) || null;
447
+ let resolvedFolderId = (params.folder_id as string) || null;
448
+ let spaceAutoCreated = false;
449
+
450
+ if (!resolvedSpaceId) {
451
+ try {
452
+ // 1. Check agent's configured default_space_id
453
+ if (assignee) {
454
+ const { data: agentRow } = await supabase
455
+ .from("agents")
456
+ .select("default_space_id")
457
+ .eq("id", assignee)
458
+ .eq("user_id", userId)
459
+ .single();
460
+ if (agentRow?.default_space_id) {
461
+ resolvedSpaceId = agentRow.default_space_id;
462
+ }
463
+ }
464
+
465
+ // 2. Fallback: use the first existing space for this user
466
+ if (!resolvedSpaceId) {
467
+ const { data: existingSpaces } = await supabase
468
+ .from("pm_spaces")
469
+ .select("id")
470
+ .eq("user_id", userId)
471
+ .order("created_at", { ascending: true })
472
+ .limit(1);
473
+ if (existingSpaces && existingSpaces.length > 0) {
474
+ resolvedSpaceId = existingSpaces[0].id;
475
+ }
476
+ }
477
+
478
+ // 3. Nuclear fallback: auto-create a space
479
+ if (!resolvedSpaceId) {
480
+ const newSpaceId = crypto.randomUUID();
481
+ const { error: spaceErr } = await supabase.from("pm_spaces").insert({
482
+ id: newSpaceId,
483
+ user_id: userId,
484
+ name: "Operations",
485
+ icon: "🏢",
486
+ icon_color: "#FF6D29",
487
+ sort_order: 0,
488
+ });
489
+ if (!spaceErr) {
490
+ resolvedSpaceId = newSpaceId;
491
+ spaceAutoCreated = true;
492
+ }
493
+ }
494
+ } catch {
495
+ // Non-fatal: task will still be created, just without space context
496
+ }
497
+ }
498
+
444
499
  const insertData: Record<string, unknown> = {
445
500
  id,
446
501
  user_id: userId,
@@ -450,8 +505,8 @@ async function handleCreateTask(
450
505
  assignee_type: "agent",
451
506
  status: (params.status as string) || "PENDING",
452
507
  priority: params.priority !== undefined ? params.priority : 1,
453
- space_id: (params.space_id as string) || null,
454
- folder_id: (params.folder_id as string) || null,
508
+ space_id: resolvedSpaceId,
509
+ folder_id: resolvedFolderId,
455
510
  start_date: (params.start_date as string) || null,
456
511
  due_date: (params.due_date as string) || (params.start_date as string) || null,
457
512
  tags: (params.tags as string[]) || [],
@@ -578,6 +633,17 @@ async function handleCreateTask(
578
633
  id,
579
634
  message: `Task "${params.title}" created and assigned to ${assignee || "no one"}${extrasStr}`,
580
635
  task: insertData,
636
+ spacePlacement: resolvedSpaceId
637
+ ? {
638
+ space_id: resolvedSpaceId,
639
+ auto_created: spaceAutoCreated,
640
+ note: spaceAutoCreated
641
+ ? 'A new "Operations" space was auto-created because no PM spaces existed.'
642
+ : resolvedFolderId
643
+ ? `Placed in folder ${resolvedFolderId}`
644
+ : "Placed in space root. To organize, check your SOPs/operating structure for folder routing, or specify folder_id.",
645
+ }
646
+ : undefined,
581
647
  scheduledExecution: didSchedule ? `Will auto-execute on ${startDate}` : undefined,
582
648
  recurrence: recurrenceInfo,
583
649
  });