ofiere-openclaw-plugin 4.3.1 → 4.4.1

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 +96 -21
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ofiere-openclaw-plugin",
3
- "version": "4.3.1",
3
+ "version": "4.4.1",
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
@@ -2098,8 +2098,11 @@ function registerConstellationOps(
2098
2098
  return path.join(OPENCLAW_ROOT, `workspace-${agentName.toLowerCase()}`);
2099
2099
  }
2100
2100
 
2101
- function listWorkspaceAgents(): Array<{ name: string; codename: string; role: string; files: string[]; hasSkills: boolean }> {
2102
- const result: Array<{ name: string; codename: string; role: string; files: string[]; hasSkills: boolean }> = [];
2101
+ // System-generated .md files that OpenClaw creates automatically not user-authored
2102
+ const SYSTEM_MD_FILES = new Set(["HEARTBEAT.md", "USER.md", "MEMORY.md"]);
2103
+
2104
+ function listWorkspaceAgents(): Array<{ name: string; codename: string; role: string; files: string[]; system_files: string[]; hasSkills: boolean }> {
2105
+ const result: Array<{ name: string; codename: string; role: string; files: string[]; system_files: string[]; hasSkills: boolean }> = [];
2103
2106
  try {
2104
2107
  const entries = fs.readdirSync(OPENCLAW_ROOT, { withFileTypes: true });
2105
2108
  for (const entry of entries) {
@@ -2107,7 +2110,9 @@ function registerConstellationOps(
2107
2110
  const agentName = entry.name.replace("workspace-", "");
2108
2111
  if (agentName === "main" || agentName === "zero" || agentName === "echo") continue; // skip system agents
2109
2112
  const wsPath = path.join(OPENCLAW_ROOT, entry.name);
2110
- const files = fs.readdirSync(wsPath).filter((f: string) => f.endsWith(".md"));
2113
+ const allMd = fs.readdirSync(wsPath).filter((f: string) => f.endsWith(".md"));
2114
+ const files = allMd.filter((f: string) => !SYSTEM_MD_FILES.has(f));
2115
+ const system_files = allMd.filter((f: string) => SYSTEM_MD_FILES.has(f));
2111
2116
  // Try to extract codename and role from IDENTITY.md
2112
2117
  let codename = agentName.toUpperCase();
2113
2118
  let role = "Agent";
@@ -2119,7 +2124,7 @@ function registerConstellationOps(
2119
2124
  if (roleMatch) role = roleMatch[1].trim();
2120
2125
  } catch {}
2121
2126
  const hasSkills = fs.existsSync(path.join(wsPath, "skills"));
2122
- result.push({ name: agentName, codename, role, files, hasSkills });
2127
+ result.push({ name: agentName, codename, role, files, system_files, hasSkills });
2123
2128
  }
2124
2129
  } catch (e) {
2125
2130
  api.logger?.warn?.(`[ofiere] Failed to list workspaces: ${e}`);
@@ -2158,6 +2163,7 @@ function registerConstellationOps(
2158
2163
  if (p.emoji) lines.push(`**Emoji:** ${p.emoji}`);
2159
2164
  lines.push(`**Role:** ${p.role || "Agent"}`);
2160
2165
  lines.push(`**Codename:** ${p.codename}`);
2166
+ if (p.color_hex) lines.push(`**Color:** ${p.color_hex}`);
2161
2167
  if (p.voice_sample) lines.push(`**Sample:** ${p.voice_sample}`);
2162
2168
  lines.push("");
2163
2169
  if (p.one_liner) {
@@ -2170,10 +2176,34 @@ function registerConstellationOps(
2170
2176
  lines.push("");
2171
2177
  lines.push(p.core_identity || `${p.agent_name} is an AI agent specializing in ${p.role || "general tasks"}.`);
2172
2178
  lines.push("");
2179
+ if (p.personality) {
2180
+ lines.push("## Personality");
2181
+ lines.push("");
2182
+ lines.push(p.personality);
2183
+ lines.push("");
2184
+ }
2173
2185
  lines.push("## Operating Style");
2174
2186
  lines.push("");
2175
2187
  lines.push(p.operating_style || "Focused, professional, detail-oriented.");
2176
2188
  lines.push("");
2189
+ if (p.tone) {
2190
+ lines.push("## Tone");
2191
+ lines.push("");
2192
+ lines.push(p.tone);
2193
+ lines.push("");
2194
+ }
2195
+ if (p.worldview) {
2196
+ lines.push("## Worldview");
2197
+ lines.push("");
2198
+ lines.push(p.worldview);
2199
+ lines.push("");
2200
+ }
2201
+ if (p.pacing) {
2202
+ lines.push("## Pacing");
2203
+ lines.push("");
2204
+ lines.push(p.pacing);
2205
+ lines.push("");
2206
+ }
2177
2207
  lines.push("## Relationship to Team");
2178
2208
  lines.push("");
2179
2209
  lines.push(p.team_relationship || "Collaborative team member within the agent constellation.");
@@ -2440,6 +2470,7 @@ function registerConstellationOps(
2440
2470
  role: a.role,
2441
2471
  file_count: a.files.length,
2442
2472
  files: a.files,
2473
+ system_files: a.system_files,
2443
2474
  has_skills: a.hasSkills,
2444
2475
  })),
2445
2476
  count: agents.length,
@@ -2452,8 +2483,10 @@ function registerConstellationOps(
2452
2483
  const name = (params.agent_name as string).toLowerCase();
2453
2484
  const wsPath = getWorkspacePath(name);
2454
2485
  if (!fs.existsSync(wsPath)) return err(`Agent workspace not found: workspace-${name}`);
2455
- const files = fs.readdirSync(wsPath).filter((f: string) => f.endsWith(".md"));
2456
- const fileDetails = files.map((f: string) => {
2486
+ const allMd = fs.readdirSync(wsPath).filter((f: string) => f.endsWith(".md"));
2487
+ const userMd = allMd.filter((f: string) => !SYSTEM_MD_FILES.has(f));
2488
+ const systemMd = allMd.filter((f: string) => SYSTEM_MD_FILES.has(f));
2489
+ const fileDetails = userMd.map((f: string) => {
2457
2490
  const stat = fs.statSync(path.join(wsPath, f));
2458
2491
  return { name: f, size_bytes: stat.size, modified: stat.mtime.toISOString() };
2459
2492
  });
@@ -2471,7 +2504,7 @@ function registerConstellationOps(
2471
2504
  if (emojiMatch) identity.emoji = emojiMatch[1].trim();
2472
2505
  } catch {}
2473
2506
  const hasSkills = fs.existsSync(path.join(wsPath, "skills"));
2474
- return ok({ agent_name: name, identity, files: fileDetails, has_skills: hasSkills, workspace_path: wsPath });
2507
+ return ok({ agent_name: name, identity, files: fileDetails, system_files: systemMd, has_skills: hasSkills, workspace_path: wsPath });
2475
2508
  }
2476
2509
 
2477
2510
  // ── Read a file ──
@@ -2540,7 +2573,46 @@ function registerConstellationOps(
2540
2573
 
2541
2574
  // Create doctrine file (codename.md) — empty scaffold
2542
2575
  const doctrineName = `${(params.codename as string).toUpperCase()}.md`;
2543
- const doctrineMd = `# ${params.codename} Doctrine\n\n## Mission\n\n${p.mission || "To be defined."}\n\n## Decision Frameworks\n\n- (Define frameworks here)\n\n## Non-Goals\n\n- (Define non-goals here)\n\n## Evaluation Criteria\n\n- (Define criteria here)\n\n## Metrics\n\n- (Define metrics here)\n\n## Standard Deliverables\n\n- (Define deliverables here)\n\n## Anti-Patterns\n\n- (Define anti-patterns here)\n\n## Handoff Rules\n\n- (Define handoff rules here)\n`;
2576
+ const doctrineMd = [
2577
+ `# ${params.codename} Doctrine`,
2578
+ "",
2579
+ "## Mission",
2580
+ "",
2581
+ p.mission || "To be defined.",
2582
+ "",
2583
+ "## Scope of Responsibility",
2584
+ "",
2585
+ p.scope || `All tasks related to ${p.role || "the assigned domain"}.`,
2586
+ "",
2587
+ "## Decision Frameworks",
2588
+ "",
2589
+ "*To be defined by the operator.*",
2590
+ "",
2591
+ "## Non-Goals",
2592
+ "",
2593
+ "*To be defined by the operator.*",
2594
+ "",
2595
+ "## Evaluation Criteria",
2596
+ "",
2597
+ "*To be defined by the operator.*",
2598
+ "",
2599
+ "## Metrics",
2600
+ "",
2601
+ "*To be defined by the operator.*",
2602
+ "",
2603
+ "## Standard Deliverables",
2604
+ "",
2605
+ "*To be defined by the operator.*",
2606
+ "",
2607
+ "## Anti-Patterns",
2608
+ "",
2609
+ "*To be defined by the operator.*",
2610
+ "",
2611
+ "## Handoff Rules",
2612
+ "",
2613
+ "*To be defined by the operator.*",
2614
+ "",
2615
+ ].join("\n");
2544
2616
  writeAgentFile(agentName, doctrineName, doctrineMd);
2545
2617
  filesWritten.push(doctrineName);
2546
2618
 
@@ -2618,12 +2690,13 @@ function registerConstellationOps(
2618
2690
  const agentsContent = readAgentFile(agent.name, "AGENTS.md");
2619
2691
  const owns: string[] = [];
2620
2692
  if (agentsContent) {
2621
- // Extract ### Owns section
2622
- const ownsMatch = agentsContent.match(/###\s+Owns\s*\n([\s\S]*?)(?=\n###|\n##|$)/i);
2693
+ // Extract Owns section — flexible heading match (##, ###, or ####)
2694
+ // Also try matching under a Boundaries parent section
2695
+ const ownsMatch = agentsContent.match(/#{2,4}\s+Owns\s*\n+([\s\S]*?)(?=\n#{2,4}\s|$)/i);
2623
2696
  if (ownsMatch) {
2624
2697
  const items = ownsMatch[1].split("\n")
2625
2698
  .map((l: string) => l.replace(/^[\s-*]+/, "").trim())
2626
- .filter((l: string) => l.length > 0);
2699
+ .filter((l: string) => l.length > 0 && !l.startsWith("#"));
2627
2700
  owns.push(...items);
2628
2701
  }
2629
2702
  }
@@ -2640,17 +2713,18 @@ function registerConstellationOps(
2640
2713
 
2641
2714
  // Safety gate: confirm must be explicitly true
2642
2715
  if (params.confirm !== true) {
2643
- // List what would be deleted so the agent can show the user
2644
- let fileList: string[] = [];
2716
+ // List only user-visible files (exclude system md + internal dirs)
2717
+ let userFiles: string[] = [];
2645
2718
  try {
2646
2719
  if (fs.existsSync(wsPath)) {
2647
- fileList = fs.readdirSync(wsPath, { recursive: true }) as string[];
2720
+ userFiles = fs.readdirSync(wsPath)
2721
+ .filter((f: string) => (f.endsWith(".md") && !SYSTEM_MD_FILES.has(f)) || f === "skills");
2648
2722
  }
2649
2723
  } catch {}
2650
2724
  return err(
2651
- `⚠️ DESTRUCTIVE ACTION: This will permanently delete agent "${agentName}" and ALL files in workspace-${agentName}/ (${fileList.length} items). ` +
2725
+ `⚠️ DESTRUCTIVE ACTION: This will permanently delete agent "${agentName}" and ALL files in workspace-${agentName}/ (${userFiles.length} user files). ` +
2652
2726
  `This CANNOT be undone.\n\n` +
2653
- `Files that will be deleted:\n${fileList.map((f: string) => ` - ${f}`).join("\n") || " (directory not found)"}\n\n` +
2727
+ `Files that will be deleted:\n${userFiles.map((f: string) => ` - ${f}`).join("\n") || " (directory not found)"}\n\n` +
2654
2728
  `To proceed, ask the user for explicit confirmation and then call this action again with confirm: true.`
2655
2729
  );
2656
2730
  }
@@ -2660,10 +2734,11 @@ function registerConstellationOps(
2660
2734
  return err(`Agent workspace-${agentName} does not exist at ${wsPath}`);
2661
2735
  }
2662
2736
 
2663
- // Count files before deletion for the report
2664
- let deletedFiles: string[] = [];
2737
+ // Count user-visible files before deletion for the report
2738
+ let deletedUserFiles: string[] = [];
2665
2739
  try {
2666
- deletedFiles = fs.readdirSync(wsPath, { recursive: true }) as string[];
2740
+ deletedUserFiles = fs.readdirSync(wsPath)
2741
+ .filter((f: string) => (f.endsWith(".md") && !SYSTEM_MD_FILES.has(f)) || f === "skills");
2667
2742
  } catch {}
2668
2743
 
2669
2744
  // Remove the entire workspace directory
@@ -2690,13 +2765,13 @@ function registerConstellationOps(
2690
2765
  unregResult = { success: false, message: `Unregistration may have failed: ${unregCombined.slice(0, 200)}` };
2691
2766
  }
2692
2767
 
2693
- api.logger?.info?.(`[ofiere] Deleted agent "${agentName}" — ${deletedFiles.length} files removed`);
2768
+ api.logger?.info?.(`[ofiere] Deleted agent "${agentName}" — ${deletedUserFiles.length} files removed`);
2694
2769
 
2695
2770
  return ok({
2696
2771
  message: `Agent "${agentName}" has been permanently deleted`,
2697
2772
  agent_name: agentName,
2698
2773
  workspace_deleted: wsPath,
2699
- files_removed: deletedFiles.length,
2774
+ files_removed: deletedUserFiles.length,
2700
2775
  unregistration: unregResult,
2701
2776
  });
2702
2777
  }