@cabane/companion 0.6.234 → 0.6.236

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/dist/cli.js CHANGED
@@ -3205,9 +3205,11 @@ function envResolvedFrom(server, secretEnv) {
3205
3205
  if (!server.env && Object.keys(resolved).length === 0) return void 0;
3206
3206
  return { ...server.env, ...resolved };
3207
3207
  }
3208
+ var TURN_TOKEN_ENV;
3208
3209
  var init_mcp_secret_env = __esm({
3209
3210
  "packages/agent-runtime/src/mcp-secret-env.ts"() {
3210
3211
  "use strict";
3212
+ TURN_TOKEN_ENV = "CABANE_TURN_TOKEN";
3211
3213
  }
3212
3214
  });
3213
3215
 
@@ -3357,7 +3359,7 @@ function buildClaudeCodeOptions(req, augment) {
3357
3359
  type: "http",
3358
3360
  url: req.cabane.mcpUrl,
3359
3361
  headers: {
3360
- Authorization: `Bearer ${req.cabane.bearer}`,
3362
+ Authorization: `\${${TURN_TOKEN_ENV}}`,
3361
3363
  [ACTIVE_CONVERSATION_HEADER]: req.cabane.activeConversationId
3362
3364
  },
3363
3365
  // Claude Code 2.1.x defers every MCP tool behind tool-search by default;
@@ -3416,10 +3418,15 @@ function buildClaudeCodeOptions(req, augment) {
3416
3418
  //
3417
3419
  // `secretEnv` — the values the MCP headers above reference — joins here and only here: it is
3418
3420
  // this child's environment, not the host's.
3421
+ //
3422
+ // The turn token goes after everything a room secret, a hook or the inherited environment can
3423
+ // supply: this spread order is the only thing that stops a variable of the same name from
3424
+ // displacing the turn's own credential.
3419
3425
  env: {
3420
3426
  ...process.env,
3421
3427
  ...req.local.env,
3422
3428
  ...req.local.secretEnv,
3429
+ [TURN_TOKEN_ENV]: `Bearer ${req.cabane.bearer}`,
3423
3430
  CLAUDE_CODE_DISABLE_BACKGROUND_TASKS: "1"
3424
3431
  },
3425
3432
  ...resume ? { resume } : {}
@@ -5249,12 +5256,16 @@ function codexSecretEnv(req) {
5249
5256
  const env = { ...req.local.secretEnv };
5250
5257
  for (const server of Object.values(req.local.mcpServers ?? {})) {
5251
5258
  if ("url" in server) continue;
5252
- for (const [variable, envName] of Object.entries(server.envFromEnv ?? {})) {
5259
+ for (const [variable, envName] of forwardedEnvVars(server.envFromEnv)) {
5253
5260
  const value = req.local.secretEnv?.[envName];
5254
5261
  if (value !== void 0) env[variable] = value;
5255
5262
  }
5256
5263
  }
5257
- return Object.keys(env).length > 0 ? env : null;
5264
+ env[TURN_TOKEN_ENV] = `Bearer ${req.cabane.bearer}`;
5265
+ return env;
5266
+ }
5267
+ function forwardedEnvVars(envFromEnv) {
5268
+ return Object.entries(envFromEnv ?? {}).filter(([variable]) => variable !== TURN_TOKEN_ENV);
5258
5269
  }
5259
5270
  function buildInput(req, segments, preamble, resumed) {
5260
5271
  const userText = req.content.filter((b) => b.type === "text").map((b) => b.text).join("\n\n");
@@ -5296,7 +5307,7 @@ function buildConfig(req) {
5296
5307
  default_tools_approval_mode: "approve"
5297
5308
  };
5298
5309
  } else if ("command" in server) {
5299
- const forwarded = Object.keys(server.envFromEnv ?? {}).sort();
5310
+ const forwarded = forwardedEnvVars(server.envFromEnv).map(([variable]) => variable).sort();
5300
5311
  mcp_servers[name] = {
5301
5312
  command: server.command,
5302
5313
  ...server.args ? { args: server.args } : {},
@@ -5324,19 +5335,15 @@ function buildConfig(req) {
5324
5335
  }
5325
5336
  mcp_servers[CABANE_MCP_SERVER3] = {
5326
5337
  url: req.cabane.mcpUrl,
5327
- http_headers: {
5328
- Authorization: `Bearer ${req.cabane.bearer}`,
5329
- [ACTIVE_CONVERSATION_HEADER3]: req.cabane.activeConversationId
5330
- },
5338
+ http_headers: { [ACTIVE_CONVERSATION_HEADER3]: req.cabane.activeConversationId },
5339
+ env_http_headers: { Authorization: TURN_TOKEN_ENV },
5331
5340
  default_tools_approval_mode: "approve"
5332
5341
  };
5333
5342
  if (req.cabane.turnControlUrl) {
5334
5343
  mcp_servers[TURN_CONTROL_MCP_SERVER] = {
5335
5344
  url: req.cabane.turnControlUrl,
5336
- http_headers: {
5337
- Authorization: `Bearer ${req.cabane.bearer}`,
5338
- [ACTIVE_CONVERSATION_HEADER3]: req.cabane.activeConversationId
5339
- },
5345
+ http_headers: { [ACTIVE_CONVERSATION_HEADER3]: req.cabane.activeConversationId },
5346
+ env_http_headers: { Authorization: TURN_TOKEN_ENV },
5340
5347
  default_tools_approval_mode: "approve"
5341
5348
  };
5342
5349
  }
@@ -5361,6 +5368,7 @@ var CABANE_MCP_SERVER3, ACTIVE_CONVERSATION_HEADER3, ENV_ENVELOPE_KEYS, CORE_REP
5361
5368
  var init_run_spec2 = __esm({
5362
5369
  "packages/agent-runtime/src/codex/run-spec.ts"() {
5363
5370
  "use strict";
5371
+ init_mcp_secret_env();
5364
5372
  init_descriptions();
5365
5373
  init_standing();
5366
5374
  init_policy3();
@@ -5476,7 +5484,7 @@ function createSdkCodexTransport(opts = {}) {
5476
5484
  // path (the CLI splits on `.` and ignores TOML quoting), so it must ride inside an inline-table
5477
5485
  // value, which the SDK's flattener can't produce. See `config-overrides.ts`.
5478
5486
  configOverrides: buildConfigOverrides(spec.config),
5479
- ...spec.secretEnv ? { env: codexProcessEnv(spec.secretEnv) } : {}
5487
+ env: codexProcessEnv(spec.secretEnv)
5480
5488
  };
5481
5489
  const codex = new Codex(codexOptions);
5482
5490
  const threadOptions = buildSdkThreadOptions(spec);
package/dist/runtime.js CHANGED
@@ -3134,6 +3134,7 @@ var CLAUDE_CODE_ADDENDUM = [
3134
3134
  ].join("\n");
3135
3135
 
3136
3136
  // packages/agent-runtime/src/mcp-secret-env.ts
3137
+ var TURN_TOKEN_ENV = "CABANE_TURN_TOKEN";
3137
3138
  function headersAsEnvReferences(server) {
3138
3139
  const refs = Object.entries(server.headersFromEnv ?? {}).map(
3139
3140
  ([header, envName]) => [header, `\${${envName}}`]
@@ -3298,7 +3299,7 @@ function buildClaudeCodeOptions(req, augment) {
3298
3299
  type: "http",
3299
3300
  url: req.cabane.mcpUrl,
3300
3301
  headers: {
3301
- Authorization: `Bearer ${req.cabane.bearer}`,
3302
+ Authorization: `\${${TURN_TOKEN_ENV}}`,
3302
3303
  [ACTIVE_CONVERSATION_HEADER]: req.cabane.activeConversationId
3303
3304
  },
3304
3305
  // Claude Code 2.1.x defers every MCP tool behind tool-search by default;
@@ -3357,10 +3358,15 @@ function buildClaudeCodeOptions(req, augment) {
3357
3358
  //
3358
3359
  // `secretEnv` — the values the MCP headers above reference — joins here and only here: it is
3359
3360
  // this child's environment, not the host's.
3361
+ //
3362
+ // The turn token goes after everything a room secret, a hook or the inherited environment can
3363
+ // supply: this spread order is the only thing that stops a variable of the same name from
3364
+ // displacing the turn's own credential.
3360
3365
  env: {
3361
3366
  ...process.env,
3362
3367
  ...req.local.env,
3363
3368
  ...req.local.secretEnv,
3369
+ [TURN_TOKEN_ENV]: `Bearer ${req.cabane.bearer}`,
3364
3370
  CLAUDE_CODE_DISABLE_BACKGROUND_TASKS: "1"
3365
3371
  },
3366
3372
  ...resume ? { resume } : {}
@@ -4991,12 +4997,16 @@ function codexSecretEnv(req) {
4991
4997
  const env = { ...req.local.secretEnv };
4992
4998
  for (const server of Object.values(req.local.mcpServers ?? {})) {
4993
4999
  if ("url" in server) continue;
4994
- for (const [variable, envName] of Object.entries(server.envFromEnv ?? {})) {
5000
+ for (const [variable, envName] of forwardedEnvVars(server.envFromEnv)) {
4995
5001
  const value = req.local.secretEnv?.[envName];
4996
5002
  if (value !== void 0) env[variable] = value;
4997
5003
  }
4998
5004
  }
4999
- return Object.keys(env).length > 0 ? env : null;
5005
+ env[TURN_TOKEN_ENV] = `Bearer ${req.cabane.bearer}`;
5006
+ return env;
5007
+ }
5008
+ function forwardedEnvVars(envFromEnv) {
5009
+ return Object.entries(envFromEnv ?? {}).filter(([variable]) => variable !== TURN_TOKEN_ENV);
5000
5010
  }
5001
5011
  var CORE_REPLACES = "Your standing instructions changed since an earlier copy in this conversation, or that copy may have been compacted away. This copy replaces every earlier one: where they differ, this one holds, and anything an earlier copy said that this one does not no longer applies.";
5002
5012
  var CONVERSATION_REPLACES = "This conversation's standing context \u2014 its charters, skill indexes and roster \u2014 changed since an earlier copy in this conversation, or that copy may have been compacted away. This copy replaces every earlier one, including charters and skills an earlier turn carried in its own text: where they differ, this one holds, and anything an earlier copy said that this one does not no longer applies.";
@@ -5040,7 +5050,7 @@ function buildConfig(req) {
5040
5050
  default_tools_approval_mode: "approve"
5041
5051
  };
5042
5052
  } else if ("command" in server) {
5043
- const forwarded = Object.keys(server.envFromEnv ?? {}).sort();
5053
+ const forwarded = forwardedEnvVars(server.envFromEnv).map(([variable]) => variable).sort();
5044
5054
  mcp_servers[name] = {
5045
5055
  command: server.command,
5046
5056
  ...server.args ? { args: server.args } : {},
@@ -5068,19 +5078,15 @@ function buildConfig(req) {
5068
5078
  }
5069
5079
  mcp_servers[CABANE_MCP_SERVER3] = {
5070
5080
  url: req.cabane.mcpUrl,
5071
- http_headers: {
5072
- Authorization: `Bearer ${req.cabane.bearer}`,
5073
- [ACTIVE_CONVERSATION_HEADER3]: req.cabane.activeConversationId
5074
- },
5081
+ http_headers: { [ACTIVE_CONVERSATION_HEADER3]: req.cabane.activeConversationId },
5082
+ env_http_headers: { Authorization: TURN_TOKEN_ENV },
5075
5083
  default_tools_approval_mode: "approve"
5076
5084
  };
5077
5085
  if (req.cabane.turnControlUrl) {
5078
5086
  mcp_servers[TURN_CONTROL_MCP_SERVER] = {
5079
5087
  url: req.cabane.turnControlUrl,
5080
- http_headers: {
5081
- Authorization: `Bearer ${req.cabane.bearer}`,
5082
- [ACTIVE_CONVERSATION_HEADER3]: req.cabane.activeConversationId
5083
- },
5088
+ http_headers: { [ACTIVE_CONVERSATION_HEADER3]: req.cabane.activeConversationId },
5089
+ env_http_headers: { Authorization: TURN_TOKEN_ENV },
5084
5090
  default_tools_approval_mode: "approve"
5085
5091
  };
5086
5092
  }
@@ -5196,7 +5202,7 @@ function createSdkCodexTransport(opts = {}) {
5196
5202
  // path (the CLI splits on `.` and ignores TOML quoting), so it must ride inside an inline-table
5197
5203
  // value, which the SDK's flattener can't produce. See `config-overrides.ts`.
5198
5204
  configOverrides: buildConfigOverrides(spec.config),
5199
- ...spec.secretEnv ? { env: codexProcessEnv(spec.secretEnv) } : {}
5205
+ env: codexProcessEnv(spec.secretEnv)
5200
5206
  };
5201
5207
  const codex = new Codex(codexOptions);
5202
5208
  const threadOptions = buildSdkThreadOptions(spec);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cabane/companion",
3
- "version": "0.6.234",
3
+ "version": "0.6.236",
4
4
  "type": "module",
5
5
  "description": "The Cabane Companion (headless): connect an agent on your machine to your Cabane workspace as a responder — drive work against your own codebase, files, and MCP servers without putting any of it in Cabane.",
6
6
  "license": "UNLICENSED",
@@ -38,7 +38,7 @@
38
38
  "prepublishOnly": "pnpm build"
39
39
  },
40
40
  "dependencies": {
41
- "@anthropic-ai/claude-agent-sdk": "0.3.319",
41
+ "@anthropic-ai/claude-agent-sdk": "0.3.322",
42
42
  "@clack/prompts": "1.8.1",
43
43
  "@openai/codex-sdk": "0.167.0",
44
44
  "commander": "12.1.0",