ofiere-openclaw-plugin 4.54.1 → 4.55.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/prompt.js +130 -130
- package/dist/src/staffPersona.js +3 -1
- package/dist/src/tools.js +121 -2
- package/index.ts +105 -105
- package/package.json +12 -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/prompt.ts +267 -267
- package/src/sop-render.ts +216 -216
- package/src/staffPersona.ts +299 -289
- package/src/supabase.ts +13 -13
- package/src/tools.ts +122 -2
- 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
|
+
}
|