ofiere-openclaw-plugin 4.37.1 → 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.
Files changed (2) hide show
  1. package/package.json +1 -1
  2. package/src/tools.ts +38 -9
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ofiere-openclaw-plugin",
3
- "version": "4.37.1",
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/tools.ts CHANGED
@@ -5244,9 +5244,11 @@ function registerFrameworkOps(
5244
5244
  `\\"strategic_objectives\\":[{\\"objective\\":\\"Grow MRR\\",\\"target\\":\\"$100k\\",\\"measurement\\":\\"Revenue dashboard\\"}],` +
5245
5245
  `\\"risk_appetite\\":\\"moderate\\",\\"escalation_matrix\\":[{\\"trigger\\":\\"Budget >80%\\",\\"escalate_to\\":\\"CEO\\",\\"priority\\":\\"P1\\"}],` +
5246
5246
  `\\"notes\\":\\"Quarterly review\\"}"\n\n` +
5247
- `Supported content fields: mission, vision, core_principles, decision_authority, budget_constraints, ` +
5248
- `resource_limits, tool_stack, strategic_objectives, risk_appetite, compliance_requirements, ` +
5249
- `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` +
5250
5252
  `Status values: "draft", "active", "under_review", "archived"`,
5251
5253
  parameters: {
5252
5254
  type: "object",
@@ -5278,6 +5280,33 @@ function registerFrameworkOps(
5278
5280
 
5279
5281
  // ── Framework action handlers ────────────────────────────────────────────────
5280
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
+
5281
5310
  async function handleFWCreate(
5282
5311
  supabase: SupabaseClient, userId: string,
5283
5312
  resolveAgent: (id?: string) => Promise<string | null>,
@@ -5296,13 +5325,13 @@ async function handleFWCreate(
5296
5325
  // Already a JSON string — merge with title
5297
5326
  try {
5298
5327
  const parsed = JSON.parse(params.content);
5299
- content = JSON.stringify({ title, ...parsed });
5328
+ content = JSON.stringify(normalizeFrameworkContent({ title, ...parsed }));
5300
5329
  } catch {
5301
5330
  // Not valid JSON — wrap as notes
5302
- content = JSON.stringify({ title, notes: params.content });
5331
+ content = JSON.stringify(normalizeFrameworkContent({ title, notes: params.content }));
5303
5332
  }
5304
5333
  } else if (params.framework_data && typeof params.framework_data === "object") {
5305
- content = JSON.stringify({ title, ...(params.framework_data as Record<string, unknown>) });
5334
+ content = JSON.stringify(normalizeFrameworkContent({ title, ...(params.framework_data as Record<string, unknown>) }));
5306
5335
  } else {
5307
5336
  content = JSON.stringify({ title });
5308
5337
  }
@@ -5363,13 +5392,13 @@ async function handleFWUpdate(supabase: SupabaseClient, userId: string, params:
5363
5392
  if (typeof params.content === "string" && params.content.trim()) {
5364
5393
  try {
5365
5394
  const parsed = JSON.parse(params.content);
5366
- 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 }));
5367
5396
  } catch {
5368
- 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 }));
5369
5398
  }
5370
5399
  } else if (params.framework_data && typeof params.framework_data === "object") {
5371
5400
  const raw = params.framework_data as Record<string, unknown>;
5372
- 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 }));
5373
5402
  }
5374
5403
 
5375
5404
  const { data, error } = await supabase.from("frameworks").update(updates)