@engineeros/connector 0.8.6 → 0.8.8

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 CHANGED
@@ -40,10 +40,11 @@ An empty or document-only folder establishes a greenfield baseline. A code-beari
40
40
  ## Reconnect
41
41
 
42
42
  ```sh
43
- npx @engineeros/connector start --workspace .
43
+ npx --yes @engineeros/connector@latest start --workspace .
44
44
  ```
45
45
 
46
46
  Credentials are stored per workspace under `~/.engineeros/connectors` with owner-only permissions where supported.
47
+ If a new pairing command is accidentally run from the same folder against the same EngineerOS server, the connector reuses this saved identity instead of creating another baseline assessment.
47
48
 
48
49
  ## Run Goals
49
50
 
@@ -3,7 +3,9 @@ import os from "node:os";
3
3
  import path from "node:path";
4
4
  import {
5
5
  assessmentResultUrl,
6
+ connectorResumeCredentials,
6
7
  loadConfig,
8
+ mergePairedConfig,
7
9
  resultUrl,
8
10
  saveConfig,
9
11
  socketUrl,
@@ -59,6 +61,7 @@ if (command === "status") {
59
61
 
60
62
  let config;
61
63
  let firstMessage;
64
+ let existingConfig;
62
65
  if (command === "pair") {
63
66
  const pairingCode = positional[0];
64
67
  if (!pairingCode)
@@ -81,11 +84,13 @@ if (command === "pair") {
81
84
  flags.name ||
82
85
  `${os.hostname()} - ${path.basename(path.resolve(flags.workspace || process.cwd()))}`,
83
86
  };
87
+ existingConfig = await loadConfig(config.workspace);
84
88
  firstMessage = {
85
89
  type: "pair",
86
90
  pairing_code: pairingCode,
87
91
  name: config.name,
88
92
  capabilities: {},
93
+ ...connectorResumeCredentials(existingConfig, config.server_url),
89
94
  };
90
95
  } else if (command === "start") {
91
96
  config = await loadConfig(flags.workspace || process.cwd());
@@ -157,11 +162,14 @@ async function connect() {
157
162
  const message = JSON.parse(String(event.data));
158
163
  if (message.type === "paired") {
159
164
  clearConnectionWatchdog?.();
160
- config = {
161
- ...config,
162
- connector_id: message.connector.id,
163
- token: message.token,
164
- };
165
+ const reusedConnector =
166
+ existingConfig?.connector_id === message.connector.id;
167
+ config = mergePairedConfig(
168
+ config,
169
+ existingConfig,
170
+ message.connector.id,
171
+ message.token,
172
+ );
165
173
  await saveConfig(config);
166
174
  firstMessage = {
167
175
  type: "authenticate",
@@ -169,7 +177,11 @@ async function connect() {
169
177
  token: config.token,
170
178
  capabilities,
171
179
  };
172
- console.log(`Paired. Connector ${config.connector_id} is online.`);
180
+ console.log(
181
+ reusedConnector
182
+ ? `Reconnected existing workspace connector ${config.connector_id}; assessment history is preserved.`
183
+ : `Paired. Connector ${config.connector_id} is online.`,
184
+ );
173
185
  reconnectDelay = 1_000;
174
186
  startPings();
175
187
  if (config.onboarding_pending) void submitWorkspaceSnapshot();
@@ -259,13 +271,16 @@ async function connect() {
259
271
  console.error(`EngineerOS: ${message.message}`);
260
272
  }
261
273
  });
262
- socket.addEventListener("close", () => {
274
+ socket.addEventListener("close", (event) => {
263
275
  clearConnectionWatchdog?.();
264
276
  clearInterval(pingTimer);
265
277
  if (active?.kind === "prompt") {
266
278
  active.cancelled = true;
267
279
  void stopProcess(active.child);
268
280
  }
281
+ if (event.code === 4001 && active?.kind === "assessment") {
282
+ void stopProcess(active.child);
283
+ }
269
284
  if (connectionRejected) {
270
285
  stopped = true;
271
286
  console.error(
@@ -416,7 +431,7 @@ async function executePrompt(assignment) {
416
431
  lastProgressMessage = message;
417
432
  sendPromptProgress(promptId, message);
418
433
  };
419
- sendPromptProgress(promptId, "Coding agent started this request");
434
+ sendPromptProgress(promptId, "Agent started this request");
420
435
  console.log(
421
436
  `Answering ${assignment.purpose || "project"} prompt with ${codingAgent.name}.`,
422
437
  );
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@engineeros/connector",
3
- "version": "0.8.6",
3
+ "version": "0.8.8",
4
4
  "description": "Connect a local coding agent to EngineerOS, using ACP when supported.",
5
5
  "private": false,
6
6
  "type": "module",
package/src/config.mjs CHANGED
@@ -24,6 +24,36 @@ export function socketUrl(value) {
24
24
  return url.toString();
25
25
  }
26
26
 
27
+ export function connectorResumeCredentials(config, serverUrl) {
28
+ if (
29
+ !config?.connector_id ||
30
+ !config.token ||
31
+ config.server_url !== serverUrl
32
+ ) {
33
+ return {};
34
+ }
35
+ return {
36
+ existing_connector_id: config.connector_id,
37
+ existing_token: config.token,
38
+ };
39
+ }
40
+
41
+ export function mergePairedConfig(
42
+ requestedConfig,
43
+ existingConfig,
44
+ connectorId,
45
+ token,
46
+ ) {
47
+ const preserved =
48
+ existingConfig?.connector_id === connectorId ? existingConfig : {};
49
+ return {
50
+ ...preserved,
51
+ ...requestedConfig,
52
+ connector_id: connectorId,
53
+ token,
54
+ };
55
+ }
56
+
27
57
  export function resultUrl(websocketUrl, connectorId, runId) {
28
58
  const url = new URL(websocketUrl);
29
59
  url.protocol = url.protocol === "wss:" ? "https:" : "http:";
package/src/runner.mjs CHANGED
@@ -587,9 +587,9 @@ export function promptProgressMessage(event) {
587
587
  if (event.type === "item.completed" && event.item?.type === "agent_message") {
588
588
  return "Preparing the response";
589
589
  }
590
- if (event.type === "agent.connected") return "Connected to the coding agent";
590
+ if (event.type === "agent.connected") return "Agent connected";
591
591
  if (event.type === "acp.tool_call" || event.type === "acp.tool_call_update") {
592
- return "Inspecting the workspace with the coding agent";
592
+ return "Agent is inspecting the workspace";
593
593
  }
594
594
  if (event.type === "acp.agent_message_chunk") return "Preparing the response";
595
595
  return null;
@@ -597,15 +597,15 @@ export function promptProgressMessage(event) {
597
597
 
598
598
  export function promptQueueMessage(activeKind) {
599
599
  if (activeKind === "assessment") {
600
- return "Queued: coding agent is finishing the workspace assessment";
600
+ return "Queued: agent is finishing the workspace assessment";
601
601
  }
602
602
  if (activeKind === "goal") {
603
- return "Queued: coding agent is finishing an active Goal";
603
+ return "Queued: agent is finishing an active Goal";
604
604
  }
605
605
  if (activeKind === "prompt") {
606
- return "Queued: coding agent is finishing another request";
606
+ return "Queued: agent is finishing another request";
607
607
  }
608
- return "Coding agent accepted the request";
608
+ return "Agent accepted the request";
609
609
  }
610
610
 
611
611
  function assessmentCommandMilestone(command) {
@@ -882,22 +882,29 @@ export function codexExecutionArgs({
882
882
  if (profile.reasoning_effort) {
883
883
  optionArgs.push(
884
884
  "--config",
885
- `model_reasoning_effort=${JSON.stringify(profile.reasoning_effort)}`,
885
+ codexConfigArgument(
886
+ `model_reasoning_effort=${tomlLiteralString(profile.reasoning_effort)}`,
887
+ ),
886
888
  );
887
889
  }
888
890
  if (mcpServer) {
891
+ const mcpArgs = [
892
+ mcpServer.connectorBin,
893
+ "mcp",
894
+ "--workspace",
895
+ mcpServer.workspace,
896
+ "--run-id",
897
+ mcpServer.runId,
898
+ ];
889
899
  optionArgs.push(
890
900
  "--config",
891
- `mcp_servers.engineeros.command=${JSON.stringify(process.execPath)}`,
901
+ codexConfigArgument(
902
+ `mcp_servers.engineeros.command=${tomlLiteralString(process.execPath)}`,
903
+ ),
892
904
  "--config",
893
- `mcp_servers.engineeros.args=${JSON.stringify([
894
- mcpServer.connectorBin,
895
- "mcp",
896
- "--workspace",
897
- mcpServer.workspace,
898
- "--run-id",
899
- mcpServer.runId,
900
- ])}`,
905
+ codexConfigArgument(
906
+ `mcp_servers.engineeros.args=[${mcpArgs.map(tomlLiteralString).join(",")}]`,
907
+ ),
901
908
  );
902
909
  }
903
910
  return previousSessionId
@@ -905,6 +912,20 @@ export function codexExecutionArgs({
905
912
  : ["exec", ...optionArgs, "--sandbox", sandbox, "-C", workspace, "-"];
906
913
  }
907
914
 
915
+ function tomlLiteralString(value) {
916
+ const text = String(value);
917
+ if (text.includes("'''")) {
918
+ throw new Error(
919
+ "Codex configuration values cannot contain three consecutive apostrophes.",
920
+ );
921
+ }
922
+ return `'''${text}'''`;
923
+ }
924
+
925
+ function codexConfigArgument(override) {
926
+ return process.platform === "win32" ? `"${override}"` : override;
927
+ }
928
+
908
929
  function launchAgentProcess(
909
930
  workspace,
910
931
  prompt,