@super-hands/connect 0.1.4 → 0.1.6

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.
Files changed (2) hide show
  1. package/client.mjs +67 -29
  2. package/package.json +1 -1
package/client.mjs CHANGED
@@ -32,7 +32,7 @@ function codexConfigBlock(args) {
32
32
  return [
33
33
  `[mcp_servers.${MCP_SERVER_KEY}]`,
34
34
  `url = "${args.endpoint}"`,
35
- `bearer_token = "${args.token}"`
35
+ `http_headers = { "Authorization" = "${mcpAuthorizationHeader(args.token)}" }`
36
36
  ].join("\n");
37
37
  }
38
38
 
@@ -94,6 +94,12 @@ function stop(message) {
94
94
  `);
95
95
  process.exit(1);
96
96
  }
97
+ function cursorServerEntry(args) {
98
+ return {
99
+ url: args.endpoint,
100
+ headers: { Authorization: mcpAuthorizationHeader(args.token) }
101
+ };
102
+ }
97
103
  function mergedCursorConfig(existing, args) {
98
104
  let config = {};
99
105
  if (existing !== null && existing.trim() !== "") {
@@ -111,21 +117,28 @@ function mergedCursorConfig(existing, args) {
111
117
  const serversRaw = config.mcpServers;
112
118
  const servers = typeof serversRaw === "object" && serversRaw !== null && !Array.isArray(serversRaw) ? serversRaw : {};
113
119
  const replaced = MCP_SERVER_KEY in servers;
114
- servers[MCP_SERVER_KEY] = {
115
- url: args.endpoint,
116
- headers: { Authorization: mcpAuthorizationHeader(args.token) }
117
- };
120
+ servers[MCP_SERVER_KEY] = cursorServerEntry(args);
118
121
  config.mcpServers = servers;
119
122
  return { text: `${JSON.stringify(config, null, 2)}
120
123
  `, replaced };
121
124
  }
122
125
  function appendedCodexConfig(existing, args) {
126
+ const staleOwnBlock = new RegExp(
127
+ `\\[mcp_servers\\.${MCP_SERVER_KEY}\\]\\nurl = "[^"\\n]*"\\nbearer_token = "[^"\\n]*"`
128
+ );
129
+ if (staleOwnBlock.test(existing)) {
130
+ return {
131
+ text: existing.replace(staleOwnBlock, codexConfigBlock(args)),
132
+ alreadyPresent: false,
133
+ repaired: true
134
+ };
135
+ }
123
136
  if (existing.includes(`[mcp_servers.${MCP_SERVER_KEY}]`)) {
124
- return { text: existing, alreadyPresent: true };
137
+ return { text: existing, alreadyPresent: true, repaired: false };
125
138
  }
126
139
  const sep = existing === "" || existing.endsWith("\n\n") ? "" : existing.endsWith("\n") ? "\n" : "\n\n";
127
140
  return { text: `${existing}${sep}${codexConfigBlock(args)}
128
- `, alreadyPresent: false };
141
+ `, alreadyPresent: false, repaired: false };
129
142
  }
130
143
  function writeSkill(clientDir) {
131
144
  const skillPath = join(clientDir, "skills", CONNECT_SKILL_DIR, CONNECT_SKILL_FILENAME);
@@ -188,26 +201,40 @@ async function main() {
188
201
  } catch {
189
202
  existing = null;
190
203
  }
204
+ let merged = null;
191
205
  try {
192
- const merged = mergedCursorConfig(existing, { endpoint, token });
193
- mkdirSync(dirname(configPath), { recursive: true });
194
- writeFileSync(configPath, merged.text);
195
- say(
196
- merged.replaced ? `Cursor \u2014 updated the ${MCP_SERVER_KEY} server in ${configPath}.` : `Cursor \u2014 added the ${MCP_SERVER_KEY} server to ${configPath}.`
197
- );
198
- if (openCursor()) {
199
- say(
200
- ` Cursor is opening \u2014 enable ${MCP_SERVER_KEY} under Settings \u2192 MCP. If it was already running, restart it first.`
201
- );
202
- } else {
203
- say(` Open Cursor (restart it if it was running), then enable ${MCP_SERVER_KEY} under Settings \u2192 MCP.`);
204
- }
205
- writeSkill(cursorDir);
206
- connected += 1;
206
+ merged = mergedCursorConfig(existing, { endpoint, token });
207
207
  } catch {
208
208
  say(`Cursor \u2014 ${configPath} is not valid JSON, so it was left untouched.`);
209
209
  say(" Fix or remove that file, then run this command again.");
210
210
  }
211
+ if (merged) {
212
+ try {
213
+ mkdirSync(dirname(configPath), { recursive: true });
214
+ writeFileSync(configPath, merged.text);
215
+ say(
216
+ merged.replaced ? `Cursor \u2014 updated the ${MCP_SERVER_KEY} server in ${configPath}.` : `Cursor \u2014 added the ${MCP_SERVER_KEY} server to ${configPath}.`
217
+ );
218
+ if (openCursor()) {
219
+ say(
220
+ ` Cursor is opening \u2014 enable ${MCP_SERVER_KEY} under Settings \u2192 MCP. If it was already running, restart it first.`
221
+ );
222
+ } else {
223
+ say(` Open Cursor (restart it if it was running), then enable ${MCP_SERVER_KEY} under Settings \u2192 MCP.`);
224
+ }
225
+ writeSkill(cursorDir);
226
+ connected += 1;
227
+ } catch {
228
+ say(`Cursor \u2014 ${configPath} could not be written, so it was left as it was.`);
229
+ say(
230
+ ' A sandboxed agent usually cannot write outside its workspace. Run this same command in a regular terminal, or add this under "mcpServers" in that file (or in .cursor/mcp.json inside the project, which connects this project alone):'
231
+ );
232
+ process.stdout.write(
233
+ `${JSON.stringify({ [MCP_SERVER_KEY]: cursorServerEntry({ endpoint, token }) }, null, 2)}
234
+ `
235
+ );
236
+ }
237
+ }
211
238
  }
212
239
  if (onlyClaude || autodetect && hasCli("claude")) {
213
240
  attempted += 1;
@@ -255,16 +282,27 @@ async function main() {
255
282
  const result = appendedCodexConfig(existing, { endpoint, token });
256
283
  if (result.alreadyPresent) {
257
284
  say(`Codex \u2014 ${configPath} already names a ${MCP_SERVER_KEY} server, so it was left as it is.`);
258
- say(" If that connection is stale, update bearer_token there by hand.");
285
+ say(" If that connection is stale, update the http_headers Authorization value there by hand.");
259
286
  writeSkill(codexDir);
260
287
  connected += 1;
261
288
  } else {
262
- mkdirSync(dirname(configPath), { recursive: true });
263
- writeFileSync(configPath, result.text);
264
- say(`Codex \u2014 added the ${MCP_SERVER_KEY} server to ${configPath}.`);
265
- say(" The app and the CLI both read this config \u2014 open either and it connects when a session starts.");
266
- writeSkill(codexDir);
267
- connected += 1;
289
+ try {
290
+ mkdirSync(dirname(configPath), { recursive: true });
291
+ writeFileSync(configPath, result.text);
292
+ say(
293
+ result.repaired ? `Codex \u2014 replaced the ${MCP_SERVER_KEY} entry in ${configPath}: its old bearer_token spelling makes current Codex reject the whole config.` : `Codex \u2014 added the ${MCP_SERVER_KEY} server to ${configPath}.`
294
+ );
295
+ say(" The app and the CLI both read this config \u2014 open either and it connects when a session starts.");
296
+ writeSkill(codexDir);
297
+ connected += 1;
298
+ } catch {
299
+ say(`Codex \u2014 ${configPath} could not be written, so it was left as it was.`);
300
+ say(
301
+ " A sandboxed agent usually cannot write outside its workspace. Run this same command in a regular terminal, or append this block to that file yourself:"
302
+ );
303
+ process.stdout.write(`${codexConfigBlock({ endpoint, token })}
304
+ `);
305
+ }
268
306
  }
269
307
  }
270
308
  if (connected === 0) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@super-hands/connect",
3
- "version": "0.1.4",
3
+ "version": "0.1.6",
4
4
  "description": "Connect the coding agents on this machine to your team's Superhands MCP server. Writes each client's own config; reads no repository, uploads nothing.",
5
5
  "bin": {
6
6
  "superhands-connect": "client.mjs"