ofiere-openclaw-plugin 4.18.1 → 4.18.3
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 +1 -1
- package/src/tools.ts +30 -10
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ofiere-openclaw-plugin",
|
|
3
|
-
"version": "4.18.
|
|
3
|
+
"version": "4.18.3",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "OpenClaw plugin for Ofiere PM - 12 meta-tools covering tasks, agents, projects, scheduling, knowledge, workflows, notifications, memory, prompts, constellation, space file management, and execution plan builder",
|
|
6
6
|
"keywords": ["openclaw", "ofiere", "project-management", "agents", "plugin"],
|
package/src/tools.ts
CHANGED
|
@@ -4131,7 +4131,7 @@ function generatePlanNodeId(): string {
|
|
|
4131
4131
|
}
|
|
4132
4132
|
|
|
4133
4133
|
function generatePlanId(): string {
|
|
4134
|
-
return
|
|
4134
|
+
return crypto.randomUUID();
|
|
4135
4135
|
}
|
|
4136
4136
|
|
|
4137
4137
|
/** Normalize agent-provided node into the PlanNode shape stored in plan_data */
|
|
@@ -4233,11 +4233,13 @@ async function handleListPlans(supabase: SupabaseClient, userId: string, params:
|
|
|
4233
4233
|
async function handleGetPlan(supabase: SupabaseClient, userId: string, params: Record<string, unknown>): Promise<ToolResult> {
|
|
4234
4234
|
try {
|
|
4235
4235
|
if (!params.plan_id) return err("Missing required field: plan_id");
|
|
4236
|
-
const { data, error } = await supabase.from("pm_plans").select("*").eq("id", params.plan_id as string).eq("user_id", userId)
|
|
4236
|
+
const { data, error } = await supabase.from("pm_plans").select("*").eq("id", params.plan_id as string).eq("user_id", userId);
|
|
4237
4237
|
if (error) return err(error.message);
|
|
4238
|
+
if (!data || data.length === 0) return err("Plan not found");
|
|
4239
|
+
const plan = data[0];
|
|
4238
4240
|
let parsed: any = null;
|
|
4239
|
-
try { parsed = JSON.parse(
|
|
4240
|
-
return ok({ plan: { ...
|
|
4241
|
+
try { parsed = JSON.parse(plan.plan_data || "{}"); } catch { parsed = {}; }
|
|
4242
|
+
return ok({ plan: { ...plan, plan_data: parsed } });
|
|
4241
4243
|
} catch (e) { return err(e instanceof Error ? e.message : String(e)); }
|
|
4242
4244
|
}
|
|
4243
4245
|
|
|
@@ -4267,9 +4269,22 @@ async function handleUpdatePlan(supabase: SupabaseClient, userId: string, params
|
|
|
4267
4269
|
if (params.nodes !== undefined) {
|
|
4268
4270
|
const rootNodes = Array.isArray(params.nodes) ? (params.nodes as any[]).map(normalizeNode) : [];
|
|
4269
4271
|
updates.plan_data = buildPlanJson(params.plan_id as string, (params.name as string) || "Plan", params.description as string | undefined, rootNodes);
|
|
4272
|
+
} else if (params.name !== undefined || params.description !== undefined) {
|
|
4273
|
+
// Sync plan_data inner name/description without replacing nodes
|
|
4274
|
+
const { data: existing } = await supabase.from("pm_plans").select("plan_data").eq("id", params.plan_id as string).eq("user_id", userId);
|
|
4275
|
+
if (existing && existing.length > 0) {
|
|
4276
|
+
try {
|
|
4277
|
+
const pd = JSON.parse(existing[0].plan_data || "{}");
|
|
4278
|
+
if (params.name !== undefined) pd.name = params.name;
|
|
4279
|
+
if (params.description !== undefined) pd.description = params.description;
|
|
4280
|
+
pd.updatedAt = new Date().toISOString();
|
|
4281
|
+
updates.plan_data = JSON.stringify(pd, null, 2);
|
|
4282
|
+
} catch { /* plan_data parse failure — skip inner sync */ }
|
|
4283
|
+
}
|
|
4270
4284
|
}
|
|
4271
|
-
const { error } = await supabase.from("pm_plans").update(updates).eq("id", params.plan_id as string).eq("user_id", userId);
|
|
4285
|
+
const { data, error } = await supabase.from("pm_plans").update(updates).eq("id", params.plan_id as string).eq("user_id", userId).select("id");
|
|
4272
4286
|
if (error) return err(error.message);
|
|
4287
|
+
if (!data || data.length === 0) return err("Plan not found");
|
|
4273
4288
|
return ok({ message: `Plan updated` });
|
|
4274
4289
|
} catch (e) { return err(e instanceof Error ? e.message : String(e)); }
|
|
4275
4290
|
}
|
|
@@ -4277,8 +4292,9 @@ async function handleUpdatePlan(supabase: SupabaseClient, userId: string, params
|
|
|
4277
4292
|
async function handleDeletePlan(supabase: SupabaseClient, userId: string, params: Record<string, unknown>): Promise<ToolResult> {
|
|
4278
4293
|
try {
|
|
4279
4294
|
if (!params.plan_id) return err("Missing required field: plan_id");
|
|
4280
|
-
const { error } = await supabase.from("pm_plans").delete().eq("id", params.plan_id as string).eq("user_id", userId);
|
|
4295
|
+
const { data, error } = await supabase.from("pm_plans").delete().eq("id", params.plan_id as string).eq("user_id", userId).select("id");
|
|
4281
4296
|
if (error) return err(error.message);
|
|
4297
|
+
if (!data || data.length === 0) return err("Plan not found — nothing deleted");
|
|
4282
4298
|
return ok({ message: `Plan deleted`, deleted: true });
|
|
4283
4299
|
} catch (e) { return err(e instanceof Error ? e.message : String(e)); }
|
|
4284
4300
|
}
|
|
@@ -4330,15 +4346,18 @@ async function handleExecutePlan(
|
|
|
4330
4346
|
let folderId = (params.folder_id as string) || null;
|
|
4331
4347
|
|
|
4332
4348
|
// Step 1: Create project folder
|
|
4349
|
+
let folderSkipped = false;
|
|
4333
4350
|
if (createFolder && spaceId) {
|
|
4334
4351
|
const folderRow = {
|
|
4335
|
-
id:
|
|
4336
|
-
user_id: userId, space_id: spaceId, name: plan.name || "Untitled Plan",
|
|
4352
|
+
id: crypto.randomUUID(),
|
|
4353
|
+
user_id: userId, space_id: spaceId, name: data.name || plan.name || "Untitled Plan",
|
|
4337
4354
|
type: "project", parent_folder_id: folderId, sort_order: 0,
|
|
4338
4355
|
created_at: new Date().toISOString(), updated_at: new Date().toISOString(),
|
|
4339
4356
|
};
|
|
4340
4357
|
const { error: folderErr } = await supabase.from("pm_folders").insert(folderRow);
|
|
4341
4358
|
if (!folderErr) folderId = folderRow.id;
|
|
4359
|
+
} else if (createFolder && !spaceId) {
|
|
4360
|
+
folderSkipped = true;
|
|
4342
4361
|
}
|
|
4343
4362
|
|
|
4344
4363
|
// Step 2: BFS — create tasks with full field mapping
|
|
@@ -4348,7 +4367,7 @@ async function handleExecutePlan(
|
|
|
4348
4367
|
|
|
4349
4368
|
while (queue.length > 0) {
|
|
4350
4369
|
const { node, parentTaskId } = queue.shift()!;
|
|
4351
|
-
if (node.type === "task"
|
|
4370
|
+
if (node.type === "task") {
|
|
4352
4371
|
const taskId = `task-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
|
|
4353
4372
|
const now = new Date().toISOString();
|
|
4354
4373
|
const agentId = node.agentId ? await resolveAgent(node.agentId) : null;
|
|
@@ -4446,11 +4465,12 @@ async function handleExecutePlan(
|
|
|
4446
4465
|
await supabase.from("pm_plans").update({ is_deployed: true, deployed_at: new Date().toISOString(), updated_at: new Date().toISOString() }).eq("id", params.plan_id as string).eq("user_id", userId);
|
|
4447
4466
|
|
|
4448
4467
|
return ok({
|
|
4449
|
-
message: `Plan "${plan.name}" executed successfully`,
|
|
4468
|
+
message: `Plan "${data.name || plan.name}" executed successfully`,
|
|
4450
4469
|
tasks_created: tasksCreated,
|
|
4451
4470
|
dependencies_created: depsCreated,
|
|
4452
4471
|
folder_id: folderId,
|
|
4453
4472
|
space_id: spaceId,
|
|
4473
|
+
...(folderSkipped ? { folder_skipped_reason: "No space_id provided — assign the plan to a space to enable folder creation" } : {}),
|
|
4454
4474
|
});
|
|
4455
4475
|
} catch (e) { return err(e instanceof Error ? e.message : String(e)); }
|
|
4456
4476
|
}
|