ofiere-openclaw-plugin 1.0.2 → 1.1.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/index.ts +5 -1
- package/package.json +1 -1
- package/src/tools.ts +113 -20
package/index.ts
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
import type { OpenClawPluginApi } from "openclaw/plugin-sdk";
|
|
5
5
|
import { parseOfiereConfig } from "./src/config.js";
|
|
6
6
|
import { getSupabase } from "./src/supabase.js";
|
|
7
|
-
import { registerTools } from "./src/tools.js";
|
|
7
|
+
import { registerTools, probeApiForAgentName } from "./src/tools.js";
|
|
8
8
|
import { getSystemPrompt } from "./src/prompt.js";
|
|
9
9
|
import { registerCli } from "./src/cli.js";
|
|
10
10
|
import { seedAgentCache } from "./src/agent-resolver.js";
|
|
@@ -70,6 +70,10 @@ const ofierePlugin = {
|
|
|
70
70
|
// ── Connect to Supabase and register tools ────────────────────────────
|
|
71
71
|
try {
|
|
72
72
|
const supabase = getSupabase(config.supabaseUrl, config.serviceRoleKey);
|
|
73
|
+
|
|
74
|
+
// Probe the api object for any agent identity info (for debugging + fallback)
|
|
75
|
+
probeApiForAgentName(api, api.logger);
|
|
76
|
+
|
|
73
77
|
registerTools(api, supabase, config);
|
|
74
78
|
promptState.toolCount = 5;
|
|
75
79
|
promptState.ready = true;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ofiere-openclaw-plugin",
|
|
3
|
-
"version": "1.0
|
|
3
|
+
"version": "1.1.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "OpenClaw plugin for Ofiere PM — manage tasks, agents, and projects from your agent",
|
|
6
6
|
"keywords": ["openclaw", "ofiere", "project-management", "agents", "plugin"],
|
package/src/tools.ts
CHANGED
|
@@ -30,19 +30,74 @@ function err(message: string): ToolResult {
|
|
|
30
30
|
|
|
31
31
|
// ─── Helper: extract calling agent's accountId from OpenClaw context ─────────
|
|
32
32
|
|
|
33
|
+
// Module-level: set once at registration time from index.ts
|
|
34
|
+
let _registrationAgentName = "";
|
|
35
|
+
export function setRegistrationAgentName(name: string) {
|
|
36
|
+
if (name && !_registrationAgentName) _registrationAgentName = name;
|
|
37
|
+
}
|
|
38
|
+
|
|
33
39
|
function getCallingAgentName(api: any): string {
|
|
34
|
-
// OpenClaw passes agent context in various ways — try
|
|
40
|
+
// OpenClaw passes agent context in various ways — try ALL known paths
|
|
41
|
+
try {
|
|
42
|
+
const candidates = [
|
|
43
|
+
api?.agentContext?.accountId,
|
|
44
|
+
api?.agentContext?.name,
|
|
45
|
+
api?.agentContext?.id,
|
|
46
|
+
api?.currentAgent?.accountId,
|
|
47
|
+
api?.currentAgent?.name,
|
|
48
|
+
api?.currentAgent?.id,
|
|
49
|
+
api?.agent?.accountId,
|
|
50
|
+
api?.agent?.name,
|
|
51
|
+
api?.agent?.id,
|
|
52
|
+
api?.agentId,
|
|
53
|
+
api?.agentName,
|
|
54
|
+
api?.accountId,
|
|
55
|
+
api?.name,
|
|
56
|
+
api?.id,
|
|
57
|
+
api?.metadata?.agentId,
|
|
58
|
+
api?.metadata?.accountId,
|
|
59
|
+
api?.metadata?.agentName,
|
|
60
|
+
api?.context?.agentId,
|
|
61
|
+
api?.context?.accountId,
|
|
62
|
+
api?.context?.agent?.name,
|
|
63
|
+
];
|
|
64
|
+
for (const c of candidates) {
|
|
65
|
+
if (typeof c === "string" && c.trim()) return c.trim();
|
|
66
|
+
}
|
|
67
|
+
} catch {
|
|
68
|
+
// ignore
|
|
69
|
+
}
|
|
70
|
+
return "";
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Probe the API object for any agent identity info. Called once at registration.
|
|
75
|
+
* Logs ALL available keys for debugging.
|
|
76
|
+
*/
|
|
77
|
+
export function probeApiForAgentName(api: any, logger?: any): string {
|
|
78
|
+
// Direct detection
|
|
79
|
+
const name = getCallingAgentName(api);
|
|
80
|
+
if (name) {
|
|
81
|
+
logger?.info?.(`[ofiere] Detected agent from API: "${name}"`);
|
|
82
|
+
setRegistrationAgentName(name);
|
|
83
|
+
return name;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
// Log all top-level keys for future debugging
|
|
35
87
|
try {
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
api
|
|
41
|
-
""
|
|
42
|
-
|
|
88
|
+
const keys = Object.keys(api || {});
|
|
89
|
+
logger?.debug?.(`[ofiere] API object keys: ${JSON.stringify(keys)}`);
|
|
90
|
+
// Check if any key looks like it contains agent info
|
|
91
|
+
for (const key of keys) {
|
|
92
|
+
const val = api[key];
|
|
93
|
+
if (typeof val === "string" && val.length > 0 && val.length < 50) {
|
|
94
|
+
logger?.debug?.(`[ofiere] API.${key} = "${val}"`);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
43
97
|
} catch {
|
|
44
|
-
|
|
98
|
+
// ignore
|
|
45
99
|
}
|
|
100
|
+
return "";
|
|
46
101
|
}
|
|
47
102
|
|
|
48
103
|
// ─── Tool Registration ───────────────────────────────────────────────────────
|
|
@@ -57,11 +112,23 @@ export function registerTools(
|
|
|
57
112
|
|
|
58
113
|
/**
|
|
59
114
|
* Resolve the agent ID for the calling agent.
|
|
60
|
-
* Priority: explicit param > runtime context > env var fallback
|
|
115
|
+
* Priority: explicit param > runtime context > registration-time detection > env var > DB fallback
|
|
61
116
|
*/
|
|
62
117
|
async function resolveAgent(explicitId?: string): Promise<string | null> {
|
|
63
|
-
// 1. Explicit agent_id passed by the LLM (e.g. "
|
|
64
|
-
if (explicitId && explicitId.trim())
|
|
118
|
+
// 1. Explicit agent_id passed by the LLM (e.g. "ivy", "daisy", or a UUID)
|
|
119
|
+
if (explicitId && explicitId.trim()) {
|
|
120
|
+
const trimmed = explicitId.trim();
|
|
121
|
+
// If it looks like a UUID or our ID format, use directly
|
|
122
|
+
if (trimmed.match(/^[0-9a-f]{8}-/) || trimmed.match(/^agent-/)) {
|
|
123
|
+
return trimmed;
|
|
124
|
+
}
|
|
125
|
+
// Otherwise treat as a name and resolve to the actual agent ID
|
|
126
|
+
try {
|
|
127
|
+
return await resolveAgentId(trimmed, userId, supabase);
|
|
128
|
+
} catch {
|
|
129
|
+
return trimmed; // fallback: use as-is
|
|
130
|
+
}
|
|
131
|
+
}
|
|
65
132
|
|
|
66
133
|
// 2. Runtime: read calling agent's name from OpenClaw context
|
|
67
134
|
const callerName = getCallingAgentName(api);
|
|
@@ -69,12 +136,37 @@ export function registerTools(
|
|
|
69
136
|
try {
|
|
70
137
|
return await resolveAgentId(callerName, userId, supabase);
|
|
71
138
|
} catch {
|
|
72
|
-
// Fall through
|
|
139
|
+
// Fall through
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
// 3. Registration-time detection (set when plugin was loaded)
|
|
144
|
+
if (_registrationAgentName) {
|
|
145
|
+
try {
|
|
146
|
+
return await resolveAgentId(_registrationAgentName, userId, supabase);
|
|
147
|
+
} catch {
|
|
148
|
+
// Fall through
|
|
73
149
|
}
|
|
74
150
|
}
|
|
75
151
|
|
|
76
|
-
//
|
|
77
|
-
|
|
152
|
+
// 4. Env var fallback (OFIERE_AGENT_ID — legacy single-agent mode)
|
|
153
|
+
if (fallbackAgentId) return fallbackAgentId;
|
|
154
|
+
|
|
155
|
+
// 5. Nuclear fallback: query the FIRST agent for this user
|
|
156
|
+
try {
|
|
157
|
+
const { data } = await supabase
|
|
158
|
+
.from("agents")
|
|
159
|
+
.select("id")
|
|
160
|
+
.eq("user_id", userId)
|
|
161
|
+
.order("name", { ascending: true })
|
|
162
|
+
.limit(1)
|
|
163
|
+
.single();
|
|
164
|
+
if (data?.id) return data.id;
|
|
165
|
+
} catch {
|
|
166
|
+
// ignore
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
return null;
|
|
78
170
|
}
|
|
79
171
|
|
|
80
172
|
// ── OFIERE_LIST_TASKS — Required (read-only, no side effects) ────────
|
|
@@ -134,21 +226,22 @@ export function registerTools(
|
|
|
134
226
|
label: "Create Ofiere Task",
|
|
135
227
|
description:
|
|
136
228
|
"Create a new task in the Ofiere PM dashboard. " +
|
|
137
|
-
"
|
|
229
|
+
"IMPORTANT: You MUST always pass your own name as agent_id (e.g. 'ivy', 'daisy') to assign the task to yourself. " +
|
|
230
|
+
"If you want to assign to a different agent, pass their name instead. " +
|
|
138
231
|
"Pass agent_id as 'none' or 'unassigned' to create an unassigned task. " +
|
|
139
232
|
"The task will appear in the dashboard immediately via real-time sync.",
|
|
140
233
|
parameters: {
|
|
141
234
|
type: "object",
|
|
142
|
-
required: ["title"],
|
|
235
|
+
required: ["title", "agent_id"],
|
|
143
236
|
properties: {
|
|
144
237
|
title: { type: "string", description: "Task title (required)" },
|
|
145
238
|
description: { type: "string", description: "Task description" },
|
|
146
239
|
agent_id: {
|
|
147
240
|
type: "string",
|
|
148
241
|
description:
|
|
149
|
-
"
|
|
150
|
-
"
|
|
151
|
-
"
|
|
242
|
+
"REQUIRED. Your own agent name (e.g. 'ivy', 'daisy', 'celia') to self-assign, " +
|
|
243
|
+
"or another agent's name to assign to them. " +
|
|
244
|
+
"Pass 'none' or 'unassigned' to create a task with no assignee.",
|
|
152
245
|
},
|
|
153
246
|
status: {
|
|
154
247
|
type: "string",
|