@engineeros/connector 0.10.2 → 0.10.4

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/package.json CHANGED
@@ -1,40 +1,40 @@
1
- {
2
- "name": "@engineeros/connector",
3
- "version": "0.10.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/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
- "dependencies": {
38
- "@agentclientprotocol/sdk": "1.3.0"
39
- }
40
- }
1
+ {
2
+ "name": "@engineeros/connector",
3
+ "version": "0.10.4",
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
+ "dependencies": {
38
+ "@agentclientprotocol/sdk": "1.3.0"
39
+ }
40
+ }
@@ -58,11 +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
- }
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
+ }
66
105
 
67
106
  export function activeAcpRuntimeCount() {
68
107
  return runtimes.size;
@@ -1,29 +1,24 @@
1
- import path from "node:path";
2
- import { agentHarnessCapabilities } from "./agent-harness.mjs";
3
-
1
+ import path from "node:path";
2
+ import { agentHarnessCapabilities } from "./agent-harness.mjs";
3
+
4
4
  export function advertisedCapabilities(config, codingAgent) {
5
- const configuredModels = String(
6
- process.env.ENGINEEROS_AGENT_MODELS || "gpt-5.6-sol,gpt-5.6-terra",
7
- )
8
- .split(",")
9
- .map((model) => model.trim())
10
- .filter(Boolean);
11
- return {
12
- agent_protocols: [codingAgent.protocol],
13
- coding_agent: true,
14
- codex_cli: codingAgent.protocol === "codex",
15
- platform: process.platform,
16
- workspace_name: path.basename(config.workspace),
17
- agent_name: codingAgent.name,
18
- agent_version: codingAgent.version,
19
- ...agentHarnessCapabilities(),
20
- execution_profiles: {
21
- model_selection: codingAgent.protocol === "codex",
22
- models: codingAgent.protocol === "codex" ? configuredModels : [],
23
- reasoning_efforts:
24
- codingAgent.protocol === "codex"
25
- ? ["low", "medium", "high", "xhigh"]
26
- : [],
27
- },
5
+ const executionProfiles = codingAgent.executionProfiles || {
6
+ model_selection: false,
7
+ model_profiles: [],
8
+ reasoning_efforts: [],
28
9
  };
29
- }
10
+ return {
11
+ agent_protocols: [codingAgent.protocol],
12
+ coding_agent: true,
13
+ codex_cli: codingAgent.protocol === "codex",
14
+ platform: process.platform,
15
+ workspace_name: path.basename(config.workspace),
16
+ agent_name: codingAgent.name,
17
+ agent_version: codingAgent.version,
18
+ ...agentHarnessCapabilities(),
19
+ execution_profiles: {
20
+ ...executionProfiles,
21
+ models: (executionProfiles.model_profiles || []).map((model) => model.id),
22
+ },
23
+ };
24
+ }
@@ -1,5 +1,84 @@
1
1
  import { spawn } from "node:child_process";
2
- import readline from "node:readline";
2
+ import readline from "node:readline";
3
+
4
+ export async function inspectCodexExecutionProfiles({
5
+ workspace,
6
+ command = process.env.CODEX_BIN || (process.platform === "win32" ? "codex.cmd" : "codex"),
7
+ spawnProcess = spawn,
8
+ timeoutMs = 15_000,
9
+ }) {
10
+ const child = spawnProcess(command, ["app-server", "--stdio"], {
11
+ cwd: workspace,
12
+ env: process.env,
13
+ shell: process.platform === "win32",
14
+ windowsHide: true,
15
+ stdio: ["pipe", "pipe", "pipe"],
16
+ });
17
+ const pending = new Map();
18
+ let requestId = 0;
19
+ let stderr = "";
20
+ const request = (method, params) => new Promise((resolve, reject) => {
21
+ const id = ++requestId;
22
+ pending.set(id, { resolve, reject });
23
+ child.stdin.write(`${JSON.stringify({ id, method, params })}\n`);
24
+ });
25
+ const lines = readline.createInterface({ input: child.stdout });
26
+ lines.on("line", (line) => {
27
+ try {
28
+ const message = JSON.parse(line);
29
+ const waiter = pending.get(message.id);
30
+ if (!waiter) return;
31
+ pending.delete(message.id);
32
+ if (message.error) waiter.reject(new Error(message.error.message || "Codex model discovery failed."));
33
+ else waiter.resolve(message.result);
34
+ } catch {
35
+ // Ignore non-protocol output.
36
+ }
37
+ });
38
+ child.stderr.setEncoding("utf8");
39
+ child.stderr.on("data", (chunk) => { stderr = `${stderr}${chunk}`.slice(-4_000); });
40
+ const rejectPending = (message) => {
41
+ for (const waiter of pending.values()) waiter.reject(new Error(message));
42
+ pending.clear();
43
+ };
44
+ child.once("error", (error) => rejectPending(error.message));
45
+ child.once("close", (code) => {
46
+ if (pending.size) rejectPending(`Codex model discovery stopped with code ${code ?? 1}. ${stderr}`.trim());
47
+ });
48
+ const timeout = setTimeout(() => {
49
+ rejectPending("Codex model discovery timed out.");
50
+ child.kill();
51
+ }, timeoutMs);
52
+ try {
53
+ await request("initialize", {
54
+ clientInfo: { name: "engineeros-connector", title: "EngineerOS Connector", version: "0.10.4" },
55
+ });
56
+ child.stdin.write(`${JSON.stringify({ method: "initialized" })}\n`);
57
+ const models = [];
58
+ let cursor = null;
59
+ do {
60
+ const result = await request("model/list", { cursor, includeHidden: false });
61
+ models.push(...(Array.isArray(result?.data) ? result.data : []));
62
+ cursor = result?.nextCursor || null;
63
+ } while (cursor);
64
+ return models.map((item) => ({
65
+ id: item.model || item.id,
66
+ name: item.displayName || item.model || item.id,
67
+ description: item.description || "",
68
+ is_default: item.isDefault === true,
69
+ default_reasoning_effort: item.defaultReasoningEffort || null,
70
+ reasoning_efforts: (item.supportedReasoningEfforts || [])
71
+ .map((option) => option.reasoningEffort)
72
+ .filter(Boolean),
73
+ })).filter((item) => item.id);
74
+ } catch (error) {
75
+ const detail = error instanceof Error ? error.message : String(error);
76
+ throw new Error(`${detail}${stderr ? ` ${stderr}` : ""}`.trim());
77
+ } finally {
78
+ clearTimeout(timeout);
79
+ child.kill();
80
+ }
81
+ }
3
82
 
4
83
  export function launchCodexAppServer({
5
84
  workspace,
@@ -89,7 +168,7 @@ export function launchCodexAppServer({
89
168
  void (async () => {
90
169
  try {
91
170
  await request("initialize", {
92
- clientInfo: { name: "engineeros-connector", title: "EngineerOS Connector", version: "0.10.1" },
171
+ clientInfo: { name: "engineeros-connector", title: "EngineerOS Connector", version: "0.10.4" },
93
172
  });
94
173
  child.stdin.write(`${JSON.stringify({ method: "initialized" })}\n`);
95
174
  const threadResult = previousSessionId
package/src/runner.mjs CHANGED
@@ -11,8 +11,11 @@ import os from "node:os";
11
11
  import path from "node:path";
12
12
  import { promisify } from "node:util";
13
13
  import { deflateRaw } from "node:zlib";
14
- import { launchAcpAgent } from "./acp-client.mjs";
15
- import { launchCodexAppServer } from "./codex-app-server.mjs";
14
+ import { inspectAcpExecutionProfiles, launchAcpAgent } from "./acp-client.mjs";
15
+ import {
16
+ inspectCodexExecutionProfiles,
17
+ launchCodexAppServer,
18
+ } from "./codex-app-server.mjs";
16
19
  import {
17
20
  buildAgentHarnessPrompt,
18
21
  normalizeAgentStructuredOutput,
@@ -526,22 +529,34 @@ export async function executeConnectedPrompt(assignment, config, callbacks) {
526
529
  };
527
530
  }
528
531
 
529
- export async function inspectCodingAgent(config, workspace = process.cwd()) {
532
+ export async function inspectCodingAgent(config, workspace = process.cwd()) {
530
533
  if (config.agent_protocol === "acp") {
531
534
  if (!config.agent_command) {
532
535
  throw new Error(
533
536
  "ACP requires --agent-command when pairing the connector.",
534
537
  );
535
538
  }
536
- return {
537
- protocol: "acp",
539
+ const executionProfiles = await inspectAcpExecutionProfiles(workspace, config);
540
+ return {
541
+ protocol: "acp",
538
542
  name: config.agent_name || path.basename(config.agent_command),
539
- version: config.agent_version || "ACP v1",
543
+ version: config.agent_version || "ACP v1",
544
+ executionProfiles,
540
545
  };
541
546
  }
542
- const codex = await inspectCodexCli(workspace);
543
- return { protocol: "codex", name: "Codex CLI", version: codex.version };
544
- }
547
+ const codex = await inspectCodexCli(workspace);
548
+ const modelProfiles = await inspectCodexExecutionProfiles({ workspace, command: codex.command });
549
+ return {
550
+ protocol: "codex",
551
+ name: "Codex CLI",
552
+ version: codex.version,
553
+ executionProfiles: {
554
+ model_selection: modelProfiles.length > 0,
555
+ model_profiles: modelProfiles,
556
+ reasoning_efforts: [...new Set(modelProfiles.flatMap((model) => model.reasoning_efforts))],
557
+ },
558
+ };
559
+ }
545
560
 
546
561
  export async function inspectCodexCli(workspace = process.cwd()) {
547
562
  const command =
@@ -727,10 +742,10 @@ export function connectorExecution(assignment, options = {}) {
727
742
  const model =
728
743
  typeof rawProfile.model === "string" ? rawProfile.model.trim() : "";
729
744
  const reasoningEffort = rawProfile.reasoning_effort;
730
- if (
731
- reasoningEffort &&
732
- !new Set(["low", "medium", "high", "xhigh"]).has(reasoningEffort)
733
- ) {
745
+ if (
746
+ reasoningEffort &&
747
+ !new Set(["minimal", "low", "medium", "high", "xhigh", "max", "ultra"]).has(reasoningEffort)
748
+ ) {
734
749
  throw new Error(
735
750
  "EngineerOS assignment has an unsupported reasoning effort.",
736
751
  );
@@ -1032,14 +1047,13 @@ export function codexExecutionArgs({
1032
1047
  : ["exec", ...optionArgs, "--sandbox", sandbox, "-C", workspace, "-"];
1033
1048
  }
1034
1049
 
1035
- export function sanitizeAgentResponse(value) {
1036
- return String(value || "")
1037
- .replace(
1038
- /^Warning: Exceeded skills context budget(?: of \d+%)?\. All skill descriptions were removed and \d+ additional skills? (?:was|were) not included in the model-visible skills list\.\s*/i,
1039
- "",
1040
- )
1041
- .trimStart();
1042
- }
1050
+ export function sanitizeAgentResponse(value) {
1051
+ return String(value || "")
1052
+ .replace(
1053
+ /^Warning: Exceeded skills context budget(?: of \d+%)?\. All skill descriptions were removed and \d+ additional skills? (?:was|were) not included in the model-visible skills list\.\s*/i,
1054
+ "",
1055
+ );
1056
+ }
1043
1057
 
1044
1058
  function tomlLiteralString(value) {
1045
1059
  const text = String(value);
@@ -1,12 +1,12 @@
1
- ---
2
- name: change-planning
3
- description: Produce a decision-complete implementation plan grounded in the connected repository.
4
- ---
5
-
6
- # Change Planning
7
-
8
- 1. Inspect current behavior, ownership boundaries, call paths, tests, and project instructions before proposing changes.
9
- 2. Define the intended outcome, affected components, non-goals, risks, and proof of completion.
10
- 3. Resolve questions answerable from the repository. Label only genuinely unavailable facts as assumptions.
11
- 4. Sequence bounded implementation steps with the files or symbols each step affects and the verification it requires.
12
- 5. Stay read-only and hand off a plan that an implementation Agent can execute without rediscovering the problem.
1
+ ---
2
+ name: change-planning
3
+ description: Produce a decision-complete implementation plan grounded in the connected repository.
4
+ ---
5
+
6
+ # Change Planning
7
+
8
+ 1. Inspect current behavior, ownership boundaries, call paths, tests, and project instructions before proposing changes.
9
+ 2. Define the intended outcome, affected components, non-goals, risks, and proof of completion.
10
+ 3. Resolve questions answerable from the repository. Label only genuinely unavailable facts as assumptions.
11
+ 4. Sequence bounded implementation steps with the files or symbols each step affects and the verification it requires.
12
+ 5. Stay read-only and hand off a plan that an implementation Agent can execute without rediscovering the problem.
@@ -1,12 +1,12 @@
1
- ---
2
- name: change-verification
3
- description: Independently verify a completed change against its explicit proof contract.
4
- ---
5
-
6
- # Change Verification
7
-
8
- 1. Inspect the exact supplied revision, changed paths, Goal boundaries, constraints, and every Proof item.
9
- 2. Run or inspect each check independently; do not rely on the implementation Agent's claims.
10
- 3. Stay read-only. Do not repair failures, edit files, install dependencies, commit, or push.
11
- 4. Mark a check passed only when directly observed evidence matches its expected result.
12
- 5. Return the requested structured verification report with concise commands, exit codes, and evidence.
1
+ ---
2
+ name: change-verification
3
+ description: Independently verify a completed change against its explicit proof contract.
4
+ ---
5
+
6
+ # Change Verification
7
+
8
+ 1. Inspect the exact supplied revision, changed paths, Goal boundaries, constraints, and every Proof item.
9
+ 2. Run or inspect each check independently; do not rely on the implementation Agent's claims.
10
+ 3. Stay read-only. Do not repair failures, edit files, install dependencies, commit, or push.
11
+ 4. Mark a check passed only when directly observed evidence matches its expected result.
12
+ 5. Return the requested structured verification report with concise commands, exit codes, and evidence.
@@ -1,12 +1,12 @@
1
- ---
2
- name: codebase-research
3
- description: Investigate a connected repository and answer from directly observed evidence.
4
- ---
5
-
6
- # Codebase Research
7
-
8
- 1. Define the exact question and inspect the smallest relevant surface first.
9
- 2. Trace callers, dependencies, data flow, configuration, and tests when they materially affect the answer.
10
- 3. Separate observed facts from inferences and cite concrete repository paths for important claims.
11
- 4. Stay read-only. Do not install, generate, edit, delete, commit, or start long-running services.
12
- 5. Return the answer first, followed by supporting evidence and unresolved gaps only when they matter.
1
+ ---
2
+ name: codebase-research
3
+ description: Investigate a connected repository and answer from directly observed evidence.
4
+ ---
5
+
6
+ # Codebase Research
7
+
8
+ 1. Define the exact question and inspect the smallest relevant surface first.
9
+ 2. Trace callers, dependencies, data flow, configuration, and tests when they materially affect the answer.
10
+ 3. Separate observed facts from inferences and cite concrete repository paths for important claims.
11
+ 4. Stay read-only. Do not install, generate, edit, delete, commit, or start long-running services.
12
+ 5. Return the answer first, followed by supporting evidence and unresolved gaps only when they matter.
@@ -1,12 +1,12 @@
1
- ---
2
- name: goal-execution
3
- description: Implement one bounded EngineerOS Goal and prove the resulting behavior.
4
- ---
5
-
6
- # Goal Execution
7
-
8
- 1. Read the complete Goal packet, repository instructions, current Git state, and relevant implementation paths.
9
- 2. Implement the smallest coherent change that satisfies the included outcome and constraints.
10
- 3. Preserve unrelated user changes and stay inside the stated boundary; stop only for a genuine missing authority or prerequisite.
11
- 4. Run focused checks while working, then the proportionate final tests, lint, type checks, or build required by the Goal.
12
- 5. Do not commit or push. EngineerOS creates the isolated run commit after the implementation completes.
1
+ ---
2
+ name: goal-execution
3
+ description: Implement one bounded EngineerOS Goal and prove the resulting behavior.
4
+ ---
5
+
6
+ # Goal Execution
7
+
8
+ 1. Read the complete Goal packet, repository instructions, current Git state, and relevant implementation paths.
9
+ 2. Implement the smallest coherent change that satisfies the included outcome and constraints.
10
+ 3. Preserve unrelated user changes and stay inside the stated boundary; stop only for a genuine missing authority or prerequisite.
11
+ 4. Run focused checks while working, then the proportionate final tests, lint, type checks, or build required by the Goal.
12
+ 5. Do not commit or push. EngineerOS creates the isolated run commit after the implementation completes.