@cabane/companion 0.6.227 → 0.6.229
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 +2 -2
- package/dist/cli.js +30 -41
- package/dist/credential-broker.js +10 -1
- package/dist/runtime.js +30 -41
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -158,7 +158,7 @@ An operator-managed sandbox can use the host-side `@cabane/companion/credential-
|
|
|
158
158
|
|
|
159
159
|
Run the broker and its credential files under a host identity outside every sandbox UID mapping. Hold an exclusive process lock for the entire service lifetime, including shutdown: there must be exactly one renewal owner for each account file. The parent of an account file must be owned by that identity with mode `0700`; the file must be a regular, single-link `0600` file. Stop the service before importing or changing login state. `fileCredentialStore(path)` and `openBrokerCredentials(store)` read that state; share the resulting owner between every grant using the account. Renewal writes and fsyncs a replacement before releasing it. A failed persistence write refuses further use until the operator recovers the stored account.
|
|
160
160
|
|
|
161
|
-
The account format is `{ mode, accessToken, refreshToken?, idToken?, expiresAt?, accountId? }`. `mode` is `claude-setup`, `claude-oauth`, `codex-oauth` or `github`. OAuth modes require a refresh token and an expiry in epoch milliseconds. A setup token never renews. Normal Claude OAuth renews inside the broker before expiry, or on one upstream 401; Codex renewal returns fresh placeholders to its client. Never place the real account file, a credential-store bind, or an alternate harness login inside the sandbox. Real OAuth compatibility must be verified with the installed harness and login mode; a successful setup-token turn proves nothing about OAuth renewal.
|
|
161
|
+
The account format is `{ mode, accessToken, refreshToken?, idToken?, expiresAt?, accountId? }`. `mode` is `claude-setup`, `claude-oauth`, `codex-oauth` or `github`. OAuth modes require a refresh token and an expiry in epoch milliseconds. A setup token never renews. Normal Claude OAuth renews inside the broker before expiry, or on one upstream 401; Codex renewal returns fresh placeholders to its client. After a failed exchange the owner refuses renewal for a backoff window, 30 seconds doubling to 15 minutes, rather than retrying upstream on every request; a successful renewal clears it. Never place the real account file, a credential-store bind, or an alternate harness login inside the sandbox. Real OAuth compatibility must be verified with the installed harness and login mode; a successful setup-token turn proves nothing about OAuth renewal.
|
|
162
162
|
|
|
163
163
|
Create the broker with `createCredentialBroker({ resolveIdentity, audit? })`. Its `server` handles model and git routes; bind it only to host loopback. Git's HTTP proxy requests are accepted only for the exact `http://github.com/` authority, then forwarded to fixed HTTPS GitHub upstreams. Arbitrary proxy destinations and CONNECT tunnels are refused. Its `githubServer` handles gh's `http_unix_socket` transport; authenticate that socket's peer too. Neither exposes a management endpoint. Call `grant({ identity, credentials, expiresAt })` only from the trusted host adapter. `credentials` maps `claude`, `codex` and `github` to their corresponding credential owners. The returned `token` is disposable; `revoke()` aborts active requests and removes its aliases. Teardown calls `revokeIdentity(identity)`; service shutdown calls `revokeAll()` and closes both servers. A restart creates fresh grants, so old placeholders stop working.
|
|
164
164
|
|
|
@@ -166,7 +166,7 @@ Scope the GitHub token on GitHub's side; the broker imposes no repository, branc
|
|
|
166
166
|
|
|
167
167
|
Set `runner.brokeredCredentials: true` beside `runner.command` in the Companion config. This removes provider and GitHub credential variables from the launcher's environment, secret-store payload and device-grant payload before the wrapper receives them. The wrapper supplies `brokerClientConfiguration({ baseUrl, placeholder, githubSocket, codexConfig })`'s environment and generated configuration to the isolated home, and writes `await grant.codexAuth()` as its placeholder-only Codex `auth.json`. The helper preserves the supplied Codex settings while selecting the broker provider and HTTP Responses transport. Include its git configuration in the sandbox's global config and use its gh configuration there. For a GitHub-enabled box, provide `githubSocket`. The helper sets `GH_TOKEN` and preserves `github.com` in git's expanded remote so gh can resolve a tracked branch, without setting `GH_REPO`. The generated git config rewrites HTTPS URLs to an HTTP GitHub URL carrying only a placeholder, and sends that origin through the loopback broker using Git's per-origin `http.proxy`; the broker's upstream hop remains HTTPS. Install the entire generated config, replacing the previous generated file, rather than retaining an older rewrite. Do not bypass this proxy with `NO_PROXY` or a per-remote proxy override. For a model-only box, omit `githubSocket` or pass `null`; no GitHub environment is emitted and both git/gh config strings are empty, so an adapter can clear any previous generated routing. The wrapper must remove old credential mounts and alternate authentication helpers; this switch cannot inspect or secure an operator's filesystem mounts.
|
|
168
168
|
|
|
169
|
-
The fixed upstream hosts are `api.anthropic.com`, `chatgpt.com`, `api.github.com` and `github.com`. Paths and request bodies pass through without a workflow policy, except for known credential-minting, credential-registering or disclosure endpoints: Claude CLI API-key creation and OAuth token exchange, ChatGPT session/token disclosure, and GitHub app-manifest conversion, installation/application token endpoints, legacy authorizations, SSH user/deploy-key registration, runner registration/removal/JIT credentials and OAuth/device token endpoints. These return new secrets the echo filter cannot know in advance, or register box-chosen credentials that would outlive the grant. This deny-list must be revisited when providers add credential-returning or credential-registering routes; it is not a guarantee against unknown endpoints or arbitrary encodings. Redirects are refused and responses are filtered for known credential echoes. Credential-free injection is restricted to Codex's designated `/backend-api/ps/mcp` route. Each upstream exchange is capped at ten minutes, and request bodies at 64 MiB.
|
|
169
|
+
The fixed upstream hosts are `api.anthropic.com`, `chatgpt.com`, `api.github.com` and `github.com`. Paths and request bodies pass through without a workflow policy, except for known credential-minting, credential-registering or disclosure endpoints: Claude CLI API-key creation and OAuth token exchange, ChatGPT session/token disclosure, and GitHub app-manifest conversion, installation/application token endpoints, legacy authorizations, SSH user/deploy-key registration, runner registration/removal/JIT credentials and OAuth/device token endpoints. These return new secrets the echo filter cannot know in advance, or register box-chosen credentials that would outlive the grant. This deny-list must be revisited when providers add credential-returning or credential-registering routes; it is not a guarantee against unknown endpoints or arbitrary encodings. Redirects are refused and responses are filtered for known credential echoes. Credential-free injection is restricted to Codex's designated `/backend-api/ps/mcp` route. Each upstream exchange, streams included, is capped at ten minutes by default (`requestTimeoutMs` on `createCredentialBroker`), and request bodies at 64 MiB.
|
|
170
170
|
|
|
171
171
|
Arbitrary room secrets and other MCP credentials still follow their existing delivery contract. This API does not protect SSH keys or offer general secret injection into arbitrary HTTP destinations. Claude's feature flags fall back to defaults when their direct requests use placeholders. Before enabling a sandbox deployment, verify actual socket ownership, PID/namespace reuse, service UID separation, grant revocation, concurrent renewal and restart, required client operations, and a canary extraction attempt from inside the real sandbox. A successful unit test or package installation does not establish that host boundary.
|
|
172
172
|
|
package/dist/cli.js
CHANGED
|
@@ -2822,8 +2822,10 @@ var init_pump = __esm({
|
|
|
2822
2822
|
|
|
2823
2823
|
// packages/agent-runtime/src/turn-control/prompt-guidance.ts
|
|
2824
2824
|
function turnControlPromptGuidance(prefix) {
|
|
2825
|
-
|
|
2826
|
-
|
|
2825
|
+
return [
|
|
2826
|
+
"Turn tools (read each description before calling):",
|
|
2827
|
+
...TURN_CONTROL_TOOLS.map((name) => `- \`${prefix}${name}\` \u2014 ${MEANINGS[name]}.`)
|
|
2828
|
+
].join("\n");
|
|
2827
2829
|
}
|
|
2828
2830
|
var MEANINGS;
|
|
2829
2831
|
var init_prompt_guidance = __esm({
|
|
@@ -2832,8 +2834,8 @@ var init_prompt_guidance = __esm({
|
|
|
2832
2834
|
init_descriptions();
|
|
2833
2835
|
MEANINGS = {
|
|
2834
2836
|
answer: "declare the text you write next as your answer",
|
|
2835
|
-
open_exchange: "
|
|
2836
|
-
cancel_wake: "cancel your
|
|
2837
|
+
open_exchange: "ask a person for a decision, approval or action",
|
|
2838
|
+
cancel_wake: "cancel your scheduled return to this conversation",
|
|
2837
2839
|
skip_turn: "end without posting a reply",
|
|
2838
2840
|
wake_me: "schedule your own return; when it fires, say what you came back to check",
|
|
2839
2841
|
withdraw_exchange: "withdraw an open exchange in this conversation with a reason"
|
|
@@ -2848,15 +2850,14 @@ var init_addendum = __esm({
|
|
|
2848
2850
|
"use strict";
|
|
2849
2851
|
init_prompt_guidance();
|
|
2850
2852
|
CLAUDE_CODE_ADDENDUM = [
|
|
2851
|
-
"
|
|
2852
|
-
"`
|
|
2853
|
-
"
|
|
2854
|
-
"
|
|
2855
|
-
|
|
2856
|
-
"
|
|
2857
|
-
|
|
2858
|
-
|
|
2859
|
-
].join(" ");
|
|
2853
|
+
"- Workspace tools: `mcp__cabane__query`, `mcp__cabane__mutate`, `mcp__cabane__describe`.",
|
|
2854
|
+
"- File tools: `mcp__cabane__read_binary`, `mcp__cabane__upload`, `mcp__cabane__begin_upload`, `mcp__cabane__finalize_upload`.",
|
|
2855
|
+
"- Page verification: `mcp__cabane__mint_render_token`.",
|
|
2856
|
+
"- Where these instructions use a bare tool name, call its prefixed form from the tool list.",
|
|
2857
|
+
"- Host tools such as the shell and local file editor keep their ordinary names and act on the local device.",
|
|
2858
|
+
"",
|
|
2859
|
+
turnControlPromptGuidance("mcp__cabane_companion__")
|
|
2860
|
+
].join("\n");
|
|
2860
2861
|
}
|
|
2861
2862
|
});
|
|
2862
2863
|
|
|
@@ -3704,17 +3705,14 @@ var init_addendum2 = __esm({
|
|
|
3704
3705
|
"use strict";
|
|
3705
3706
|
init_prompt_guidance();
|
|
3706
3707
|
OPENCODE_ADDENDUM = [
|
|
3707
|
-
"
|
|
3708
|
-
"`
|
|
3709
|
-
|
|
3710
|
-
"
|
|
3711
|
-
"`
|
|
3712
|
-
"
|
|
3713
|
-
"
|
|
3714
|
-
|
|
3715
|
-
"operation name, so keep the bare verb and the dotted name apart. If a tool ever appears with",
|
|
3716
|
-
"an `mcp__\u2026__` prefix, that prefix is not part of its name here."
|
|
3717
|
-
].join(" ");
|
|
3708
|
+
"- Workspace tools: `query`, `mutate`, `describe`.",
|
|
3709
|
+
"- File tools: `read_binary`, `upload`, `begin_upload`, `finalize_upload`.",
|
|
3710
|
+
"- Page verification: `mint_render_token`.",
|
|
3711
|
+
"- Call tools by their plain names here, without an `mcp__\u2026__` prefix.",
|
|
3712
|
+
"- Host tools such as `bash`, `read` and `edit` act on the local device. To read a workspace file, call `query` with the operation `files.read`.",
|
|
3713
|
+
"",
|
|
3714
|
+
turnControlPromptGuidance("")
|
|
3715
|
+
].join("\n");
|
|
3718
3716
|
}
|
|
3719
3717
|
});
|
|
3720
3718
|
|
|
@@ -4447,23 +4445,14 @@ var init_addendum3 = __esm({
|
|
|
4447
4445
|
"use strict";
|
|
4448
4446
|
init_prompt_guidance();
|
|
4449
4447
|
CODEX_ADDENDUM = [
|
|
4450
|
-
"
|
|
4451
|
-
"
|
|
4452
|
-
"
|
|
4453
|
-
"the deferred-tool inventory and
|
|
4454
|
-
"
|
|
4455
|
-
"
|
|
4456
|
-
"
|
|
4457
|
-
|
|
4458
|
-
// Every ancillary tool is written as Codex's own tool list shows it — qualified — so the sentence
|
|
4459
|
-
// instructing exact qualified names doesn't contradict itself. The bare `query` / `mutate` below
|
|
4460
|
-
// stay: that sentence is about operation names, after the qualified forms are given.
|
|
4461
|
-
"The ancillary tools are `mcp__cabane__read_binary`, `mcp__cabane__upload`,",
|
|
4462
|
-
"`mcp__cabane__begin_upload`, `mcp__cabane__finalize_upload` and",
|
|
4463
|
-
"`mcp__cabane__mint_render_token` \u2014 all possibly deferred too.",
|
|
4464
|
-
"There is no Cabane `read`/`write`/`search` tool \u2014 those are",
|
|
4465
|
-
"operation NAMES you pass to `query` / `mutate`."
|
|
4466
|
-
].join(" ");
|
|
4448
|
+
"- Workspace tools: `mcp__cabane__query`, `mcp__cabane__mutate`, `mcp__cabane__describe`.",
|
|
4449
|
+
"- File tools: `mcp__cabane__read_binary`, `mcp__cabane__upload`, `mcp__cabane__begin_upload`, `mcp__cabane__finalize_upload`.",
|
|
4450
|
+
"- Page verification: `mcp__cabane__mint_render_token`.",
|
|
4451
|
+
"- Codex may defer MCP tools. If a listed tool is missing, search the deferred-tool inventory and call the matching tool by its exact name. Report discovery or call failures with the recorded error.",
|
|
4452
|
+
"- Names such as `files.read` are operations passed to `query` or `mutate`, not separate tools.",
|
|
4453
|
+
"",
|
|
4454
|
+
turnControlPromptGuidance("mcp__cabane_companion__")
|
|
4455
|
+
].join("\n");
|
|
4467
4456
|
}
|
|
4468
4457
|
});
|
|
4469
4458
|
|
|
@@ -176,6 +176,7 @@ function refuse(res, route, body, status = 403) {
|
|
|
176
176
|
function createCredentialBroker(options) {
|
|
177
177
|
const now = options.now ?? Date.now;
|
|
178
178
|
const upstream = options.fetch ?? fetch;
|
|
179
|
+
const requestTimeoutMs = options.requestTimeoutMs ?? 6e5;
|
|
179
180
|
const grants = /* @__PURE__ */ new Set();
|
|
180
181
|
const byToken = /* @__PURE__ */ new Map();
|
|
181
182
|
function revoke(grant) {
|
|
@@ -233,7 +234,7 @@ function createCredentialBroker(options) {
|
|
|
233
234
|
grant.active.add(abort);
|
|
234
235
|
const signal = AbortSignal.any([
|
|
235
236
|
abort.signal,
|
|
236
|
-
AbortSignal.timeout(Math.max(1, Math.min(
|
|
237
|
+
AbortSignal.timeout(Math.max(1, Math.min(requestTimeoutMs, grant.expiresAt - now())))
|
|
237
238
|
]);
|
|
238
239
|
res.once("close", () => abort?.abort());
|
|
239
240
|
body ??= await readBody(req);
|
|
@@ -490,6 +491,8 @@ var OAUTH = {
|
|
|
490
491
|
clientId: "app_EMoamEEZ73f0CkXaXp7hrann"
|
|
491
492
|
}
|
|
492
493
|
};
|
|
494
|
+
var REFRESH_BACKOFF_MS = 3e4;
|
|
495
|
+
var REFRESH_BACKOFF_MAX_MS = 9e5;
|
|
493
496
|
async function openBrokerCredentials(store, ports = {}) {
|
|
494
497
|
let account;
|
|
495
498
|
try {
|
|
@@ -501,6 +504,8 @@ async function openBrokerCredentials(store, ports = {}) {
|
|
|
501
504
|
const now = ports.now ?? Date.now;
|
|
502
505
|
let pending;
|
|
503
506
|
let poisoned = false;
|
|
507
|
+
let failures = 0;
|
|
508
|
+
let retryAt = 0;
|
|
504
509
|
const secrets = /* @__PURE__ */ new Set();
|
|
505
510
|
function remember(value) {
|
|
506
511
|
for (const secret of [value.accessToken, value.refreshToken, value.idToken]) {
|
|
@@ -568,9 +573,12 @@ async function openBrokerCredentials(store, ports = {}) {
|
|
|
568
573
|
throw new BrokerError("persistence_failed");
|
|
569
574
|
}
|
|
570
575
|
account = next;
|
|
576
|
+
failures = 0;
|
|
577
|
+
retryAt = 0;
|
|
571
578
|
return account;
|
|
572
579
|
} catch (error) {
|
|
573
580
|
if (error instanceof BrokerError) throw error;
|
|
581
|
+
retryAt = now() + Math.min(REFRESH_BACKOFF_MAX_MS, REFRESH_BACKOFF_MS * 2 ** failures++);
|
|
574
582
|
throw new BrokerError("refresh_failed");
|
|
575
583
|
}
|
|
576
584
|
}
|
|
@@ -584,6 +592,7 @@ async function openBrokerCredentials(store, ports = {}) {
|
|
|
584
592
|
if (!account.mode.endsWith("-oauth") || rejectedAccessToken !== void 0 && rejectedAccessToken !== account.accessToken || rejectedAccessToken === void 0 && (account.expiresAt ?? 0) > now() + 6e4) {
|
|
585
593
|
return account;
|
|
586
594
|
}
|
|
595
|
+
if (now() < retryAt) throw new BrokerError("refresh_failed");
|
|
587
596
|
pending = renew();
|
|
588
597
|
try {
|
|
589
598
|
return await pending;
|
package/dist/runtime.js
CHANGED
|
@@ -3016,28 +3016,29 @@ import {
|
|
|
3016
3016
|
// packages/agent-runtime/src/turn-control/prompt-guidance.ts
|
|
3017
3017
|
var MEANINGS = {
|
|
3018
3018
|
answer: "declare the text you write next as your answer",
|
|
3019
|
-
open_exchange: "
|
|
3020
|
-
cancel_wake: "cancel your
|
|
3019
|
+
open_exchange: "ask a person for a decision, approval or action",
|
|
3020
|
+
cancel_wake: "cancel your scheduled return to this conversation",
|
|
3021
3021
|
skip_turn: "end without posting a reply",
|
|
3022
3022
|
wake_me: "schedule your own return; when it fires, say what you came back to check",
|
|
3023
3023
|
withdraw_exchange: "withdraw an open exchange in this conversation with a reason"
|
|
3024
3024
|
};
|
|
3025
3025
|
function turnControlPromptGuidance(prefix) {
|
|
3026
|
-
|
|
3027
|
-
|
|
3026
|
+
return [
|
|
3027
|
+
"Turn tools (read each description before calling):",
|
|
3028
|
+
...TURN_CONTROL_TOOLS.map((name) => `- \`${prefix}${name}\` \u2014 ${MEANINGS[name]}.`)
|
|
3029
|
+
].join("\n");
|
|
3028
3030
|
}
|
|
3029
3031
|
|
|
3030
3032
|
// packages/agent-runtime/src/claude-code/addendum.ts
|
|
3031
3033
|
var CLAUDE_CODE_ADDENDUM = [
|
|
3032
|
-
"
|
|
3033
|
-
"`
|
|
3034
|
-
"
|
|
3035
|
-
"
|
|
3036
|
-
|
|
3037
|
-
"
|
|
3038
|
-
|
|
3039
|
-
|
|
3040
|
-
].join(" ");
|
|
3034
|
+
"- Workspace tools: `mcp__cabane__query`, `mcp__cabane__mutate`, `mcp__cabane__describe`.",
|
|
3035
|
+
"- File tools: `mcp__cabane__read_binary`, `mcp__cabane__upload`, `mcp__cabane__begin_upload`, `mcp__cabane__finalize_upload`.",
|
|
3036
|
+
"- Page verification: `mcp__cabane__mint_render_token`.",
|
|
3037
|
+
"- Where these instructions use a bare tool name, call its prefixed form from the tool list.",
|
|
3038
|
+
"- Host tools such as the shell and local file editor keep their ordinary names and act on the local device.",
|
|
3039
|
+
"",
|
|
3040
|
+
turnControlPromptGuidance("mcp__cabane_companion__")
|
|
3041
|
+
].join("\n");
|
|
3041
3042
|
|
|
3042
3043
|
// packages/agent-runtime/src/mcp-secret-env.ts
|
|
3043
3044
|
function headersAsEnvReferences(server) {
|
|
@@ -3763,17 +3764,14 @@ var claudeCodeAdapter = createClaudeCodeAdapter();
|
|
|
3763
3764
|
|
|
3764
3765
|
// packages/agent-runtime/src/opencode/addendum.ts
|
|
3765
3766
|
var OPENCODE_ADDENDUM = [
|
|
3766
|
-
"
|
|
3767
|
-
"`
|
|
3768
|
-
|
|
3769
|
-
"
|
|
3770
|
-
"`
|
|
3771
|
-
"
|
|
3772
|
-
"
|
|
3773
|
-
|
|
3774
|
-
"operation name, so keep the bare verb and the dotted name apart. If a tool ever appears with",
|
|
3775
|
-
"an `mcp__\u2026__` prefix, that prefix is not part of its name here."
|
|
3776
|
-
].join(" ");
|
|
3767
|
+
"- Workspace tools: `query`, `mutate`, `describe`.",
|
|
3768
|
+
"- File tools: `read_binary`, `upload`, `begin_upload`, `finalize_upload`.",
|
|
3769
|
+
"- Page verification: `mint_render_token`.",
|
|
3770
|
+
"- Call tools by their plain names here, without an `mcp__\u2026__` prefix.",
|
|
3771
|
+
"- Host tools such as `bash`, `read` and `edit` act on the local device. To read a workspace file, call `query` with the operation `files.read`.",
|
|
3772
|
+
"",
|
|
3773
|
+
turnControlPromptGuidance("")
|
|
3774
|
+
].join("\n");
|
|
3777
3775
|
|
|
3778
3776
|
// packages/agent-runtime/src/opencode/events.ts
|
|
3779
3777
|
function asRecord(v) {
|
|
@@ -4433,23 +4431,14 @@ var opencodeAdapter = createOpencodeAdapter();
|
|
|
4433
4431
|
|
|
4434
4432
|
// packages/agent-runtime/src/codex/addendum.ts
|
|
4435
4433
|
var CODEX_ADDENDUM = [
|
|
4436
|
-
"
|
|
4437
|
-
"
|
|
4438
|
-
"
|
|
4439
|
-
"the deferred-tool inventory and
|
|
4440
|
-
"
|
|
4441
|
-
"
|
|
4442
|
-
"
|
|
4443
|
-
|
|
4444
|
-
// Every ancillary tool is written as Codex's own tool list shows it — qualified — so the sentence
|
|
4445
|
-
// instructing exact qualified names doesn't contradict itself. The bare `query` / `mutate` below
|
|
4446
|
-
// stay: that sentence is about operation names, after the qualified forms are given.
|
|
4447
|
-
"The ancillary tools are `mcp__cabane__read_binary`, `mcp__cabane__upload`,",
|
|
4448
|
-
"`mcp__cabane__begin_upload`, `mcp__cabane__finalize_upload` and",
|
|
4449
|
-
"`mcp__cabane__mint_render_token` \u2014 all possibly deferred too.",
|
|
4450
|
-
"There is no Cabane `read`/`write`/`search` tool \u2014 those are",
|
|
4451
|
-
"operation NAMES you pass to `query` / `mutate`."
|
|
4452
|
-
].join(" ");
|
|
4434
|
+
"- Workspace tools: `mcp__cabane__query`, `mcp__cabane__mutate`, `mcp__cabane__describe`.",
|
|
4435
|
+
"- File tools: `mcp__cabane__read_binary`, `mcp__cabane__upload`, `mcp__cabane__begin_upload`, `mcp__cabane__finalize_upload`.",
|
|
4436
|
+
"- Page verification: `mcp__cabane__mint_render_token`.",
|
|
4437
|
+
"- Codex may defer MCP tools. If a listed tool is missing, search the deferred-tool inventory and call the matching tool by its exact name. Report discovery or call failures with the recorded error.",
|
|
4438
|
+
"- Names such as `files.read` are operations passed to `query` or `mutate`, not separate tools.",
|
|
4439
|
+
"",
|
|
4440
|
+
turnControlPromptGuidance("mcp__cabane_companion__")
|
|
4441
|
+
].join("\n");
|
|
4453
4442
|
|
|
4454
4443
|
// packages/agent-runtime/src/codex/events.ts
|
|
4455
4444
|
function asRecord3(v) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cabane/companion",
|
|
3
|
-
"version": "0.6.
|
|
3
|
+
"version": "0.6.229",
|
|
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",
|