ofiere-openclaw-plugin 4.55.0 → 4.56.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/README.md +104 -104
- package/dist/src/gateOps.js +169 -0
- package/dist/src/planExecute.js +145 -0
- package/dist/src/prompt.js +130 -130
- package/dist/src/tools.js +32 -60
- package/index.ts +105 -105
- package/package.json +2 -2
- package/src/agent-resolver.ts +90 -90
- package/src/agent-tier.ts +192 -192
- package/src/attach-token.ts +106 -106
- package/src/attachments.ts +601 -601
- package/src/cli.ts +247 -247
- package/src/config.ts +78 -78
- package/src/gateOps.ts +177 -0
- package/src/planExecute.ts +197 -0
- package/src/prompt.ts +267 -267
- package/src/sop-render.ts +216 -216
- package/src/supabase.ts +13 -13
- package/src/tools.ts +30 -59
- package/src/types/openclaw.d.ts +8 -8
- package/src/types.ts +10 -10
package/src/sop-render.ts
CHANGED
|
@@ -1,216 +1,216 @@
|
|
|
1
|
-
// src/sop-render.ts — Plugin-side markdown renderer for SOPs and Frameworks.
|
|
2
|
-
// Mirrors dashboard/lib/sopRender.ts. Output is what gets prepended/appended to
|
|
3
|
-
// the system prompt during `before_prompt_build`.
|
|
4
|
-
|
|
5
|
-
interface SOPCheckItem { text?: string; checked?: boolean; }
|
|
6
|
-
interface SOPStep {
|
|
7
|
-
name?: string; action?: string; owner?: string; output?: string;
|
|
8
|
-
decision_logic?: string; failure_state?: string; fallback_action?: string;
|
|
9
|
-
estimated_duration?: string;
|
|
10
|
-
}
|
|
11
|
-
interface SOPEscalationRule { trigger?: string; escalateTo?: string; priority?: string; }
|
|
12
|
-
interface SOPPrerequisites {
|
|
13
|
-
conditions?: SOPCheckItem[]; required_tools?: string[];
|
|
14
|
-
required_permissions?: string[]; safety_warnings?: string[];
|
|
15
|
-
}
|
|
16
|
-
export interface SOPData {
|
|
17
|
-
title?: string;
|
|
18
|
-
purpose?: string; scope?: string; applicability?: string;
|
|
19
|
-
prerequisites?: SOPPrerequisites;
|
|
20
|
-
procedure_steps?: SOPStep[];
|
|
21
|
-
expected_outputs?: string[];
|
|
22
|
-
acceptance_criteria?: SOPCheckItem[];
|
|
23
|
-
escalation_rules?: SOPEscalationRule[];
|
|
24
|
-
rollback_procedure?: string;
|
|
25
|
-
notes?: string;
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
interface FrameworkObjective {
|
|
29
|
-
objective?: string; target?: string; measurement?: string; frequency?: string;
|
|
30
|
-
}
|
|
31
|
-
interface FrameworkEscalation {
|
|
32
|
-
trigger?: string; escalate_to?: string; priority?: string; response_sla?: string;
|
|
33
|
-
}
|
|
34
|
-
export interface FrameworkData {
|
|
35
|
-
title?: string;
|
|
36
|
-
mission?: string; vision?: string;
|
|
37
|
-
core_principles?: string[];
|
|
38
|
-
decision_authority?: string; budget_constraints?: string;
|
|
39
|
-
resource_limits?: string; tool_stack?: string[];
|
|
40
|
-
strategic_objectives?: FrameworkObjective[];
|
|
41
|
-
risk_appetite?: string; compliance_requirements?: string[];
|
|
42
|
-
escalation_matrix?: FrameworkEscalation[];
|
|
43
|
-
team_composition?: string; integration_points?: string[];
|
|
44
|
-
review_frequency?: string; last_reviewed?: string; next_review?: string;
|
|
45
|
-
notes?: string;
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
function bullet(items: (string | undefined | null)[]): string {
|
|
49
|
-
const cleaned = items.map((s) => (s ?? "").toString().trim()).filter(Boolean);
|
|
50
|
-
return cleaned.length ? cleaned.map((s) => `- ${s}`).join("\n") : "";
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
function section(label: string, body: string): string {
|
|
54
|
-
const trimmed = body.trim();
|
|
55
|
-
return trimmed ? `### ${label}\n${trimmed}` : "";
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
function joinSections(parts: string[]): string {
|
|
59
|
-
return parts.filter(Boolean).join("\n\n");
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
function safeParse<T = unknown>(s: string): T | null {
|
|
63
|
-
try { return JSON.parse(s) as T; } catch { return null; }
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
export function renderSopMarkdown(input: string | SOPData | null | undefined): string {
|
|
67
|
-
if (input == null) return "";
|
|
68
|
-
const data: SOPData = typeof input === "string"
|
|
69
|
-
? (safeParse<SOPData>(input) || {})
|
|
70
|
-
: input;
|
|
71
|
-
|
|
72
|
-
const parts: string[] = [];
|
|
73
|
-
if (data.purpose) parts.push(section("Purpose", data.purpose));
|
|
74
|
-
if (data.scope) parts.push(section("Scope", data.scope));
|
|
75
|
-
if (data.applicability) parts.push(section("Applicability", data.applicability));
|
|
76
|
-
|
|
77
|
-
const prereq = data.prerequisites;
|
|
78
|
-
if (prereq) {
|
|
79
|
-
const pieces: string[] = [];
|
|
80
|
-
const cond = (prereq.conditions || []).map((c) => c?.text).filter(Boolean) as string[];
|
|
81
|
-
if (cond.length) pieces.push(`**Conditions:**\n${bullet(cond)}`);
|
|
82
|
-
if (prereq.required_tools?.length) pieces.push(`**Required tools:**\n${bullet(prereq.required_tools)}`);
|
|
83
|
-
if (prereq.required_permissions?.length) pieces.push(`**Required permissions:**\n${bullet(prereq.required_permissions)}`);
|
|
84
|
-
if (prereq.safety_warnings?.length) pieces.push(`**Safety warnings:**\n${bullet(prereq.safety_warnings)}`);
|
|
85
|
-
if (pieces.length) parts.push(section("Prerequisites", pieces.join("\n\n")));
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
if (data.procedure_steps?.length) {
|
|
89
|
-
const steps = data.procedure_steps.map((step, i) => {
|
|
90
|
-
const lines: string[] = [`${i + 1}. **${step.name || `Step ${i + 1}`}**`];
|
|
91
|
-
if (step.action) lines.push(` - Action: ${step.action}`);
|
|
92
|
-
if (step.owner) lines.push(` - Owner: ${step.owner}`);
|
|
93
|
-
if (step.output) lines.push(` - Output: ${step.output}`);
|
|
94
|
-
if (step.decision_logic) lines.push(` - Decision logic: ${step.decision_logic}`);
|
|
95
|
-
if (step.failure_state) lines.push(` - Failure state: ${step.failure_state}`);
|
|
96
|
-
if (step.fallback_action) lines.push(` - Fallback: ${step.fallback_action}`);
|
|
97
|
-
if (step.estimated_duration) lines.push(` - ETA: ${step.estimated_duration}`);
|
|
98
|
-
return lines.join("\n");
|
|
99
|
-
}).join("\n");
|
|
100
|
-
parts.push(section("Procedure", steps));
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
if (data.expected_outputs?.length) parts.push(section("Expected Outputs", bullet(data.expected_outputs)));
|
|
104
|
-
if (data.acceptance_criteria?.length) {
|
|
105
|
-
parts.push(section("Acceptance Criteria", bullet(data.acceptance_criteria.map((c) => c?.text || ""))));
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
if (data.escalation_rules?.length) {
|
|
109
|
-
const rules = data.escalation_rules
|
|
110
|
-
.filter((r) => r.trigger || r.escalateTo)
|
|
111
|
-
.map((r) => `- [${r.priority || "P2"}] ${r.trigger || "(unspecified trigger)"} → ${r.escalateTo || "(unspecified)"}`)
|
|
112
|
-
.join("\n");
|
|
113
|
-
if (rules) parts.push(section("Escalation", rules));
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
if (data.rollback_procedure) parts.push(section("Rollback", data.rollback_procedure));
|
|
117
|
-
if (data.notes) parts.push(section("Notes", data.notes));
|
|
118
|
-
|
|
119
|
-
return joinSections(parts);
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
export function renderFrameworkMarkdown(input: string | FrameworkData | null | undefined): string {
|
|
123
|
-
if (input == null) return "";
|
|
124
|
-
const data: FrameworkData = typeof input === "string"
|
|
125
|
-
? (safeParse<FrameworkData>(input) || {})
|
|
126
|
-
: input;
|
|
127
|
-
|
|
128
|
-
const parts: string[] = [];
|
|
129
|
-
if (data.mission) parts.push(section("Mission", data.mission));
|
|
130
|
-
if (data.vision) parts.push(section("Vision", data.vision));
|
|
131
|
-
if (data.core_principles?.length) parts.push(section("Core Principles", bullet(data.core_principles)));
|
|
132
|
-
|
|
133
|
-
const authParts: string[] = [];
|
|
134
|
-
if (data.decision_authority) authParts.push(`**Decision authority:** ${data.decision_authority}`);
|
|
135
|
-
if (data.budget_constraints) authParts.push(`**Budget constraints:** ${data.budget_constraints}`);
|
|
136
|
-
if (data.resource_limits) authParts.push(`**Resource limits:** ${data.resource_limits}`);
|
|
137
|
-
if (data.tool_stack?.length) authParts.push(`**Tool stack:**\n${bullet(data.tool_stack)}`);
|
|
138
|
-
if (authParts.length) parts.push(section("Authority & Constraints", authParts.join("\n\n")));
|
|
139
|
-
|
|
140
|
-
if (data.strategic_objectives?.length) {
|
|
141
|
-
const rows = data.strategic_objectives
|
|
142
|
-
.filter((o) => o.objective || o.target)
|
|
143
|
-
.map((o) => {
|
|
144
|
-
const bits = [
|
|
145
|
-
o.objective ? `**${o.objective}**` : "",
|
|
146
|
-
o.target ? `target: ${o.target}` : "",
|
|
147
|
-
o.measurement ? `measure: ${o.measurement}` : "",
|
|
148
|
-
o.frequency ? `cadence: ${o.frequency}` : "",
|
|
149
|
-
].filter(Boolean);
|
|
150
|
-
return `- ${bits.join(" · ")}`;
|
|
151
|
-
})
|
|
152
|
-
.join("\n");
|
|
153
|
-
if (rows) parts.push(section("Strategic Objectives (KPIs)", rows));
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
const riskParts: string[] = [];
|
|
157
|
-
if (data.risk_appetite) riskParts.push(`**Risk appetite:** ${data.risk_appetite}`);
|
|
158
|
-
if (data.compliance_requirements?.length) riskParts.push(`**Compliance:**\n${bullet(data.compliance_requirements)}`);
|
|
159
|
-
if (riskParts.length) parts.push(section("Risk & Compliance", riskParts.join("\n\n")));
|
|
160
|
-
|
|
161
|
-
if (data.escalation_matrix?.length) {
|
|
162
|
-
const rows = data.escalation_matrix
|
|
163
|
-
.filter((e) => e.trigger || e.escalate_to)
|
|
164
|
-
.map((e) => {
|
|
165
|
-
const sla = e.response_sla ? ` (SLA ${e.response_sla})` : "";
|
|
166
|
-
return `- [${e.priority || "P2"}] ${e.trigger || "(unspecified)"} → ${e.escalate_to || "(unspecified)"}${sla}`;
|
|
167
|
-
})
|
|
168
|
-
.join("\n");
|
|
169
|
-
if (rows) parts.push(section("Escalation Matrix", rows));
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
const teamParts: string[] = [];
|
|
173
|
-
if (data.team_composition) teamParts.push(`**Team:** ${data.team_composition}`);
|
|
174
|
-
if (data.integration_points?.length) teamParts.push(`**Integration points:**\n${bullet(data.integration_points)}`);
|
|
175
|
-
if (teamParts.length) parts.push(section("Team & Integrations", teamParts.join("\n\n")));
|
|
176
|
-
|
|
177
|
-
if (data.review_frequency || data.next_review) {
|
|
178
|
-
const lines = [
|
|
179
|
-
data.review_frequency ? `**Review cadence:** ${data.review_frequency}` : "",
|
|
180
|
-
data.last_reviewed ? `**Last reviewed:** ${data.last_reviewed}` : "",
|
|
181
|
-
data.next_review ? `**Next review:** ${data.next_review}` : "",
|
|
182
|
-
].filter(Boolean);
|
|
183
|
-
if (lines.length) parts.push(section("Review Cycle", lines.join("\n")));
|
|
184
|
-
}
|
|
185
|
-
|
|
186
|
-
if (data.notes) parts.push(section("Notes", data.notes));
|
|
187
|
-
|
|
188
|
-
return joinSections(parts);
|
|
189
|
-
}
|
|
190
|
-
|
|
191
|
-
export function renderAttachmentBlock(args: {
|
|
192
|
-
sops?: Array<{ title: string; content: string }>;
|
|
193
|
-
frameworks?: Array<{ title: string; content: string }>;
|
|
194
|
-
}): string {
|
|
195
|
-
const blocks: string[] = [];
|
|
196
|
-
|
|
197
|
-
if (args.frameworks?.length) {
|
|
198
|
-
const sections = args.frameworks.map((fw) => {
|
|
199
|
-
const md = renderFrameworkMarkdown(fw.content);
|
|
200
|
-
if (!md) return `## ${fw.title}\n_(empty)_`;
|
|
201
|
-
return `## ${fw.title}\n${md}`;
|
|
202
|
-
}).join("\n\n");
|
|
203
|
-
blocks.push(`[FRAMEWORKS — ATTACHED]\nThese frameworks are active for this run. Orient strategic decisions toward them.\n\n${sections}`);
|
|
204
|
-
}
|
|
205
|
-
|
|
206
|
-
if (args.sops?.length) {
|
|
207
|
-
const sections = args.sops.map((sop) => {
|
|
208
|
-
const md = renderSopMarkdown(sop.content);
|
|
209
|
-
if (!md) return `## ${sop.title}\n_(empty)_`;
|
|
210
|
-
return `## ${sop.title}\n${md}`;
|
|
211
|
-
}).join("\n\n");
|
|
212
|
-
blocks.push(`[SOPS — ATTACHED]\nThese SOPs are active for this run. Follow the procedure steps and escalation rules.\n\n${sections}`);
|
|
213
|
-
}
|
|
214
|
-
|
|
215
|
-
return blocks.join("\n\n");
|
|
216
|
-
}
|
|
1
|
+
// src/sop-render.ts — Plugin-side markdown renderer for SOPs and Frameworks.
|
|
2
|
+
// Mirrors dashboard/lib/sopRender.ts. Output is what gets prepended/appended to
|
|
3
|
+
// the system prompt during `before_prompt_build`.
|
|
4
|
+
|
|
5
|
+
interface SOPCheckItem { text?: string; checked?: boolean; }
|
|
6
|
+
interface SOPStep {
|
|
7
|
+
name?: string; action?: string; owner?: string; output?: string;
|
|
8
|
+
decision_logic?: string; failure_state?: string; fallback_action?: string;
|
|
9
|
+
estimated_duration?: string;
|
|
10
|
+
}
|
|
11
|
+
interface SOPEscalationRule { trigger?: string; escalateTo?: string; priority?: string; }
|
|
12
|
+
interface SOPPrerequisites {
|
|
13
|
+
conditions?: SOPCheckItem[]; required_tools?: string[];
|
|
14
|
+
required_permissions?: string[]; safety_warnings?: string[];
|
|
15
|
+
}
|
|
16
|
+
export interface SOPData {
|
|
17
|
+
title?: string;
|
|
18
|
+
purpose?: string; scope?: string; applicability?: string;
|
|
19
|
+
prerequisites?: SOPPrerequisites;
|
|
20
|
+
procedure_steps?: SOPStep[];
|
|
21
|
+
expected_outputs?: string[];
|
|
22
|
+
acceptance_criteria?: SOPCheckItem[];
|
|
23
|
+
escalation_rules?: SOPEscalationRule[];
|
|
24
|
+
rollback_procedure?: string;
|
|
25
|
+
notes?: string;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
interface FrameworkObjective {
|
|
29
|
+
objective?: string; target?: string; measurement?: string; frequency?: string;
|
|
30
|
+
}
|
|
31
|
+
interface FrameworkEscalation {
|
|
32
|
+
trigger?: string; escalate_to?: string; priority?: string; response_sla?: string;
|
|
33
|
+
}
|
|
34
|
+
export interface FrameworkData {
|
|
35
|
+
title?: string;
|
|
36
|
+
mission?: string; vision?: string;
|
|
37
|
+
core_principles?: string[];
|
|
38
|
+
decision_authority?: string; budget_constraints?: string;
|
|
39
|
+
resource_limits?: string; tool_stack?: string[];
|
|
40
|
+
strategic_objectives?: FrameworkObjective[];
|
|
41
|
+
risk_appetite?: string; compliance_requirements?: string[];
|
|
42
|
+
escalation_matrix?: FrameworkEscalation[];
|
|
43
|
+
team_composition?: string; integration_points?: string[];
|
|
44
|
+
review_frequency?: string; last_reviewed?: string; next_review?: string;
|
|
45
|
+
notes?: string;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
function bullet(items: (string | undefined | null)[]): string {
|
|
49
|
+
const cleaned = items.map((s) => (s ?? "").toString().trim()).filter(Boolean);
|
|
50
|
+
return cleaned.length ? cleaned.map((s) => `- ${s}`).join("\n") : "";
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
function section(label: string, body: string): string {
|
|
54
|
+
const trimmed = body.trim();
|
|
55
|
+
return trimmed ? `### ${label}\n${trimmed}` : "";
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
function joinSections(parts: string[]): string {
|
|
59
|
+
return parts.filter(Boolean).join("\n\n");
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
function safeParse<T = unknown>(s: string): T | null {
|
|
63
|
+
try { return JSON.parse(s) as T; } catch { return null; }
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
export function renderSopMarkdown(input: string | SOPData | null | undefined): string {
|
|
67
|
+
if (input == null) return "";
|
|
68
|
+
const data: SOPData = typeof input === "string"
|
|
69
|
+
? (safeParse<SOPData>(input) || {})
|
|
70
|
+
: input;
|
|
71
|
+
|
|
72
|
+
const parts: string[] = [];
|
|
73
|
+
if (data.purpose) parts.push(section("Purpose", data.purpose));
|
|
74
|
+
if (data.scope) parts.push(section("Scope", data.scope));
|
|
75
|
+
if (data.applicability) parts.push(section("Applicability", data.applicability));
|
|
76
|
+
|
|
77
|
+
const prereq = data.prerequisites;
|
|
78
|
+
if (prereq) {
|
|
79
|
+
const pieces: string[] = [];
|
|
80
|
+
const cond = (prereq.conditions || []).map((c) => c?.text).filter(Boolean) as string[];
|
|
81
|
+
if (cond.length) pieces.push(`**Conditions:**\n${bullet(cond)}`);
|
|
82
|
+
if (prereq.required_tools?.length) pieces.push(`**Required tools:**\n${bullet(prereq.required_tools)}`);
|
|
83
|
+
if (prereq.required_permissions?.length) pieces.push(`**Required permissions:**\n${bullet(prereq.required_permissions)}`);
|
|
84
|
+
if (prereq.safety_warnings?.length) pieces.push(`**Safety warnings:**\n${bullet(prereq.safety_warnings)}`);
|
|
85
|
+
if (pieces.length) parts.push(section("Prerequisites", pieces.join("\n\n")));
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
if (data.procedure_steps?.length) {
|
|
89
|
+
const steps = data.procedure_steps.map((step, i) => {
|
|
90
|
+
const lines: string[] = [`${i + 1}. **${step.name || `Step ${i + 1}`}**`];
|
|
91
|
+
if (step.action) lines.push(` - Action: ${step.action}`);
|
|
92
|
+
if (step.owner) lines.push(` - Owner: ${step.owner}`);
|
|
93
|
+
if (step.output) lines.push(` - Output: ${step.output}`);
|
|
94
|
+
if (step.decision_logic) lines.push(` - Decision logic: ${step.decision_logic}`);
|
|
95
|
+
if (step.failure_state) lines.push(` - Failure state: ${step.failure_state}`);
|
|
96
|
+
if (step.fallback_action) lines.push(` - Fallback: ${step.fallback_action}`);
|
|
97
|
+
if (step.estimated_duration) lines.push(` - ETA: ${step.estimated_duration}`);
|
|
98
|
+
return lines.join("\n");
|
|
99
|
+
}).join("\n");
|
|
100
|
+
parts.push(section("Procedure", steps));
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
if (data.expected_outputs?.length) parts.push(section("Expected Outputs", bullet(data.expected_outputs)));
|
|
104
|
+
if (data.acceptance_criteria?.length) {
|
|
105
|
+
parts.push(section("Acceptance Criteria", bullet(data.acceptance_criteria.map((c) => c?.text || ""))));
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
if (data.escalation_rules?.length) {
|
|
109
|
+
const rules = data.escalation_rules
|
|
110
|
+
.filter((r) => r.trigger || r.escalateTo)
|
|
111
|
+
.map((r) => `- [${r.priority || "P2"}] ${r.trigger || "(unspecified trigger)"} → ${r.escalateTo || "(unspecified)"}`)
|
|
112
|
+
.join("\n");
|
|
113
|
+
if (rules) parts.push(section("Escalation", rules));
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
if (data.rollback_procedure) parts.push(section("Rollback", data.rollback_procedure));
|
|
117
|
+
if (data.notes) parts.push(section("Notes", data.notes));
|
|
118
|
+
|
|
119
|
+
return joinSections(parts);
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
export function renderFrameworkMarkdown(input: string | FrameworkData | null | undefined): string {
|
|
123
|
+
if (input == null) return "";
|
|
124
|
+
const data: FrameworkData = typeof input === "string"
|
|
125
|
+
? (safeParse<FrameworkData>(input) || {})
|
|
126
|
+
: input;
|
|
127
|
+
|
|
128
|
+
const parts: string[] = [];
|
|
129
|
+
if (data.mission) parts.push(section("Mission", data.mission));
|
|
130
|
+
if (data.vision) parts.push(section("Vision", data.vision));
|
|
131
|
+
if (data.core_principles?.length) parts.push(section("Core Principles", bullet(data.core_principles)));
|
|
132
|
+
|
|
133
|
+
const authParts: string[] = [];
|
|
134
|
+
if (data.decision_authority) authParts.push(`**Decision authority:** ${data.decision_authority}`);
|
|
135
|
+
if (data.budget_constraints) authParts.push(`**Budget constraints:** ${data.budget_constraints}`);
|
|
136
|
+
if (data.resource_limits) authParts.push(`**Resource limits:** ${data.resource_limits}`);
|
|
137
|
+
if (data.tool_stack?.length) authParts.push(`**Tool stack:**\n${bullet(data.tool_stack)}`);
|
|
138
|
+
if (authParts.length) parts.push(section("Authority & Constraints", authParts.join("\n\n")));
|
|
139
|
+
|
|
140
|
+
if (data.strategic_objectives?.length) {
|
|
141
|
+
const rows = data.strategic_objectives
|
|
142
|
+
.filter((o) => o.objective || o.target)
|
|
143
|
+
.map((o) => {
|
|
144
|
+
const bits = [
|
|
145
|
+
o.objective ? `**${o.objective}**` : "",
|
|
146
|
+
o.target ? `target: ${o.target}` : "",
|
|
147
|
+
o.measurement ? `measure: ${o.measurement}` : "",
|
|
148
|
+
o.frequency ? `cadence: ${o.frequency}` : "",
|
|
149
|
+
].filter(Boolean);
|
|
150
|
+
return `- ${bits.join(" · ")}`;
|
|
151
|
+
})
|
|
152
|
+
.join("\n");
|
|
153
|
+
if (rows) parts.push(section("Strategic Objectives (KPIs)", rows));
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
const riskParts: string[] = [];
|
|
157
|
+
if (data.risk_appetite) riskParts.push(`**Risk appetite:** ${data.risk_appetite}`);
|
|
158
|
+
if (data.compliance_requirements?.length) riskParts.push(`**Compliance:**\n${bullet(data.compliance_requirements)}`);
|
|
159
|
+
if (riskParts.length) parts.push(section("Risk & Compliance", riskParts.join("\n\n")));
|
|
160
|
+
|
|
161
|
+
if (data.escalation_matrix?.length) {
|
|
162
|
+
const rows = data.escalation_matrix
|
|
163
|
+
.filter((e) => e.trigger || e.escalate_to)
|
|
164
|
+
.map((e) => {
|
|
165
|
+
const sla = e.response_sla ? ` (SLA ${e.response_sla})` : "";
|
|
166
|
+
return `- [${e.priority || "P2"}] ${e.trigger || "(unspecified)"} → ${e.escalate_to || "(unspecified)"}${sla}`;
|
|
167
|
+
})
|
|
168
|
+
.join("\n");
|
|
169
|
+
if (rows) parts.push(section("Escalation Matrix", rows));
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
const teamParts: string[] = [];
|
|
173
|
+
if (data.team_composition) teamParts.push(`**Team:** ${data.team_composition}`);
|
|
174
|
+
if (data.integration_points?.length) teamParts.push(`**Integration points:**\n${bullet(data.integration_points)}`);
|
|
175
|
+
if (teamParts.length) parts.push(section("Team & Integrations", teamParts.join("\n\n")));
|
|
176
|
+
|
|
177
|
+
if (data.review_frequency || data.next_review) {
|
|
178
|
+
const lines = [
|
|
179
|
+
data.review_frequency ? `**Review cadence:** ${data.review_frequency}` : "",
|
|
180
|
+
data.last_reviewed ? `**Last reviewed:** ${data.last_reviewed}` : "",
|
|
181
|
+
data.next_review ? `**Next review:** ${data.next_review}` : "",
|
|
182
|
+
].filter(Boolean);
|
|
183
|
+
if (lines.length) parts.push(section("Review Cycle", lines.join("\n")));
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
if (data.notes) parts.push(section("Notes", data.notes));
|
|
187
|
+
|
|
188
|
+
return joinSections(parts);
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
export function renderAttachmentBlock(args: {
|
|
192
|
+
sops?: Array<{ title: string; content: string }>;
|
|
193
|
+
frameworks?: Array<{ title: string; content: string }>;
|
|
194
|
+
}): string {
|
|
195
|
+
const blocks: string[] = [];
|
|
196
|
+
|
|
197
|
+
if (args.frameworks?.length) {
|
|
198
|
+
const sections = args.frameworks.map((fw) => {
|
|
199
|
+
const md = renderFrameworkMarkdown(fw.content);
|
|
200
|
+
if (!md) return `## ${fw.title}\n_(empty)_`;
|
|
201
|
+
return `## ${fw.title}\n${md}`;
|
|
202
|
+
}).join("\n\n");
|
|
203
|
+
blocks.push(`[FRAMEWORKS — ATTACHED]\nThese frameworks are active for this run. Orient strategic decisions toward them.\n\n${sections}`);
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
if (args.sops?.length) {
|
|
207
|
+
const sections = args.sops.map((sop) => {
|
|
208
|
+
const md = renderSopMarkdown(sop.content);
|
|
209
|
+
if (!md) return `## ${sop.title}\n_(empty)_`;
|
|
210
|
+
return `## ${sop.title}\n${md}`;
|
|
211
|
+
}).join("\n\n");
|
|
212
|
+
blocks.push(`[SOPS — ATTACHED]\nThese SOPs are active for this run. Follow the procedure steps and escalation rules.\n\n${sections}`);
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
return blocks.join("\n\n");
|
|
216
|
+
}
|
package/src/supabase.ts
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
|
-
import { createClient, type SupabaseClient } from "@supabase/supabase-js";
|
|
2
|
-
|
|
3
|
-
let _client: SupabaseClient | null = null;
|
|
4
|
-
|
|
5
|
-
export function getSupabase(supabaseUrl: string, serviceRoleKey: string): SupabaseClient {
|
|
6
|
-
if (_client) return _client;
|
|
7
|
-
|
|
8
|
-
_client = createClient(supabaseUrl, serviceRoleKey, {
|
|
9
|
-
auth: { persistSession: false },
|
|
10
|
-
});
|
|
11
|
-
|
|
12
|
-
return _client;
|
|
13
|
-
}
|
|
1
|
+
import { createClient, type SupabaseClient } from "@supabase/supabase-js";
|
|
2
|
+
|
|
3
|
+
let _client: SupabaseClient | null = null;
|
|
4
|
+
|
|
5
|
+
export function getSupabase(supabaseUrl: string, serviceRoleKey: string): SupabaseClient {
|
|
6
|
+
if (_client) return _client;
|
|
7
|
+
|
|
8
|
+
_client = createClient(supabaseUrl, serviceRoleKey, {
|
|
9
|
+
auth: { persistSession: false },
|
|
10
|
+
});
|
|
11
|
+
|
|
12
|
+
return _client;
|
|
13
|
+
}
|
package/src/tools.ts
CHANGED
|
@@ -23,6 +23,8 @@ import {
|
|
|
23
23
|
} from "./attachments.js";
|
|
24
24
|
import { invalidateAgentTier } from "./agent-tier.js";
|
|
25
25
|
import { loadSubagentRow, readDispatchSubagentId, loadDispatchContextBySession, type DispatchContextRow } from "./staffPersona.js";
|
|
26
|
+
import { expandPlanToDependencyEdges, type PlanNode } from "./planExecute.js";
|
|
27
|
+
import { registerGateOps } from "./gateOps.js";
|
|
26
28
|
|
|
27
29
|
// ─── Tool result shape (matches OpenClaw SDK) ────────────────────────────────
|
|
28
30
|
|
|
@@ -5033,7 +5035,7 @@ async function handleExecutePlan(
|
|
|
5033
5035
|
|
|
5034
5036
|
while (queue.length > 0) {
|
|
5035
5037
|
const { node, parentTaskId } = queue.shift()!;
|
|
5036
|
-
if (node.type === "task") {
|
|
5038
|
+
if (node.type === "task" || node.type === "milestone") {
|
|
5037
5039
|
const taskId = `task-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
|
|
5038
5040
|
const now = new Date().toISOString();
|
|
5039
5041
|
const agentId = node.agentId ? await resolveAgent(node.agentId) : null;
|
|
@@ -5094,70 +5096,36 @@ async function handleExecutePlan(
|
|
|
5094
5096
|
}
|
|
5095
5097
|
}
|
|
5096
5098
|
|
|
5097
|
-
// Step 3:
|
|
5098
|
-
|
|
5099
|
+
// Step 3: Build dependencies + manual-gate rows via shared helper.
|
|
5100
|
+
// The helper handles gate-skip-through (Option A), OR-join via group_id (Option B),
|
|
5101
|
+
// and manual gates via pm_gates rows (Option C). See dashboard/lib/pm/planExecute.ts.
|
|
5102
|
+
const { edges, gates: gateRows, emptyGates } = expandPlanToDependencyEdges(rootNodes as PlanNode[], idMap);
|
|
5099
5103
|
let depsCreated = 0;
|
|
5104
|
+
let gatesCreated = 0;
|
|
5100
5105
|
|
|
5101
|
-
|
|
5102
|
-
function resolveTaskId(n: any): string | undefined {
|
|
5103
|
-
return idMap.get(n.id);
|
|
5104
|
-
}
|
|
5105
|
-
|
|
5106
|
-
// Helper: insert a dependency row into pm_dependencies
|
|
5107
|
-
async function insertDep(predId: string, succId: string): Promise<boolean> {
|
|
5106
|
+
for (const e of edges) {
|
|
5108
5107
|
const { error } = await supabase.from("pm_dependencies").insert({
|
|
5109
5108
|
id: `dep-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`,
|
|
5110
|
-
user_id: userId,
|
|
5111
|
-
|
|
5109
|
+
user_id: userId,
|
|
5110
|
+
predecessor_id: e.predTaskId,
|
|
5111
|
+
successor_id: e.succTaskId,
|
|
5112
|
+
dependency_type: e.dependencyType,
|
|
5113
|
+
lag_days: e.lagDays,
|
|
5114
|
+
group_id: e.groupId,
|
|
5112
5115
|
});
|
|
5113
|
-
|
|
5114
|
-
}
|
|
5115
|
-
|
|
5116
|
-
while (depsQueue.length > 0) {
|
|
5117
|
-
const node = depsQueue.shift()!;
|
|
5118
|
-
const nodeRealId = resolveTaskId(node);
|
|
5119
|
-
|
|
5120
|
-
// Chain siblings: sequential children of this node get chained left-to-right
|
|
5121
|
-
if (Array.isArray(node.children) && node.children.length > 1 && !node.parallel) {
|
|
5122
|
-
const taskChildren: string[] = [];
|
|
5123
|
-
for (const child of node.children) {
|
|
5124
|
-
const cid = resolveTaskId(child);
|
|
5125
|
-
if (cid) taskChildren.push(cid);
|
|
5126
|
-
}
|
|
5127
|
-
for (let i = 1; i < taskChildren.length; i++) {
|
|
5128
|
-
if (await insertDep(taskChildren[i - 1], taskChildren[i])) depsCreated++;
|
|
5129
|
-
}
|
|
5130
|
-
}
|
|
5131
|
-
|
|
5132
|
-
// Parent → first child link (sequential only)
|
|
5133
|
-
if (nodeRealId && !node.parallel && node.children?.length > 0) {
|
|
5134
|
-
const firstChildId = resolveTaskId(node.children[0]);
|
|
5135
|
-
if (firstChildId) {
|
|
5136
|
-
if (await insertDep(nodeRealId, firstChildId)) depsCreated++;
|
|
5137
|
-
}
|
|
5138
|
-
}
|
|
5139
|
-
|
|
5140
|
-
// Parallel fan-out: parent → each child
|
|
5141
|
-
if (nodeRealId && node.parallel && node.children?.length > 0) {
|
|
5142
|
-
for (const child of node.children) {
|
|
5143
|
-
const childId = resolveTaskId(child);
|
|
5144
|
-
if (childId) {
|
|
5145
|
-
if (await insertDep(nodeRealId, childId)) depsCreated++;
|
|
5146
|
-
}
|
|
5147
|
-
}
|
|
5148
|
-
}
|
|
5149
|
-
|
|
5150
|
-
if (Array.isArray(node.children)) depsQueue.push(...node.children);
|
|
5116
|
+
if (!error) depsCreated++;
|
|
5151
5117
|
}
|
|
5152
5118
|
|
|
5153
|
-
|
|
5154
|
-
|
|
5155
|
-
|
|
5156
|
-
|
|
5157
|
-
|
|
5158
|
-
|
|
5159
|
-
|
|
5160
|
-
|
|
5119
|
+
for (const g of gateRows) {
|
|
5120
|
+
const { error } = await supabase.from("pm_gates").insert({
|
|
5121
|
+
user_id: userId,
|
|
5122
|
+
plan_id: params.plan_id as string,
|
|
5123
|
+
plan_node_id: g.planNodeId,
|
|
5124
|
+
gate_label: g.gateLabel,
|
|
5125
|
+
gate_condition: g.gateCondition,
|
|
5126
|
+
task_id_blocked: g.taskIdBlocked,
|
|
5127
|
+
});
|
|
5128
|
+
if (!error) gatesCreated++;
|
|
5161
5129
|
}
|
|
5162
5130
|
|
|
5163
5131
|
// Mark plan as deployed
|
|
@@ -5167,6 +5135,8 @@ async function handleExecutePlan(
|
|
|
5167
5135
|
message: `Plan "${data.name || plan.name}" executed successfully`,
|
|
5168
5136
|
tasks_created: tasksCreated,
|
|
5169
5137
|
dependencies_created: depsCreated,
|
|
5138
|
+
gates_created: gatesCreated,
|
|
5139
|
+
empty_gates: emptyGates,
|
|
5170
5140
|
folder_id: folderId,
|
|
5171
5141
|
space_id: spaceId,
|
|
5172
5142
|
...(folderSkipped ? { folder_skipped_reason: "No space_id provided — assign the plan to a space to enable folder creation" } : {}),
|
|
@@ -7088,6 +7058,7 @@ export function registerTools(
|
|
|
7088
7058
|
registerTalentOps(api, supabase, userId); // 15
|
|
7089
7059
|
registerFrameworkOps(api, supabase, userId, resolveAgent); // 16
|
|
7090
7060
|
registerOfficeOps(api, supabase, userId, resolveAgent); // 17
|
|
7061
|
+
registerGateOps(api, supabase, userId, fallbackAgentId); // 18
|
|
7091
7062
|
|
|
7092
7063
|
// ── Register dynamic brain context hook ──
|
|
7093
7064
|
registerBrainContextHook(api, supabase, userId, fallbackAgentId);
|
|
@@ -7102,7 +7073,7 @@ export function registerTools(
|
|
|
7102
7073
|
registerBrainExtractionHook(api, supabase, userId, fallbackAgentId);
|
|
7103
7074
|
|
|
7104
7075
|
// ── Count and log ──
|
|
7105
|
-
const toolCount =
|
|
7076
|
+
const toolCount = 18;
|
|
7106
7077
|
const callerName = getCallingAgentName(api);
|
|
7107
7078
|
const agentLabel = fallbackAgentId || callerName || "auto-detect";
|
|
7108
7079
|
api.logger.info(`[ofiere] ${toolCount} meta-tools registered (agent: ${agentLabel})`);
|
package/src/types/openclaw.d.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
// Ambient declaration for the OpenClaw plugin SDK. The gateway resolves this
|
|
2
|
-
// module at runtime; npm has no published types. Keep loose — the plugin only
|
|
3
|
-
// uses a small surface (logger, on, registerTool, registerCommand, etc.).
|
|
4
|
-
|
|
5
|
-
declare module "openclaw/plugin-sdk" {
|
|
6
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
7
|
-
export type OpenClawPluginApi = any;
|
|
8
|
-
}
|
|
1
|
+
// Ambient declaration for the OpenClaw plugin SDK. The gateway resolves this
|
|
2
|
+
// module at runtime; npm has no published types. Keep loose — the plugin only
|
|
3
|
+
// uses a small surface (logger, on, registerTool, registerCommand, etc.).
|
|
4
|
+
|
|
5
|
+
declare module "openclaw/plugin-sdk" {
|
|
6
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
7
|
+
export type OpenClawPluginApi = any;
|
|
8
|
+
}
|
package/src/types.ts
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
export interface OfiereConfig {
|
|
2
|
-
enabled: boolean;
|
|
3
|
-
supabaseUrl: string;
|
|
4
|
-
serviceRoleKey: string;
|
|
5
|
-
userId: string;
|
|
6
|
-
/** Optional — if not set, agent identity is resolved at runtime from OpenClaw context */
|
|
7
|
-
agentId: string;
|
|
8
|
-
/** IANA timezone string for the user (e.g. 'Asia/Jakarta', 'America/New_York'). Default: 'Asia/Jakarta' */
|
|
9
|
-
timezone: string;
|
|
10
|
-
}
|
|
1
|
+
export interface OfiereConfig {
|
|
2
|
+
enabled: boolean;
|
|
3
|
+
supabaseUrl: string;
|
|
4
|
+
serviceRoleKey: string;
|
|
5
|
+
userId: string;
|
|
6
|
+
/** Optional — if not set, agent identity is resolved at runtime from OpenClaw context */
|
|
7
|
+
agentId: string;
|
|
8
|
+
/** IANA timezone string for the user (e.g. 'Asia/Jakarta', 'America/New_York'). Default: 'Asia/Jakarta' */
|
|
9
|
+
timezone: string;
|
|
10
|
+
}
|