ofiere-openclaw-plugin 4.37.0 → 4.37.2

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.37.0",
3
+ "version": "4.37.2",
4
4
  "type": "module",
5
5
  "description": "OpenClaw plugin for Ofiere PM - 16 meta-tools covering tasks, agents, projects, scheduling, knowledge, workflows, notifications, memory, prompts, constellation, space file management, execution plan builder, SOP management, agent brain, talent management, and corporate frameworks",
6
6
  "keywords": ["openclaw", "ofiere", "project-management", "agents", "plugin"],
package/src/prompt.ts CHANGED
@@ -107,7 +107,8 @@ Actions: "list", "get", "create", "update", "delete", "add_nodes", "execute"
107
107
 
108
108
  OFIERE_SOP_OPS: `Standard Operating Procedures for department chiefs.
109
109
  Actions: "list_templates", "create", "list", "get", "update", "delete", "list_subagents", "apply_template"
110
- - sop_data: { title, objective, scope, prerequisites[], steps[], deliverables[], escalationRules[], successCriteria[], notes }
110
+ - sop_data: { title, purpose, scope, applicability, prerequisites:{ conditions, required_tools, required_permissions, safety_warnings }, procedure_steps[], expected_outputs[], escalation_rules[], acceptance_criteria[], rollback_procedure, notes }
111
+ - Legacy field names still accepted (objective→purpose, steps→procedure_steps, deliverables→expected_outputs, escalationRules→escalation_rules, successCriteria→acceptance_criteria) — prefer new names.
111
112
  - See SOP PROTOCOL section for when to load vs skip`,
112
113
 
113
114
  OFIERE_BRAIN_OPS: `Agent memory, knowledge graph, self-improvement (TMT/MAGMA).
package/src/tools.ts CHANGED
@@ -4879,7 +4879,27 @@ function registerSOPOps(
4879
4879
  purpose: { type: "string", description: "Why this procedure exists (also accepts 'objective')" },
4880
4880
  scope: { type: "string" },
4881
4881
  applicability: { type: "string" },
4882
- prerequisites: { type: "object", description: "{ conditions: [{text,checked}], required_tools: [string], required_permissions: [string], safety_warnings: [string] }" },
4882
+ prerequisites: {
4883
+ type: "object",
4884
+ description: "Preconditions for executing this SOP. All sub-fields optional.",
4885
+ properties: {
4886
+ conditions: {
4887
+ type: "array",
4888
+ description: "Checklist items that must be true before starting.",
4889
+ items: {
4890
+ type: "object",
4891
+ properties: {
4892
+ text: { type: "string" },
4893
+ checked: { type: "boolean" },
4894
+ },
4895
+ required: ["text"],
4896
+ },
4897
+ },
4898
+ required_tools: { type: "array", items: { type: "string" } },
4899
+ required_permissions: { type: "array", items: { type: "string" } },
4900
+ safety_warnings: { type: "array", items: { type: "string" } },
4901
+ },
4902
+ },
4883
4903
  procedure_steps: { type: "array", description: "Also accepts 'steps'", items: { type: "object", properties: { id: { type: "string" }, name: { type: "string" }, action: { type: "string" }, owner: { type: "string" }, output: { type: "string" }, decision_logic: { type: "string" }, failure_state: { type: "string" }, fallback_action: { type: "string" }, estimated_duration: { type: "string" } }, required: ["name", "action"] } },
4884
4904
  expected_outputs: { type: "array", description: "Also accepts 'deliverables'", items: { type: "string" } },
4885
4905
  escalation_rules: { type: "array", description: "Also accepts 'escalationRules'", items: { type: "object", properties: { trigger: { type: "string" }, escalateTo: { type: "string" }, priority: { type: "string", enum: ["P1", "P2", "P3"] } }, required: ["trigger", "escalateTo"] } },
@@ -5224,9 +5244,11 @@ function registerFrameworkOps(
5224
5244
  `\\"strategic_objectives\\":[{\\"objective\\":\\"Grow MRR\\",\\"target\\":\\"$100k\\",\\"measurement\\":\\"Revenue dashboard\\"}],` +
5225
5245
  `\\"risk_appetite\\":\\"moderate\\",\\"escalation_matrix\\":[{\\"trigger\\":\\"Budget >80%\\",\\"escalate_to\\":\\"CEO\\",\\"priority\\":\\"P1\\"}],` +
5226
5246
  `\\"notes\\":\\"Quarterly review\\"}"\n\n` +
5227
- `Supported content fields: mission, vision, core_principles, decision_authority, budget_constraints, ` +
5228
- `resource_limits, tool_stack, strategic_objectives, risk_appetite, compliance_requirements, ` +
5229
- `escalation_matrix, team_composition, integration_points, review_frequency, notes — or any custom fields.\n\n` +
5247
+ `Field types (must match wrong shapes are coerced):\n` +
5248
+ `- string: mission, vision, decision_authority, budget_constraints, resource_limits, risk_appetite, team_composition, review_frequency, last_reviewed, next_review, notes\n` +
5249
+ `- string[]: core_principles, tool_stack, compliance_requirements, integration_points, tags\n` +
5250
+ `- object[]: strategic_objectives [{objective,target,measurement,frequency}], escalation_matrix [{trigger,escalate_to,priority,response_sla}]\n` +
5251
+ `- IMPORTANT: team_composition is a single STRING (a paragraph or newline-separated list), NOT an array. If you have multiple roles, join with newlines inside one string.\n\n` +
5230
5252
  `Status values: "draft", "active", "under_review", "archived"`,
5231
5253
  parameters: {
5232
5254
  type: "object",
@@ -5258,6 +5280,33 @@ function registerFrameworkOps(
5258
5280
 
5259
5281
  // ── Framework action handlers ────────────────────────────────────────────────
5260
5282
 
5283
+ // Coerce field values to the shape the dashboard editor expects. Without this,
5284
+ // LLMs frequently emit team_composition / core_principles etc. as the "wrong"
5285
+ // container shape and the editor crashes on .trim() / .map() / .length.
5286
+ const FW_STRING_FIELDS = ["mission", "vision", "decision_authority", "budget_constraints", "resource_limits", "risk_appetite", "team_composition", "review_frequency", "last_reviewed", "next_review", "rollback_procedure", "notes", "framework_id", "version", "category"] as const;
5287
+ const FW_STRING_ARRAY_FIELDS = ["core_principles", "tool_stack", "compliance_requirements", "integration_points", "tags"] as const;
5288
+
5289
+ function fwToString(v: unknown): string {
5290
+ if (typeof v === "string") return v;
5291
+ if (v == null) return "";
5292
+ if (Array.isArray(v)) return v.map((x) => (typeof x === "string" ? x : JSON.stringify(x))).join("\n");
5293
+ if (typeof v === "object") { try { return JSON.stringify(v); } catch { return ""; } }
5294
+ return String(v);
5295
+ }
5296
+
5297
+ function fwToStringArray(v: unknown): string[] {
5298
+ if (Array.isArray(v)) return v.map((x) => (typeof x === "string" ? x : JSON.stringify(x)));
5299
+ if (typeof v === "string" && v.trim()) return v.split(/\r?\n/).map((s) => s.trim()).filter(Boolean);
5300
+ return [];
5301
+ }
5302
+
5303
+ function normalizeFrameworkContent(raw: Record<string, unknown>): Record<string, unknown> {
5304
+ const out: Record<string, unknown> = { ...raw };
5305
+ for (const k of FW_STRING_FIELDS) if (k in out) out[k] = fwToString(out[k]);
5306
+ for (const k of FW_STRING_ARRAY_FIELDS) if (k in out) out[k] = fwToStringArray(out[k]);
5307
+ return out;
5308
+ }
5309
+
5261
5310
  async function handleFWCreate(
5262
5311
  supabase: SupabaseClient, userId: string,
5263
5312
  resolveAgent: (id?: string) => Promise<string | null>,
@@ -5276,13 +5325,13 @@ async function handleFWCreate(
5276
5325
  // Already a JSON string — merge with title
5277
5326
  try {
5278
5327
  const parsed = JSON.parse(params.content);
5279
- content = JSON.stringify({ title, ...parsed });
5328
+ content = JSON.stringify(normalizeFrameworkContent({ title, ...parsed }));
5280
5329
  } catch {
5281
5330
  // Not valid JSON — wrap as notes
5282
- content = JSON.stringify({ title, notes: params.content });
5331
+ content = JSON.stringify(normalizeFrameworkContent({ title, notes: params.content }));
5283
5332
  }
5284
5333
  } else if (params.framework_data && typeof params.framework_data === "object") {
5285
- content = JSON.stringify({ title, ...(params.framework_data as Record<string, unknown>) });
5334
+ content = JSON.stringify(normalizeFrameworkContent({ title, ...(params.framework_data as Record<string, unknown>) }));
5286
5335
  } else {
5287
5336
  content = JSON.stringify({ title });
5288
5337
  }
@@ -5343,13 +5392,13 @@ async function handleFWUpdate(supabase: SupabaseClient, userId: string, params:
5343
5392
  if (typeof params.content === "string" && params.content.trim()) {
5344
5393
  try {
5345
5394
  const parsed = JSON.parse(params.content);
5346
- updates.content = JSON.stringify({ title: parsed.title || (params.title as string) || "", ...parsed });
5395
+ updates.content = JSON.stringify(normalizeFrameworkContent({ title: parsed.title || (params.title as string) || "", ...parsed }));
5347
5396
  } catch {
5348
- updates.content = JSON.stringify({ title: (params.title as string) || "", notes: params.content });
5397
+ updates.content = JSON.stringify(normalizeFrameworkContent({ title: (params.title as string) || "", notes: params.content }));
5349
5398
  }
5350
5399
  } else if (params.framework_data && typeof params.framework_data === "object") {
5351
5400
  const raw = params.framework_data as Record<string, unknown>;
5352
- updates.content = JSON.stringify({ title: (raw.title as string) || (params.title as string) || "", ...raw });
5401
+ updates.content = JSON.stringify(normalizeFrameworkContent({ title: (raw.title as string) || (params.title as string) || "", ...raw }));
5353
5402
  }
5354
5403
 
5355
5404
  const { data, error } = await supabase.from("frameworks").update(updates)