@engineeros/connector 0.16.0 → 0.17.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.
@@ -1,264 +0,0 @@
1
- import { readFileSync } from "node:fs";
2
-
3
- const ROLE_BOUNDARIES = Object.freeze({
4
- research: Object.freeze({
5
- sandboxMode: "read-only",
6
- skill: "codebase-research",
7
- }),
8
- planning: Object.freeze({
9
- sandboxMode: "read-only",
10
- skill: "change-planning",
11
- }),
12
- implementation: Object.freeze({
13
- sandboxMode: "workspace-write",
14
- skill: "goal-execution",
15
- }),
16
- verification: Object.freeze({
17
- sandboxMode: "read-only",
18
- skill: "change-verification",
19
- }),
20
- });
21
-
22
- const skillCache = new Map();
23
-
24
- export const AGENT_ROLE_IDS = Object.freeze(Object.keys(ROLE_BOUNDARIES));
25
- export const AGENT_SKILL_IDS = Object.freeze(
26
- AGENT_ROLE_IDS.map((roleId) => ROLE_BOUNDARIES[roleId].skill),
27
- );
28
-
29
- export function agentHarnessCapabilities() {
30
- return {
31
- agent_roles: [...AGENT_ROLE_IDS],
32
- agent_skills: [...AGENT_SKILL_IDS],
33
- };
34
- }
35
-
36
- export function buildAgentHarnessPrompt({
37
- agentRole,
38
- agentDefinition,
39
- prompt,
40
- sandboxMode,
41
- requiredOutputHeading,
42
- }) {
43
- const boundary = ROLE_BOUNDARIES[agentRole];
44
- if (!boundary) {
45
- throw new Error(
46
- `EngineerOS assignment has an unsupported agent_role. Expected one of: ${AGENT_ROLE_IDS.join(", ")}.`,
47
- );
48
- }
49
- if (boundary.sandboxMode !== sandboxMode) {
50
- throw new Error(
51
- `EngineerOS ${agentRole} role requires ${boundary.sandboxMode} access, but the assignment requested ${sandboxMode}.`,
52
- );
53
- }
54
- const role = validatedAgentDefinition(agentDefinition, agentRole, boundary);
55
- const assignment = String(prompt || "").trim();
56
- if (!assignment) {
57
- throw new Error("EngineerOS assignment is missing prompt_markdown.");
58
- }
59
- const outputHeading = normalizedOutputHeading(requiredOutputHeading);
60
-
61
- const sections = [
62
- "# EngineerOS Agent Assignment",
63
- "",
64
- "## Active Role",
65
- "",
66
- `- Role: ${role.title}`,
67
- `- Access: ${role.access}`,
68
- `- Responsibility: ${role.instruction}`,
69
- `- Permitted tools: ${role.tools.length ? role.tools.join(", ") : "none"}`,
70
- "- User-facing language: refer to yourself neutrally as the Agent. Do not expose internal role, harness, provider, or coding-agent terminology unless the user asks.",
71
- ];
72
- if (!outputHeading) {
73
- sections.push(
74
- "",
75
- "## Interaction Contract",
76
- "",
77
- "- Infer the current project situation from the assignment and workspace evidence before responding.",
78
- "- Lead with the useful answer or outcome. Do not narrate routine searches, tool calls, or internal work.",
79
- "- When one next activity clearly follows and would help, offer exactly one short, concrete suggestion. Do not force a next step when none is useful.",
80
- "- Ask a question only when a consequential choice cannot be resolved from available evidence.",
81
- "- If the Assignment defines a response format, follow it exactly instead of adding conversational guidance.",
82
- );
83
- }
84
- sections.push(
85
- "",
86
- "## Active Skill",
87
- "",
88
- bundledSkill(role.skill),
89
- "",
90
- "## Assignment",
91
- "",
92
- assignment,
93
- );
94
- if (outputHeading) {
95
- sections.push(
96
- "",
97
- "## Final Response Contract",
98
- "",
99
- "- Return only the structured Markdown required by the Assignment.",
100
- `- The first non-whitespace line must be exactly: ${outputHeading}`,
101
- "- Do not add a preamble, status message, commentary, or code fence.",
102
- "- Do not append a conversational summary or next activity.",
103
- );
104
- }
105
- return sections.join("\n");
106
- }
107
-
108
- function validatedAgentDefinition(definition, agentRole, boundary) {
109
- if (!definition || typeof definition !== "object") {
110
- throw new Error("EngineerOS assignment is missing agent_definition.");
111
- }
112
- if (definition.role !== agentRole || definition.access !== boundary.sandboxMode) {
113
- throw new Error("EngineerOS agent_definition does not match the assigned role and access.");
114
- }
115
- if (definition.skill !== boundary.skill) {
116
- throw new Error(`EngineerOS ${agentRole} role requires the ${boundary.skill} skill.`);
117
- }
118
- if (
119
- typeof definition.title !== "string" ||
120
- !definition.title.trim() ||
121
- typeof definition.instruction !== "string" ||
122
- !definition.instruction.trim() ||
123
- !Array.isArray(definition.tools)
124
- ) {
125
- throw new Error("EngineerOS agent_definition is incomplete.");
126
- }
127
- return definition;
128
- }
129
-
130
- export function normalizeAgentStructuredOutput(
131
- response,
132
- requiredOutputHeading,
133
- ) {
134
- const outputHeading = normalizedOutputHeading(requiredOutputHeading);
135
- if (!outputHeading) {
136
- throw new Error(
137
- "EngineerOS structured output requires a heading contract.",
138
- );
139
- }
140
- const content = String(response || "").trim();
141
- if (!content) {
142
- throw new Error("Agent completed without returning a response.");
143
- }
144
- const firstSection = {
145
- "# Workspace Assessment": "## Executive Summary",
146
- "# Workspace Assessment Delta": "## Updated Executive Summary",
147
- "# Assessment Stage: Architecture": "## Architecture Summary",
148
- "# Assessment Stage: Capability Catalog": "## Capability Catalog",
149
- "# Assessment Stage: Capabilities": "## Observed Capabilities",
150
- "# Assessment Stage: Quality": "## Quality Summary",
151
- "# Assessment Stage: Synthesis": "## Executive Summary",
152
- }[outputHeading];
153
- if (
154
- firstSection &&
155
- (content.startsWith(firstSection) ||
156
- hasRequiredAssessmentSections(content, outputHeading))
157
- ) {
158
- return `${outputHeading}\n\n${content}`;
159
- }
160
- const lines = content.split(/\r?\n/);
161
- const headingIndex = lines.findIndex(
162
- (line) => line.trim() === outputHeading,
163
- );
164
- const firstSectionIndex = firstSection
165
- ? lines.findIndex((line) => line.trim() === firstSection)
166
- : -1;
167
- if (
168
- headingIndex < 0 &&
169
- outputHeading.startsWith("# Assessment Stage:") &&
170
- firstSectionIndex >= 0
171
- ) {
172
- const preamble = lines.slice(0, firstSectionIndex).join("\n");
173
- if (preamble.length > 2_000) {
174
- throw new Error(
175
- `Agent response contains too much text before the required section '${firstSection}'.`,
176
- );
177
- }
178
- const normalized = lines.slice(firstSectionIndex).join("\n").trim();
179
- if (/```/.test(preamble) || /(?:^|\n)```\s*$/.test(normalized)) {
180
- throw new Error(
181
- `Agent response must return '${outputHeading}' as plain Markdown, without a code fence.`,
182
- );
183
- }
184
- return `${outputHeading}\n\n${normalized}`;
185
- }
186
- const preamble =
187
- headingIndex >= 0 ? lines.slice(0, headingIndex).join("\n") : content;
188
- if (headingIndex < 0) {
189
- throw new Error(
190
- `Agent response is missing the required heading '${outputHeading}'.`,
191
- );
192
- }
193
- if (preamble.length > 2_000) {
194
- throw new Error(
195
- `Agent response contains too much text before the required heading '${outputHeading}'.`,
196
- );
197
- }
198
- const normalized = lines.slice(headingIndex).join("\n").trim();
199
- if (/```/.test(preamble) || /(?:^|\n)```\s*$/.test(normalized)) {
200
- throw new Error(
201
- `Agent response must return '${outputHeading}' as plain Markdown, without a code fence.`,
202
- );
203
- }
204
- return normalized;
205
- }
206
-
207
- function hasRequiredAssessmentSections(content, outputHeading) {
208
- const sections =
209
- outputHeading === "# Workspace Assessment"
210
- ? [
211
- "## Executive Summary",
212
- "## Assessment Delta",
213
- "## Current System Map",
214
- "## Observed Capabilities",
215
- "## Findings",
216
- "## Implementation Scorecard",
217
- "## Highest-Return Actions",
218
- "## Commands Observed",
219
- ]
220
- : [
221
- "## Updated Executive Summary",
222
- "## Assessment Delta",
223
- "## Current System Map",
224
- "## Capability Changes",
225
- "## Finding Changes",
226
- "## Scorecard Changes",
227
- "## Highest-Return Actions",
228
- "## Commands Observed",
229
- ];
230
- return sections.every((section) =>
231
- new RegExp(`(?:^|\\n)${section.replace(/[.*+?^${}()|[\\]\\]/g, "\\$&")}\\s*$`, "m").test(
232
- content,
233
- ),
234
- );
235
- }
236
-
237
- function bundledSkill(skillName) {
238
- const cached = skillCache.get(skillName);
239
- if (cached) return cached;
240
- try {
241
- const content = readFileSync(
242
- new URL(`./skills/${skillName}/SKILL.md`, import.meta.url),
243
- "utf8",
244
- ).trim();
245
- skillCache.set(skillName, content);
246
- return content;
247
- } catch (error) {
248
- throw new Error(
249
- `EngineerOS bundled skill '${skillName}' is unavailable. Reinstall @engineeros/connector.`,
250
- { cause: error },
251
- );
252
- }
253
- }
254
-
255
- function normalizedOutputHeading(value) {
256
- if (value === undefined || value === null) return null;
257
- const heading = String(value).trim();
258
- if (!/^# [^\r\n]+$/.test(heading)) {
259
- throw new Error(
260
- "EngineerOS requiredOutputHeading must be one level-one Markdown heading.",
261
- );
262
- }
263
- return heading;
264
- }