@engineeros/connector 0.11.2 → 0.12.2
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/bin/engineeros-connector.mjs +791 -790
- package/package.json +38 -37
- package/src/acp-client.mjs +63 -41
- package/src/agent-harness.mjs +51 -51
- package/src/capabilities.mjs +9 -9
- package/src/codex-app-server.mjs +235 -207
- package/src/runner.mjs +1661 -1654
package/package.json
CHANGED
|
@@ -1,40 +1,41 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "@engineeros/connector",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "Connect a local coding agent to EngineerOS, using ACP when supported.",
|
|
5
|
-
"private": false,
|
|
6
|
-
"type": "module",
|
|
7
|
-
"license": "UNLICENSED",
|
|
8
|
-
"files": [
|
|
9
|
-
"bin",
|
|
10
|
-
"src",
|
|
11
|
-
"README.md"
|
|
12
|
-
],
|
|
13
|
-
"bin": {
|
|
14
|
-
"engineeros-connector": "bin/engineeros-connector.mjs"
|
|
15
|
-
},
|
|
16
|
-
"scripts": {
|
|
17
|
-
"start": "node ./bin/engineeros-connector.mjs",
|
|
18
|
-
"prepublishOnly": "node ./scripts/release.mjs check",
|
|
19
|
-
"release:patch": "node ./scripts/release.mjs patch",
|
|
20
|
-
"test": "node --test --test-concurrency=1",
|
|
21
|
-
"type-check": "node --check ./bin/engineeros-connector.mjs && node --check ./scripts/release.mjs && node --check ./src/acp-client.mjs && node --check ./src/agent-harness.mjs && node --check ./src/agent-registry.mjs && node --check ./src/capabilities.mjs && node --check ./src/cli-args.mjs && node --check ./src/codex-app-server.mjs && node --check ./src/config.mjs && node --check ./src/connection.mjs && node --check ./src/mcp-server.mjs && node --check ./src/runner.mjs"
|
|
22
|
-
},
|
|
23
|
-
"engines": {
|
|
24
|
-
"node": ">=22"
|
|
25
|
-
},
|
|
26
|
-
"repository": {
|
|
27
|
-
"type": "git",
|
|
28
|
-
"url": "git+https://github.com/vinpuli/engineerosv2.git",
|
|
29
|
-
"directory": "packages/engineeros-connector"
|
|
30
|
-
},
|
|
31
|
-
"bugs": {
|
|
32
|
-
"url": "https://github.com/vinpuli/engineerosv2/issues"
|
|
33
|
-
},
|
|
34
|
-
"publishConfig": {
|
|
35
|
-
"access": "public"
|
|
36
|
-
},
|
|
1
|
+
{
|
|
2
|
+
"name": "@engineeros/connector",
|
|
3
|
+
"version": "0.12.2",
|
|
4
|
+
"description": "Connect a local coding agent to EngineerOS, using ACP when supported.",
|
|
5
|
+
"private": false,
|
|
6
|
+
"type": "module",
|
|
7
|
+
"license": "UNLICENSED",
|
|
8
|
+
"files": [
|
|
9
|
+
"bin",
|
|
10
|
+
"src",
|
|
11
|
+
"README.md"
|
|
12
|
+
],
|
|
13
|
+
"bin": {
|
|
14
|
+
"engineeros-connector": "bin/engineeros-connector.mjs"
|
|
15
|
+
},
|
|
16
|
+
"scripts": {
|
|
17
|
+
"start": "node ./bin/engineeros-connector.mjs",
|
|
18
|
+
"prepublishOnly": "node ./scripts/release.mjs check",
|
|
19
|
+
"release:patch": "node ./scripts/release.mjs patch",
|
|
20
|
+
"test": "node --test --test-concurrency=1",
|
|
21
|
+
"type-check": "node --check ./bin/engineeros-connector.mjs && node --check ./scripts/release.mjs && node --check ./src/acp-client.mjs && node --check ./src/agent-harness.mjs && node --check ./src/agent-registry.mjs && node --check ./src/capabilities.mjs && node --check ./src/cli-args.mjs && node --check ./src/codex-app-server.mjs && node --check ./src/config.mjs && node --check ./src/connection.mjs && node --check ./src/mcp-server.mjs && node --check ./src/runner.mjs"
|
|
22
|
+
},
|
|
23
|
+
"engines": {
|
|
24
|
+
"node": ">=22"
|
|
25
|
+
},
|
|
26
|
+
"repository": {
|
|
27
|
+
"type": "git",
|
|
28
|
+
"url": "git+https://github.com/vinpuli/engineerosv2.git",
|
|
29
|
+
"directory": "packages/engineeros-connector"
|
|
30
|
+
},
|
|
31
|
+
"bugs": {
|
|
32
|
+
"url": "https://github.com/vinpuli/engineerosv2/issues"
|
|
33
|
+
},
|
|
34
|
+
"publishConfig": {
|
|
35
|
+
"access": "public"
|
|
36
|
+
},
|
|
37
37
|
"dependencies": {
|
|
38
|
-
"@agentclientprotocol/sdk": "1.3.0"
|
|
38
|
+
"@agentclientprotocol/sdk": "1.3.0",
|
|
39
|
+
"zod": "3.25.76"
|
|
39
40
|
}
|
|
40
41
|
}
|
package/src/acp-client.mjs
CHANGED
|
@@ -58,50 +58,50 @@ export function launchAcpAgent(
|
|
|
58
58
|
};
|
|
59
59
|
}
|
|
60
60
|
|
|
61
|
-
export async function disposeAcpRuntimes() {
|
|
61
|
+
export async function disposeAcpRuntimes() {
|
|
62
62
|
const active = [...runtimes.values()];
|
|
63
63
|
runtimes.clear();
|
|
64
64
|
await Promise.all(active.map((runtime) => runtime.dispose()));
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
export async function inspectAcpExecutionProfiles(workspace, config) {
|
|
68
|
-
const runtime = new AcpRuntime(workspace, config, () => {});
|
|
69
|
-
try {
|
|
70
|
-
await runtime.ready;
|
|
71
|
-
const response = await runtime.context.request(acp.methods.agent.session.new, {
|
|
72
|
-
cwd: workspace,
|
|
73
|
-
mcpServers: [],
|
|
74
|
-
});
|
|
75
|
-
return executionProfilesFromConfigOptions(response.configOptions);
|
|
76
|
-
} finally {
|
|
77
|
-
await runtime.dispose();
|
|
78
|
-
}
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
export function executionProfilesFromConfigOptions(configOptions = []) {
|
|
82
|
-
const selectOption = (category) =>
|
|
83
|
-
configOptions.find((candidate) => candidate.category === category && candidate.type === "select");
|
|
84
|
-
const selectValues = (option) =>
|
|
85
|
-
(option?.options || []).flatMap((candidate) =>
|
|
86
|
-
Array.isArray(candidate.options) ? candidate.options : [candidate],
|
|
87
|
-
);
|
|
88
|
-
const modelOption = selectOption("model");
|
|
89
|
-
const effortOption = selectOption("thought_level");
|
|
90
|
-
const models = selectValues(modelOption);
|
|
91
|
-
const efforts = selectValues(effortOption);
|
|
92
|
-
return {
|
|
93
|
-
model_selection: models.length > 0,
|
|
94
|
-
model_profiles: models.map((model) => ({
|
|
95
|
-
id: model.value,
|
|
96
|
-
name: model.name || model.value,
|
|
97
|
-
description: model.description || "",
|
|
98
|
-
is_default: model.value === modelOption.currentValue,
|
|
99
|
-
default_reasoning_effort: effortOption?.currentValue || null,
|
|
100
|
-
reasoning_efforts: efforts.map((effort) => effort.value),
|
|
101
|
-
})),
|
|
102
|
-
reasoning_efforts: efforts.map((effort) => effort.value),
|
|
103
|
-
};
|
|
104
|
-
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
export async function inspectAcpExecutionProfiles(workspace, config) {
|
|
68
|
+
const runtime = new AcpRuntime(workspace, config, () => {});
|
|
69
|
+
try {
|
|
70
|
+
await runtime.ready;
|
|
71
|
+
const response = await runtime.context.request(acp.methods.agent.session.new, {
|
|
72
|
+
cwd: workspace,
|
|
73
|
+
mcpServers: [],
|
|
74
|
+
});
|
|
75
|
+
return executionProfilesFromConfigOptions(response.configOptions);
|
|
76
|
+
} finally {
|
|
77
|
+
await runtime.dispose();
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
export function executionProfilesFromConfigOptions(configOptions = []) {
|
|
82
|
+
const selectOption = (category) =>
|
|
83
|
+
configOptions.find((candidate) => candidate.category === category && candidate.type === "select");
|
|
84
|
+
const selectValues = (option) =>
|
|
85
|
+
(option?.options || []).flatMap((candidate) =>
|
|
86
|
+
Array.isArray(candidate.options) ? candidate.options : [candidate],
|
|
87
|
+
);
|
|
88
|
+
const modelOption = selectOption("model");
|
|
89
|
+
const effortOption = selectOption("thought_level");
|
|
90
|
+
const models = selectValues(modelOption);
|
|
91
|
+
const efforts = selectValues(effortOption);
|
|
92
|
+
return {
|
|
93
|
+
model_selection: models.length > 0,
|
|
94
|
+
model_profiles: models.map((model) => ({
|
|
95
|
+
id: model.value,
|
|
96
|
+
name: model.name || model.value,
|
|
97
|
+
description: model.description || "",
|
|
98
|
+
is_default: model.value === modelOption.currentValue,
|
|
99
|
+
default_reasoning_effort: effortOption?.currentValue || null,
|
|
100
|
+
reasoning_efforts: efforts.map((effort) => effort.value),
|
|
101
|
+
})),
|
|
102
|
+
reasoning_efforts: efforts.map((effort) => effort.value),
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
105
|
|
|
106
106
|
export function activeAcpRuntimeCount() {
|
|
107
107
|
return runtimes.size;
|
|
@@ -230,6 +230,7 @@ class AcpRuntime {
|
|
|
230
230
|
finalMessage: turn.finalMessage,
|
|
231
231
|
model: profile.model || this.config.agent_name || "acp-agent",
|
|
232
232
|
sessionId: session.sessionId,
|
|
233
|
+
usage: normalizeTokenUsage(response.usage),
|
|
233
234
|
};
|
|
234
235
|
} catch (error) {
|
|
235
236
|
throw this.failure("failed", error);
|
|
@@ -410,6 +411,27 @@ class AcpRuntime {
|
|
|
410
411
|
}
|
|
411
412
|
}
|
|
412
413
|
|
|
414
|
+
export function normalizeTokenUsage(value) {
|
|
415
|
+
if (!value || typeof value !== "object") return null;
|
|
416
|
+
const number = (...keys) => {
|
|
417
|
+
for (const key of keys) {
|
|
418
|
+
const candidate = value[key];
|
|
419
|
+
if (Number.isFinite(candidate) && candidate >= 0) return Math.trunc(candidate);
|
|
420
|
+
}
|
|
421
|
+
return 0;
|
|
422
|
+
};
|
|
423
|
+
const usage = {
|
|
424
|
+
input_tokens: number("inputTokens", "input_tokens"),
|
|
425
|
+
output_tokens: number("outputTokens", "output_tokens"),
|
|
426
|
+
cache_read_tokens: number("cachedReadTokens", "cachedInputTokens", "cache_read_input_tokens"),
|
|
427
|
+
cache_write_tokens: number("cachedWriteTokens", "cache_creation_input_tokens"),
|
|
428
|
+
reasoning_tokens: number("reasoningTokens", "reasoningOutputTokens", "reasoning_tokens"),
|
|
429
|
+
};
|
|
430
|
+
usage.total_tokens = number("totalTokens", "total_tokens") ||
|
|
431
|
+
Object.values(usage).reduce((total, tokens) => total + tokens, 0);
|
|
432
|
+
return usage.total_tokens > 0 ? usage : null;
|
|
433
|
+
}
|
|
434
|
+
|
|
413
435
|
function acpRuntimeKey(workspace, config) {
|
|
414
436
|
return JSON.stringify([
|
|
415
437
|
workspace,
|
package/src/agent-harness.mjs
CHANGED
|
@@ -137,25 +137,25 @@ export function normalizeAgentStructuredOutput(
|
|
|
137
137
|
"EngineerOS structured output requires a heading contract.",
|
|
138
138
|
);
|
|
139
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
|
-
}[outputHeading];
|
|
148
|
-
if (
|
|
149
|
-
firstSection &&
|
|
150
|
-
(content.startsWith(firstSection) ||
|
|
151
|
-
hasRequiredAssessmentSections(content, outputHeading))
|
|
152
|
-
) {
|
|
153
|
-
return `${outputHeading}\n\n${content}`;
|
|
154
|
-
}
|
|
155
|
-
const lines = content.split(/\r?\n/);
|
|
156
|
-
const headingIndex = lines.findIndex(
|
|
157
|
-
(line) => line.trim() === outputHeading,
|
|
158
|
-
);
|
|
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
|
+
}[outputHeading];
|
|
148
|
+
if (
|
|
149
|
+
firstSection &&
|
|
150
|
+
(content.startsWith(firstSection) ||
|
|
151
|
+
hasRequiredAssessmentSections(content, outputHeading))
|
|
152
|
+
) {
|
|
153
|
+
return `${outputHeading}\n\n${content}`;
|
|
154
|
+
}
|
|
155
|
+
const lines = content.split(/\r?\n/);
|
|
156
|
+
const headingIndex = lines.findIndex(
|
|
157
|
+
(line) => line.trim() === outputHeading,
|
|
158
|
+
);
|
|
159
159
|
const preamble =
|
|
160
160
|
headingIndex >= 0 ? lines.slice(0, headingIndex).join("\n") : content;
|
|
161
161
|
if (headingIndex < 0) {
|
|
@@ -174,38 +174,38 @@ export function normalizeAgentStructuredOutput(
|
|
|
174
174
|
`Agent response must return '${outputHeading}' as plain Markdown, without a code fence.`,
|
|
175
175
|
);
|
|
176
176
|
}
|
|
177
|
-
return normalized;
|
|
178
|
-
}
|
|
179
|
-
|
|
180
|
-
function hasRequiredAssessmentSections(content, outputHeading) {
|
|
181
|
-
const sections =
|
|
182
|
-
outputHeading === "# Workspace Assessment"
|
|
183
|
-
? [
|
|
184
|
-
"## Executive Summary",
|
|
185
|
-
"## Assessment Delta",
|
|
186
|
-
"## Current System Map",
|
|
187
|
-
"## Observed Capabilities",
|
|
188
|
-
"## Findings",
|
|
189
|
-
"## Implementation Scorecard",
|
|
190
|
-
"## Highest-Return Actions",
|
|
191
|
-
"## Commands Observed",
|
|
192
|
-
]
|
|
193
|
-
: [
|
|
194
|
-
"## Updated Executive Summary",
|
|
195
|
-
"## Assessment Delta",
|
|
196
|
-
"## Current System Map",
|
|
197
|
-
"## Capability Changes",
|
|
198
|
-
"## Finding Changes",
|
|
199
|
-
"## Scorecard Changes",
|
|
200
|
-
"## Highest-Return Actions",
|
|
201
|
-
"## Commands Observed",
|
|
202
|
-
];
|
|
203
|
-
return sections.every((section) =>
|
|
204
|
-
new RegExp(`(?:^|\\n)${section.replace(/[.*+?^${}()|[\\]\\]/g, "\\$&")}\\s*$`, "m").test(
|
|
205
|
-
content,
|
|
206
|
-
),
|
|
207
|
-
);
|
|
208
|
-
}
|
|
177
|
+
return normalized;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
function hasRequiredAssessmentSections(content, outputHeading) {
|
|
181
|
+
const sections =
|
|
182
|
+
outputHeading === "# Workspace Assessment"
|
|
183
|
+
? [
|
|
184
|
+
"## Executive Summary",
|
|
185
|
+
"## Assessment Delta",
|
|
186
|
+
"## Current System Map",
|
|
187
|
+
"## Observed Capabilities",
|
|
188
|
+
"## Findings",
|
|
189
|
+
"## Implementation Scorecard",
|
|
190
|
+
"## Highest-Return Actions",
|
|
191
|
+
"## Commands Observed",
|
|
192
|
+
]
|
|
193
|
+
: [
|
|
194
|
+
"## Updated Executive Summary",
|
|
195
|
+
"## Assessment Delta",
|
|
196
|
+
"## Current System Map",
|
|
197
|
+
"## Capability Changes",
|
|
198
|
+
"## Finding Changes",
|
|
199
|
+
"## Scorecard Changes",
|
|
200
|
+
"## Highest-Return Actions",
|
|
201
|
+
"## Commands Observed",
|
|
202
|
+
];
|
|
203
|
+
return sections.every((section) =>
|
|
204
|
+
new RegExp(`(?:^|\\n)${section.replace(/[.*+?^${}()|[\\]\\]/g, "\\$&")}\\s*$`, "m").test(
|
|
205
|
+
content,
|
|
206
|
+
),
|
|
207
|
+
);
|
|
208
|
+
}
|
|
209
209
|
|
|
210
210
|
function bundledSkill(skillName) {
|
|
211
211
|
const cached = skillCache.get(skillName);
|
package/src/capabilities.mjs
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import path from "node:path";
|
|
2
2
|
import { agentHarnessCapabilities } from "./agent-harness.mjs";
|
|
3
3
|
|
|
4
|
-
export function advertisedCapabilities(config, codingAgent) {
|
|
5
|
-
const executionProfiles = codingAgent.executionProfiles || {
|
|
6
|
-
model_selection: false,
|
|
7
|
-
model_profiles: [],
|
|
8
|
-
reasoning_efforts: [],
|
|
9
|
-
};
|
|
4
|
+
export function advertisedCapabilities(config, codingAgent) {
|
|
5
|
+
const executionProfiles = codingAgent.executionProfiles || {
|
|
6
|
+
model_selection: false,
|
|
7
|
+
model_profiles: [],
|
|
8
|
+
reasoning_efforts: [],
|
|
9
|
+
};
|
|
10
10
|
return {
|
|
11
11
|
agent_protocols: [codingAgent.protocol],
|
|
12
12
|
coding_agent: true,
|
|
@@ -16,9 +16,9 @@ export function advertisedCapabilities(config, codingAgent) {
|
|
|
16
16
|
agent_name: codingAgent.name,
|
|
17
17
|
agent_version: codingAgent.version,
|
|
18
18
|
...agentHarnessCapabilities(),
|
|
19
|
-
execution_profiles: {
|
|
20
|
-
...executionProfiles,
|
|
21
|
-
models: (executionProfiles.model_profiles || []).map((model) => model.id),
|
|
19
|
+
execution_profiles: {
|
|
20
|
+
...executionProfiles,
|
|
21
|
+
models: (executionProfiles.model_profiles || []).map((model) => model.id),
|
|
22
22
|
},
|
|
23
23
|
};
|
|
24
24
|
}
|