@cabane/companion 0.6.186 → 0.6.187

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
@@ -369,7 +369,6 @@ var init_prepare_hook = __esm({
369
369
  CABANE_AGENT_USERNAME: input.agentUsername,
370
370
  CABANE_DEFAULT_CWD: input.defaultCwd,
371
371
  CABANE_RUNTIME: input.runtime ?? "",
372
- CABANE_HOST_ACCESS: input.hostAccess ? "1" : "0",
373
372
  // Newline-joined — workspace paths never contain a newline, so a
374
373
  // hook splits on `\n` unambiguously. Empty string when none.
375
374
  CABANE_TRIGGER_ENTRY_PATHS: input.triggerEntryPaths.join("\n"),
@@ -727,7 +726,7 @@ var init_config = __esm({
727
726
  // yourself, `claudeCode: { autoMemory: true }` hands auto-memory back to your
728
727
  // own `~/.claude/settings.json` — Cabane then stops
729
728
  // injecting the off switch and your normal Claude Code memory workflow applies
730
- // (in coding mode, where the checkout's project settings are read).
729
+ // (the user and project settings load on every Claude Code turn).
731
730
  claudeCode: z2.object({ autoMemory: z2.boolean().optional() }).strict().optional()
732
731
  }).strict();
733
732
  agentsConfigSchema = z2.record(z2.string(), localAgentConfigSchema);
@@ -1722,45 +1721,13 @@ var init_version = __esm({
1722
1721
  }
1723
1722
  });
1724
1723
 
1725
- // packages/agent-runtime/src/host-policy.ts
1726
- import { z as z6 } from "zod";
1727
- var hostPolicySchema;
1728
- var init_host_policy = __esm({
1729
- "packages/agent-runtime/src/host-policy.ts"() {
1730
- "use strict";
1731
- hostPolicySchema = z6.object({
1732
- // Host filesystem and shell: `Bash`/`Read`/`Write`/`Edit`/`Glob`/`Grep`, the notebook pair,
1733
- // git-worktree tools and `REPL`. Off on the locked assistant surface; on in the coding posture.
1734
- hostFs: z6.boolean(),
1735
- // Public web (`WebSearch` / `WebFetch`). Not host reach; a grant like the rest.
1736
- web: z6.boolean(),
1737
- // Browser automation (the Playwright MCP surface). Varies by host.
1738
- browser: z6.boolean(),
1739
- // User-configured MCP servers permitted.
1740
- userMcp: z6.boolean(),
1741
- // Subagent dispatch (`Task` / `Agent`) — a grant: `false` on the locked surface, `true` in the
1742
- // coding posture, where the coding allow-hook reaches sub-agent tool calls. A subagent completes
1743
- // within the turn, so it's not an invariant like `scheduling`.
1744
- subagents: z6.boolean(),
1745
- // ── Hard platform invariants — always denied, never granted ────────────────
1746
- // Deferred re-invocation / scheduling (`ScheduleWakeup`, the `Cron*` / `Task*` families,
1747
- // `Monitor`, `Workflow`, …). A turn is one query that resolves on `result`; a scheduled callback
1748
- // fires after the reply window has closed and strands the agent.
1749
- scheduling: z6.literal("never"),
1750
- // Human-facing UI prompts (`AskUserQuestion`). Nothing in a Cabane conversation can answer a
1751
- // structured prompt, so the call hangs the turn. The agent asks in its reply instead.
1752
- uiPrompts: z6.literal("never")
1753
- });
1754
- }
1755
- });
1756
-
1757
1724
  // packages/agent-runtime/src/turn-event.ts
1758
- import { z as z7 } from "zod";
1725
+ import { z as z6 } from "zod";
1759
1726
  var turnEventSchema;
1760
1727
  var init_turn_event = __esm({
1761
1728
  "packages/agent-runtime/src/turn-event.ts"() {
1762
1729
  "use strict";
1763
- turnEventSchema = z7.discriminatedUnion("type", [
1730
+ turnEventSchema = z6.discriminatedUnion("type", [
1764
1731
  // The runtime's opaque session state, emitted when the adapter learns it (e.g. the SDK
1765
1732
  // `system/init` frame). The platform stores `state` verbatim per (conversation, agent) and
1766
1733
  // hands it back next turn; only the adapter knows what it means.
@@ -1772,21 +1739,21 @@ var init_turn_event = __esm({
1772
1739
  // server rewinds the mark, so the next turn rebuilds a full catch-up (this turn is unavoidably
1773
1740
  // lossy — the degrade is known only after the manifest was committed). A plain boolean; the
1774
1741
  // runtime-specific reason stays in the adapter's `onWarn` log. Optional.
1775
- z7.object({
1776
- type: z7.literal("session"),
1777
- state: z7.string(),
1778
- degraded: z7.boolean().optional()
1742
+ z6.object({
1743
+ type: z6.literal("session"),
1744
+ state: z6.string(),
1745
+ degraded: z6.boolean().optional()
1779
1746
  }),
1780
1747
  // One readable thinking summary. Transient — surfaced live, never persisted as content.
1781
- z7.object({ type: z7.literal("thinking"), text: z7.string() }),
1748
+ z6.object({ type: z6.literal("thinking"), text: z6.string() }),
1782
1749
  // Assistant text. `terminal: false` is interim narration (commits as `progress`);
1783
1750
  // `terminal: true` is the turn's closing reply (commits as `final`).
1784
- z7.object({ type: z7.literal("text"), body: z7.string(), terminal: z7.boolean() }),
1751
+ z6.object({ type: z6.literal("text"), body: z6.string(), terminal: z6.boolean() }),
1785
1752
  // Runtime/provider-authored prose about the turn — a failure's explanation, or a line the
1786
1753
  // harness wrote on a turn it recovered. Not the agent's words: the pump persists it as
1787
1754
  // `runtime_notice`, drawn in the SystemNote voice. Adapters emit it only from positive runtime
1788
1755
  // evidence; the web never classifies English strings.
1789
- z7.object({ type: z7.literal("runtime_notice"), body: z7.string() }),
1756
+ z6.object({ type: z6.literal("runtime_notice"), body: z6.string() }),
1790
1757
  // A tool-activity transition. `name` is prefix-stripped (`cabane_read`, not
1791
1758
  // `mcp__cabane__cabane_read`); `summary` is the short card label; `phase` pairs `start` with a
1792
1759
  // later `done`/`error` on the same `id`.
@@ -1795,15 +1762,15 @@ var init_turn_event = __esm({
1795
1762
  // log are a consumer concern (docs/turn-protocol.md). `mcpServer` is the MCP server the call
1796
1763
  // came from (`cabane`, `playwright`, …), derived before `name` dropped the prefix; null for a
1797
1764
  // host tool. Optional, read as null when absent.
1798
- z7.object({
1799
- type: z7.literal("tool"),
1800
- id: z7.string(),
1801
- name: z7.string(),
1802
- phase: z7.enum(["start", "done", "error"]),
1803
- summary: z7.string(),
1804
- input: z7.unknown().optional(),
1805
- result: z7.unknown().optional(),
1806
- mcpServer: z7.string().nullable().optional()
1765
+ z6.object({
1766
+ type: z6.literal("tool"),
1767
+ id: z6.string(),
1768
+ name: z6.string(),
1769
+ phase: z6.enum(["start", "done", "error"]),
1770
+ summary: z6.string(),
1771
+ input: z6.unknown().optional(),
1772
+ result: z6.unknown().optional(),
1773
+ mcpServer: z6.string().nullable().optional()
1807
1774
  }),
1808
1775
  // The turn's terminal outcome. `ok:false` carries a machine reason (`no_session`, an error
1809
1776
  // code), surfaced by the host's clear-PATCH as `errorReason`.
@@ -1824,48 +1791,48 @@ var init_turn_event = __esm({
1824
1791
  // started with); `resolvedConfig` the knobs the harness reported (`{ reasoningEffort }` for
1825
1792
  // codex). Known only after the run streams, so they ride this event home and the host relays
1826
1793
  // them on settle. A cancel has no result event at all.
1827
- z7.object({
1828
- type: z7.literal("result"),
1829
- ok: z7.boolean(),
1830
- reason: z7.string().optional(),
1831
- usage: z7.object({
1832
- inputTokens: z7.number(),
1833
- outputTokens: z7.number(),
1834
- cacheReadTokens: z7.number().optional(),
1835
- cacheCreationTokens: z7.number().optional(),
1836
- contextTokens: z7.number().optional(),
1837
- contextWindow: z7.number().optional(),
1794
+ z6.object({
1795
+ type: z6.literal("result"),
1796
+ ok: z6.boolean(),
1797
+ reason: z6.string().optional(),
1798
+ usage: z6.object({
1799
+ inputTokens: z6.number(),
1800
+ outputTokens: z6.number(),
1801
+ cacheReadTokens: z6.number().optional(),
1802
+ cacheCreationTokens: z6.number().optional(),
1803
+ contextTokens: z6.number().optional(),
1804
+ contextWindow: z6.number().optional(),
1838
1805
  // The rest of the harness's context reading, when it gave one: where it will compact, its
1839
1806
  // `/context` breakdown, and every compaction it reported. Claude Code only.
1840
- contextCompactAt: z7.number().optional(),
1841
- contextCategories: z7.array(
1842
- z7.object({
1843
- name: z7.string(),
1844
- tokens: z7.number(),
1845
- kind: z7.enum(["used", "free", "buffer", "deferred"])
1807
+ contextCompactAt: z6.number().optional(),
1808
+ contextCategories: z6.array(
1809
+ z6.object({
1810
+ name: z6.string(),
1811
+ tokens: z6.number(),
1812
+ kind: z6.enum(["used", "free", "buffer", "deferred"])
1846
1813
  })
1847
1814
  ).optional(),
1848
- contextCompactions: z7.array(
1849
- z7.object({
1850
- trigger: z7.enum(["manual", "auto"]),
1851
- preTokens: z7.number(),
1852
- postTokens: z7.number().optional()
1815
+ contextCompactions: z6.array(
1816
+ z6.object({
1817
+ trigger: z6.enum(["manual", "auto"]),
1818
+ preTokens: z6.number(),
1819
+ postTokens: z6.number().optional()
1853
1820
  })
1854
1821
  ).optional()
1855
1822
  }).optional(),
1856
- resolvedModel: z7.string().optional(),
1857
- resolvedConfig: z7.object({
1858
- effort: z7.string().optional(),
1859
- thinking: z7.string().optional(),
1860
- reasoningEffort: z7.string().optional()
1823
+ resolvedModel: z6.string().optional(),
1824
+ resolvedConfig: z6.object({
1825
+ effort: z6.string().optional(),
1826
+ thinking: z6.string().optional(),
1827
+ reasoningEffort: z6.string().optional()
1861
1828
  }).optional(),
1862
1829
  // The harness-reported MCP inventory from this turn's init frame. Diagnostic only: names,
1863
1830
  // statuses and a count — never server definitions, credentials or session ids.
1864
1831
  // `initReceived:false` tells a missing init frame from a real empty inventory.
1865
- mcpInventory: z7.object({
1866
- initReceived: z7.boolean(),
1867
- servers: z7.array(z7.object({ name: z7.string(), status: z7.string() })),
1868
- toolCount: z7.number().int().nonnegative()
1832
+ mcpInventory: z6.object({
1833
+ initReceived: z6.boolean(),
1834
+ servers: z6.array(z6.object({ name: z6.string(), status: z6.string() })),
1835
+ toolCount: z6.number().int().nonnegative()
1869
1836
  }).optional()
1870
1837
  })
1871
1838
  ]);
@@ -1873,27 +1840,27 @@ var init_turn_event = __esm({
1873
1840
  });
1874
1841
 
1875
1842
  // packages/agent-runtime/src/turn-diagnostics.ts
1876
- import { z as z8 } from "zod";
1843
+ import { z as z7 } from "zod";
1877
1844
  var turnResultReasonSchema, turnOutcomes, turnSessionModes, turnRuntimeResultKinds, turnFinalSources, turnDiagnosticsSchema;
1878
1845
  var init_turn_diagnostics = __esm({
1879
1846
  "packages/agent-runtime/src/turn-diagnostics.ts"() {
1880
1847
  "use strict";
1881
- turnResultReasonSchema = z8.discriminatedUnion("kind", [
1882
- z8.object({ kind: z8.literal("usage_capped"), resetsAt: z8.string().optional() }),
1883
- z8.object({ kind: z8.literal("rate_limited") }),
1884
- z8.object({ kind: z8.literal("server_error") }),
1885
- z8.object({ kind: z8.literal("auth_expired") }),
1886
- z8.object({ kind: z8.literal("no_result") }),
1887
- z8.object({ kind: z8.literal("empty_result") }),
1888
- z8.object({ kind: z8.literal("empty_result_unverified") }),
1889
- z8.object({ kind: z8.literal("timeout_idle") }),
1890
- z8.object({ kind: z8.literal("timeout_total") }),
1891
- z8.object({ kind: z8.literal("cancelled") }),
1892
- z8.object({ kind: z8.literal("lease_lost") }),
1893
- z8.object({ kind: z8.literal("skipped") }),
1894
- z8.object({ kind: z8.literal("session_start_failed") }),
1895
- z8.object({ kind: z8.literal("workspace_tools_missing") }),
1896
- z8.object({ kind: z8.literal("runtime_error") })
1848
+ turnResultReasonSchema = z7.discriminatedUnion("kind", [
1849
+ z7.object({ kind: z7.literal("usage_capped"), resetsAt: z7.string().optional() }),
1850
+ z7.object({ kind: z7.literal("rate_limited") }),
1851
+ z7.object({ kind: z7.literal("server_error") }),
1852
+ z7.object({ kind: z7.literal("auth_expired") }),
1853
+ z7.object({ kind: z7.literal("no_result") }),
1854
+ z7.object({ kind: z7.literal("empty_result") }),
1855
+ z7.object({ kind: z7.literal("empty_result_unverified") }),
1856
+ z7.object({ kind: z7.literal("timeout_idle") }),
1857
+ z7.object({ kind: z7.literal("timeout_total") }),
1858
+ z7.object({ kind: z7.literal("cancelled") }),
1859
+ z7.object({ kind: z7.literal("lease_lost") }),
1860
+ z7.object({ kind: z7.literal("skipped") }),
1861
+ z7.object({ kind: z7.literal("session_start_failed") }),
1862
+ z7.object({ kind: z7.literal("workspace_tools_missing") }),
1863
+ z7.object({ kind: z7.literal("runtime_error") })
1897
1864
  ]);
1898
1865
  turnOutcomes = ["success", "failure", "cancelled", "skipped"];
1899
1866
  turnSessionModes = ["fresh", "resumed", "degraded"];
@@ -1905,25 +1872,25 @@ var init_turn_diagnostics = __esm({
1905
1872
  "marker",
1906
1873
  "none"
1907
1874
  ];
1908
- turnDiagnosticsSchema = z8.object({
1909
- outcome: z8.enum(turnOutcomes),
1875
+ turnDiagnosticsSchema = z7.object({
1876
+ outcome: z7.enum(turnOutcomes),
1910
1877
  resultReason: turnResultReasonSchema.nullable(),
1911
- sessionMode: z8.enum(turnSessionModes),
1912
- sessionFingerprint: z8.string().regex(/^[a-f0-9]{16}$/).nullable(),
1913
- eventCounts: z8.object({
1914
- session: z8.number().int().nonnegative(),
1915
- text: z8.number().int().nonnegative(),
1916
- runtime_notice: z8.number().int().nonnegative(),
1917
- thinking: z8.number().int().nonnegative(),
1918
- tool: z8.number().int().nonnegative(),
1919
- result: z8.number().int().nonnegative()
1878
+ sessionMode: z7.enum(turnSessionModes),
1879
+ sessionFingerprint: z7.string().regex(/^[a-f0-9]{16}$/).nullable(),
1880
+ eventCounts: z7.object({
1881
+ session: z7.number().int().nonnegative(),
1882
+ text: z7.number().int().nonnegative(),
1883
+ runtime_notice: z7.number().int().nonnegative(),
1884
+ thinking: z7.number().int().nonnegative(),
1885
+ tool: z7.number().int().nonnegative(),
1886
+ result: z7.number().int().nonnegative()
1920
1887
  }),
1921
- runtimeResultKind: z8.enum(turnRuntimeResultKinds).nullable(),
1922
- finalSource: z8.enum(turnFinalSources),
1923
- mcpInventory: z8.object({
1924
- initReceived: z8.boolean(),
1925
- servers: z8.array(z8.object({ name: z8.string(), status: z8.string() })),
1926
- toolCount: z8.number().int().nonnegative()
1888
+ runtimeResultKind: z7.enum(turnRuntimeResultKinds).nullable(),
1889
+ finalSource: z7.enum(turnFinalSources),
1890
+ mcpInventory: z7.object({
1891
+ initReceived: z7.boolean(),
1892
+ servers: z7.array(z7.object({ name: z7.string(), status: z7.string() })),
1893
+ toolCount: z7.number().int().nonnegative()
1927
1894
  }).optional()
1928
1895
  });
1929
1896
  }
@@ -1997,105 +1964,106 @@ var init_empty_result = __esm({
1997
1964
  });
1998
1965
 
1999
1966
  // packages/agent-runtime/src/turn-request.ts
2000
- import { z as z9 } from "zod";
1967
+ import { z as z8 } from "zod";
2001
1968
  var contentBlockSchema, effortLevelSchema, resolvedRunConfigSchema, resolvedMcpServerSchema, resolvedMcpServersSchema, hostInjectedServersSchema, turnRequestSchema;
2002
1969
  var init_turn_request = __esm({
2003
1970
  "packages/agent-runtime/src/turn-request.ts"() {
2004
1971
  "use strict";
2005
- init_host_policy();
2006
- contentBlockSchema = z9.discriminatedUnion("type", [
2007
- z9.object({ type: z9.literal("text"), text: z9.string() }),
2008
- z9.object({
2009
- type: z9.literal("image"),
2010
- source: z9.object({ type: z9.literal("url"), url: z9.string() })
1972
+ contentBlockSchema = z8.discriminatedUnion("type", [
1973
+ z8.object({ type: z8.literal("text"), text: z8.string() }),
1974
+ z8.object({
1975
+ type: z8.literal("image"),
1976
+ source: z8.object({ type: z8.literal("url"), url: z8.string() })
2011
1977
  }),
2012
- z9.object({
2013
- type: z9.literal("document"),
2014
- source: z9.object({ type: z9.literal("url"), url: z9.string() })
1978
+ z8.object({
1979
+ type: z8.literal("document"),
1980
+ source: z8.object({ type: z8.literal("url"), url: z8.string() })
2015
1981
  })
2016
1982
  ]);
2017
- effortLevelSchema = z9.enum(["low", "medium", "high", "xhigh", "max"]);
2018
- resolvedRunConfigSchema = z9.object({
2019
- model: z9.string().nullable(),
1983
+ effortLevelSchema = z8.enum(["low", "medium", "high", "xhigh", "max"]);
1984
+ resolvedRunConfigSchema = z8.object({
1985
+ model: z8.string().nullable(),
2020
1986
  effort: effortLevelSchema.optional(),
2021
- runtimeOptions: z9.record(z9.string(), z9.unknown()).optional()
1987
+ runtimeOptions: z8.record(z8.string(), z8.unknown()).optional()
2022
1988
  });
2023
- resolvedMcpServerSchema = z9.union([
2024
- z9.object({
2025
- type: z9.literal("stdio").optional(),
2026
- command: z9.string(),
2027
- args: z9.array(z9.string()).optional(),
2028
- env: z9.record(z9.string(), z9.string()).optional(),
2029
- envFromEnv: z9.record(z9.string(), z9.string()).optional()
1989
+ resolvedMcpServerSchema = z8.union([
1990
+ z8.object({
1991
+ type: z8.literal("stdio").optional(),
1992
+ command: z8.string(),
1993
+ args: z8.array(z8.string()).optional(),
1994
+ env: z8.record(z8.string(), z8.string()).optional(),
1995
+ envFromEnv: z8.record(z8.string(), z8.string()).optional()
2030
1996
  }),
2031
- z9.object({
2032
- type: z9.literal("http"),
2033
- url: z9.string(),
2034
- headers: z9.record(z9.string(), z9.string()).optional(),
2035
- headersFromEnv: z9.record(z9.string(), z9.string()).optional()
1997
+ z8.object({
1998
+ type: z8.literal("http"),
1999
+ url: z8.string(),
2000
+ headers: z8.record(z8.string(), z8.string()).optional(),
2001
+ headersFromEnv: z8.record(z8.string(), z8.string()).optional()
2036
2002
  }),
2037
- z9.object({
2038
- type: z9.literal("sse"),
2039
- url: z9.string(),
2040
- headers: z9.record(z9.string(), z9.string()).optional(),
2041
- headersFromEnv: z9.record(z9.string(), z9.string()).optional()
2003
+ z8.object({
2004
+ type: z8.literal("sse"),
2005
+ url: z8.string(),
2006
+ headers: z8.record(z8.string(), z8.string()).optional(),
2007
+ headersFromEnv: z8.record(z8.string(), z8.string()).optional()
2042
2008
  })
2043
2009
  ]);
2044
- resolvedMcpServersSchema = z9.record(z9.string(), resolvedMcpServerSchema);
2045
- hostInjectedServersSchema = z9.record(z9.string(), z9.unknown());
2046
- turnRequestSchema = z9.object({
2010
+ resolvedMcpServersSchema = z8.record(z8.string(), resolvedMcpServerSchema);
2011
+ hostInjectedServersSchema = z8.record(z8.string(), z8.unknown());
2012
+ turnRequestSchema = z8.object({
2047
2013
  // Server-composed standing instructions: the core segment (body, tool naming, identity, agent
2048
2014
  // charter) and, after it, the conversation segment (workspace and room charters, skill indexes,
2049
2015
  // roster). One string to the adapter, current as of this dispatch.
2050
- systemPrompt: z9.string(),
2016
+ systemPrompt: z8.string(),
2051
2017
  // The same text as its two ordered segments, so an adapter that writes standing text into the
2052
2018
  // conversation (Codex's input preamble) can tell which half changed. `systemPrompt` is
2053
2019
  // `joinStanding(standing)`. Optional: absent from an API older than the split, where
2054
2020
  // `systemPrompt` is the core alone and the conversation material rides `prompt`.
2055
- standing: z9.object({ core: z9.string(), conversation: z9.string() }).optional(),
2021
+ standing: z8.object({ core: z8.string(), conversation: z8.string() }).optional(),
2056
2022
  // Server-composed per-turn user text (anchor reminder + the triggering message).
2057
- prompt: z9.string(),
2023
+ prompt: z8.string(),
2058
2024
  // The multi-block user-message body (text + vision).
2059
- content: z9.array(contentBlockSchema),
2025
+ content: z8.array(contentBlockSchema),
2060
2026
  // Portable-or-dialect run-config (above).
2061
2027
  config: resolvedRunConfigSchema,
2062
- // Abstract capability grants; the adapter maps them to tool names.
2063
- policy: hostPolicySchema,
2064
2028
  // Prior opaque session state, or null for a fresh session.
2065
- session: z9.string().nullable(),
2029
+ session: z8.string().nullable(),
2066
2030
  // The cabane control-plane coordinates for this turn's MCP + post-back.
2067
- cabane: z9.object({
2068
- mcpUrl: z9.string(),
2069
- bearer: z9.string(),
2070
- activeConversationId: z9.string(),
2031
+ cabane: z8.object({
2032
+ mcpUrl: z8.string(),
2033
+ bearer: z8.string(),
2034
+ activeConversationId: z8.string(),
2071
2035
  // Scoped turn-control MCP URL. Codex and opencode mount it as `cabane_companion` with the bearer
2072
2036
  // and active-conversation header, for ask, withdraw_ask, wake_me, cancel_wake and skip_turn.
2073
2037
  // Claude Code mounts the companion's in-process instance instead. Optional; the companion
2074
2038
  // populates it.
2075
- turnControlUrl: z9.string().optional(),
2039
+ turnControlUrl: z8.string().optional(),
2076
2040
  // Workspace coordinate retained for envelope compatibility. Current
2077
2041
  // adapters use MCP, whose workspace operations take workspaceId explicitly.
2078
2042
  // The companion supplies this field; it is not required by those adapters.
2079
- workspaceId: z9.string().optional()
2043
+ workspaceId: z8.string().optional()
2080
2044
  }),
2081
2045
  // Machine-local resolution (host-filled): the checkout cwd, extra env from a
2082
2046
  // prepare hook, and the resolved user MCP servers.
2083
- local: z9.object({
2084
- cwd: z9.string().optional(),
2085
- env: z9.record(z9.string(), z9.string()).optional(),
2047
+ local: z8.object({
2048
+ cwd: z8.string().optional(),
2049
+ env: z8.record(z8.string(), z8.string()).optional(),
2086
2050
  mcpServers: resolvedMcpServersSchema.optional(),
2087
2051
  // The values `headersFromEnv` names, per turn (`CABANE_MCP_<n>` → complete header value). The
2088
2052
  // adapter merges them into the harness process's environment and nowhere else; the host never
2089
2053
  // merges them into its own. Absent when no server references one.
2090
- secretEnv: z9.record(z9.string(), z9.string()).optional(),
2054
+ secretEnv: z8.record(z8.string(), z8.string()).optional(),
2091
2055
  // Machine-local claude-code knobs for an operator running their own companion — the auto-memory
2092
2056
  // escape hatch. `autoMemory: true` opts back into Claude Code's auto-memory (governed by the
2093
2057
  // operator's `.claude/settings.json`); absent/false keeps the adapter's force-off default
2094
2058
  // (`buildClaudeCodeOptions`).
2095
- claudeCode: z9.object({ autoMemory: z9.boolean().optional() }).optional()
2059
+ claudeCode: z8.object({ autoMemory: z8.boolean().optional() }).optional(),
2060
+ // Machine-local Codex facts the host read before the turn. `configSetsSandboxMode`: the
2061
+ // person's own Codex `config.toml` names a `sandbox_mode`, so the adapter passes no sandbox
2062
+ // flag and the file governs (`codexSandboxMode`). Absent/false → `danger-full-access`.
2063
+ codex: z8.object({ configSetsSandboxMode: z8.boolean().optional() }).optional()
2096
2064
  }),
2097
2065
  // Host-owned injected servers (host-filled).
2098
- extra: z9.object({
2066
+ extra: z8.object({
2099
2067
  mcpServers: hostInjectedServersSchema
2100
2068
  })
2101
2069
  });
@@ -2119,18 +2087,18 @@ var init_standing = __esm({
2119
2087
  });
2120
2088
 
2121
2089
  // packages/agent-runtime/src/conformance.ts
2122
- import { z as z10 } from "zod";
2090
+ import { z as z9 } from "zod";
2123
2091
  var conformanceFixtureSchema;
2124
2092
  var init_conformance = __esm({
2125
2093
  "packages/agent-runtime/src/conformance.ts"() {
2126
2094
  "use strict";
2127
2095
  init_turn_event();
2128
2096
  init_turn_request();
2129
- conformanceFixtureSchema = z10.object({
2130
- name: z10.string(),
2097
+ conformanceFixtureSchema = z9.object({
2098
+ name: z9.string(),
2131
2099
  request: turnRequestSchema,
2132
- nativeStream: z10.array(z10.unknown()),
2133
- expected: z10.array(turnEventSchema)
2100
+ nativeStream: z9.array(z9.unknown()),
2101
+ expected: z9.array(turnEventSchema)
2134
2102
  });
2135
2103
  }
2136
2104
  });
@@ -2627,13 +2595,7 @@ var init_mcp_secret_env = __esm({
2627
2595
  });
2628
2596
 
2629
2597
  // packages/agent-runtime/src/claude-code/policy.ts
2630
- import { z as z11 } from "zod";
2631
- function disallowedToolsFor(policy) {
2632
- const tools = [...UNSUPPORTED_TOOLS, ...STRANDING_TOOLS];
2633
- if (!policy.subagents) tools.unshift(...SUBAGENT_TOOLS);
2634
- if (!policy.hostFs) tools.unshift(...HOST_FS_TOOLS);
2635
- return tools;
2636
- }
2598
+ import { z as z10 } from "zod";
2637
2599
  function withThinkingSummaries(thinking) {
2638
2600
  if (!thinking) return { type: "adaptive", display: "summarized" };
2639
2601
  if (thinking.type === "disabled") return thinking;
@@ -2645,27 +2607,10 @@ function readThinking(runtimeOptions) {
2645
2607
  if (!parsed.success) return void 0;
2646
2608
  return parsed.data.thinking;
2647
2609
  }
2648
- var HOST_FS_TOOLS, SUBAGENT_TOOLS, UNSUPPORTED_TOOLS, STRANDING_TOOLS, DEFAULT_WEB_TOOLS, claudeCodeDialectSchema;
2610
+ var SUBAGENT_TOOLS, UNSUPPORTED_TOOLS, STRANDING_TOOLS, DEFAULT_WEB_TOOLS, claudeCodeDialectSchema;
2649
2611
  var init_policy = __esm({
2650
2612
  "packages/agent-runtime/src/claude-code/policy.ts"() {
2651
2613
  "use strict";
2652
- HOST_FS_TOOLS = [
2653
- // shell + local filesystem
2654
- "Bash",
2655
- "Read",
2656
- "Write",
2657
- "Edit",
2658
- "Glob",
2659
- "Grep",
2660
- // notebook tools (host-fs, Jupyter) — same host reach as Read/Write/Edit
2661
- "NotebookEdit",
2662
- "NotebookRead",
2663
- // git-worktree manipulation on the host checkout
2664
- "EnterWorktree",
2665
- "ExitWorktree",
2666
- // host code execution
2667
- "REPL"
2668
- ];
2669
2614
  SUBAGENT_TOOLS = ["Task", "Agent"];
2670
2615
  UNSUPPORTED_TOOLS = ["AskUserQuestion"];
2671
2616
  STRANDING_TOOLS = [
@@ -2687,18 +2632,18 @@ var init_policy = __esm({
2687
2632
  "Workflow"
2688
2633
  ];
2689
2634
  DEFAULT_WEB_TOOLS = ["WebSearch", "WebFetch"];
2690
- claudeCodeDialectSchema = z11.object({
2691
- thinking: z11.discriminatedUnion("type", [
2692
- z11.object({
2693
- type: z11.literal("adaptive"),
2694
- display: z11.enum(["summarized", "omitted"]).optional()
2635
+ claudeCodeDialectSchema = z10.object({
2636
+ thinking: z10.discriminatedUnion("type", [
2637
+ z10.object({
2638
+ type: z10.literal("adaptive"),
2639
+ display: z10.enum(["summarized", "omitted"]).optional()
2695
2640
  }),
2696
- z11.object({
2697
- type: z11.literal("enabled"),
2698
- budgetTokens: z11.number().int().positive().optional(),
2699
- display: z11.enum(["summarized", "omitted"]).optional()
2641
+ z10.object({
2642
+ type: z10.literal("enabled"),
2643
+ budgetTokens: z10.number().int().positive().optional(),
2644
+ display: z10.enum(["summarized", "omitted"]).optional()
2700
2645
  }),
2701
- z11.object({ type: z11.literal("disabled") })
2646
+ z10.object({ type: z10.literal("disabled") })
2702
2647
  ]).optional()
2703
2648
  }).loose();
2704
2649
  }
@@ -2766,13 +2711,13 @@ async function preToolUseHook(input) {
2766
2711
  hookSpecificOutput: {
2767
2712
  hookEventName: "PreToolUse",
2768
2713
  permissionDecision: "allow",
2769
- permissionDecisionReason: "coding mode: headless never-prompt (CT680)",
2714
+ permissionDecisionReason: "headless never-prompt (CT680)",
2770
2715
  updatedInput: toolInput
2771
2716
  }
2772
2717
  };
2773
2718
  }
2774
2719
  function buildClaudeCodeOptions(req, augment) {
2775
- const { policy, config } = req;
2720
+ const { config } = req;
2776
2721
  const cwd = req.local.cwd;
2777
2722
  const userServers = {};
2778
2723
  for (const [name, server] of Object.entries(req.local.mcpServers ?? {})) {
@@ -2805,15 +2750,10 @@ function buildClaudeCodeOptions(req, augment) {
2805
2750
  alwaysLoad: true
2806
2751
  };
2807
2752
  }
2808
- const useCodingPreset = policy.hostFs;
2809
2753
  const cabaneGlob = `mcp__${CABANE_MCP_SERVER}__*`;
2810
2754
  const extraServerGlobs = Object.keys(req.extra.mcpServers).map((name) => `mcp__${name}__*`);
2811
- const allowedTools = dedupe([
2812
- cabaneGlob,
2813
- ...extraServerGlobs,
2814
- ...policy.web ? DEFAULT_WEB_TOOLS : []
2815
- ]);
2816
- const disallowedTools = dedupe([...disallowedToolsFor(policy)]);
2755
+ const allowedTools = dedupe([cabaneGlob, ...extraServerGlobs, ...DEFAULT_WEB_TOOLS]);
2756
+ const disallowedTools = dedupe([...UNSUPPORTED_TOOLS, ...STRANDING_TOOLS]);
2817
2757
  const resumeDecision = decideResume(req.session, cwd);
2818
2758
  const resume = "resume" in resumeDecision ? resumeDecision.resume : null;
2819
2759
  const freshReason = "fresh" in resumeDecision ? resumeDecision.reason : void 0;
@@ -2831,9 +2771,7 @@ function buildClaudeCodeOptions(req, augment) {
2831
2771
  // (`runtimeOptions['claude-code']`).
2832
2772
  thinking: withThinkingSummaries(readThinking(config.runtimeOptions)),
2833
2773
  ...config.effort ? { effort: config.effort } : {},
2834
- // Never merge arbitrary user `~/.claude` config; without `strictMcpConfig` the
2835
- // user's existing `cabane` MCP registration could shadow ours.
2836
- settingSources: [],
2774
+ // Without `strictMcpConfig` the user's existing `cabane` MCP registration could shadow ours.
2837
2775
  strictMcpConfig: true,
2838
2776
  // Auto-memory off unless the operator opted back in (see above).
2839
2777
  ...devControlsAutoMemory ? {} : { settings: { autoMemoryEnabled: false } },
@@ -2869,31 +2807,19 @@ function buildClaudeCodeOptions(req, augment) {
2869
2807
  },
2870
2808
  ...resume ? { resume } : {}
2871
2809
  };
2872
- let options;
2873
- if (useCodingPreset) {
2874
- options = {
2875
- ...base,
2876
- systemPrompt: {
2877
- type: "preset",
2878
- preset: "claude_code",
2879
- append: req.systemPrompt,
2880
- snapshot: false
2881
- },
2882
- settingSources: ["user", "project"],
2883
- allowedTools,
2884
- disallowedTools,
2885
- hooks: { PreToolUse: [{ hooks: [preToolUseHook] }] }
2886
- };
2887
- } else {
2888
- options = {
2889
- ...base,
2890
- systemPrompt: { type: "custom", prompt: req.systemPrompt, snapshot: false },
2891
- allowedTools,
2892
- disallowedTools,
2893
- permissionMode: "bypassPermissions",
2894
- allowDangerouslySkipPermissions: true
2895
- };
2896
- }
2810
+ const options = {
2811
+ ...base,
2812
+ systemPrompt: {
2813
+ type: "preset",
2814
+ preset: "claude_code",
2815
+ append: req.systemPrompt,
2816
+ snapshot: false
2817
+ },
2818
+ settingSources: ["user", "project"],
2819
+ allowedTools,
2820
+ disallowedTools,
2821
+ hooks: { PreToolUse: [{ hooks: [preToolUseHook] }] }
2822
+ };
2897
2823
  return { options: augment ? augment(options, req) : options, resume, freshReason };
2898
2824
  }
2899
2825
  function dedupe(xs) {
@@ -3440,7 +3366,6 @@ function makeRequest(overrides2 = {}) {
3440
3366
  content: [{ type: "text", text: "hi there" }],
3441
3367
  // The adapter rejects a null model, so the fixture carries a real bare SDK id.
3442
3368
  config: { model: "claude-opus-4-8" },
3443
- policy: CABANE_POLICY,
3444
3369
  session: null,
3445
3370
  cabane: { mcpUrl: "https://cabane.test/api/mcp", bearer: "tok", activeConversationId: "conv" },
3446
3371
  local: { cwd: CWD },
@@ -3448,22 +3373,13 @@ function makeRequest(overrides2 = {}) {
3448
3373
  ...overrides2
3449
3374
  };
3450
3375
  }
3451
- var ABORT_SENTINEL, CABANE_POLICY, CWD, HEALTHY_MCP_INVENTORY, init, assistantText, assistantTextTool, toolResult, resultSuccess, resultSuccessFull, resultError, resultErrorFull, rateLimitEvent, authStatus, sessionEvent, BASE_CLAUDE_CODE_CONFORMANCE_FIXTURES, CLAUDE_CODE_CONFORMANCE_FIXTURES;
3376
+ var ABORT_SENTINEL, CWD, HEALTHY_MCP_INVENTORY, init, assistantText, assistantTextTool, toolResult, resultSuccess, resultSuccessFull, resultError, resultErrorFull, rateLimitEvent, authStatus, sessionEvent, BASE_CLAUDE_CODE_CONFORMANCE_FIXTURES, CLAUDE_CODE_CONFORMANCE_FIXTURES;
3452
3377
  var init_conformance2 = __esm({
3453
3378
  "packages/agent-runtime/src/claude-code/conformance.ts"() {
3454
3379
  "use strict";
3455
3380
  init_claude_code();
3456
3381
  init_session();
3457
3382
  ABORT_SENTINEL = { __abortHere: true };
3458
- CABANE_POLICY = {
3459
- hostFs: false,
3460
- web: true,
3461
- browser: false,
3462
- userMcp: false,
3463
- subagents: false,
3464
- scheduling: "never",
3465
- uiPrompts: "never"
3466
- };
3467
3383
  CWD = "/env/here";
3468
3384
  HEALTHY_MCP_INVENTORY = {
3469
3385
  initReceived: true,
@@ -4266,43 +4182,25 @@ var init_loop2 = __esm({
4266
4182
  });
4267
4183
 
4268
4184
  // packages/agent-runtime/src/opencode/policy.ts
4269
- import { z as z12 } from "zod";
4270
- function opencodeToolPolicy(policy) {
4185
+ import { z as z11 } from "zod";
4186
+ function opencodeTools() {
4271
4187
  const tools = {};
4272
- const deny = (names) => {
4273
- for (const n of names) tools[n] = false;
4274
- };
4275
- if (!policy.hostFs) deny(OPENCODE_HOST_TOOLS);
4276
- if (!policy.subagents) deny(OPENCODE_SUBAGENT_TOOLS);
4277
- if (!policy.web) deny(OPENCODE_WEB_TOOLS);
4278
- deny(OPENCODE_SCHEDULING_TOOLS);
4279
- deny(OPENCODE_UI_PROMPT_TOOLS);
4280
- return { tools, allowAllHostTools: policy.hostFs };
4188
+ for (const name of [...OPENCODE_SCHEDULING_TOOLS, ...OPENCODE_UI_PROMPT_TOOLS])
4189
+ tools[name] = false;
4190
+ return tools;
4281
4191
  }
4282
4192
  function readOpencodeDialect(runtimeOptions) {
4283
4193
  const parsed = opencodeDialectSchema.safeParse(runtimeOptions?.["opencode"] ?? {});
4284
4194
  return parsed.success ? parsed.data : {};
4285
4195
  }
4286
- var OPENCODE_HOST_TOOLS, OPENCODE_WEB_TOOLS, OPENCODE_SUBAGENT_TOOLS, OPENCODE_SCHEDULING_TOOLS, OPENCODE_UI_PROMPT_TOOLS, opencodeDialectSchema;
4196
+ var OPENCODE_SCHEDULING_TOOLS, OPENCODE_UI_PROMPT_TOOLS, opencodeDialectSchema;
4287
4197
  var init_policy2 = __esm({
4288
4198
  "packages/agent-runtime/src/opencode/policy.ts"() {
4289
4199
  "use strict";
4290
- OPENCODE_HOST_TOOLS = [
4291
- "bash",
4292
- "edit",
4293
- "write",
4294
- "read",
4295
- "grep",
4296
- "glob",
4297
- "list",
4298
- "patch"
4299
- ];
4300
- OPENCODE_WEB_TOOLS = ["webfetch"];
4301
- OPENCODE_SUBAGENT_TOOLS = ["task"];
4302
4200
  OPENCODE_SCHEDULING_TOOLS = [];
4303
4201
  OPENCODE_UI_PROMPT_TOOLS = ["question"];
4304
- opencodeDialectSchema = z12.object({
4305
- agent: z12.string().min(1).optional()
4202
+ opencodeDialectSchema = z11.object({
4203
+ agent: z11.string().min(1).optional()
4306
4204
  }).loose();
4307
4205
  }
4308
4206
  });
@@ -4321,18 +4219,16 @@ var init_model2 = __esm({
4321
4219
 
4322
4220
  // packages/agent-runtime/src/opencode/run-spec.ts
4323
4221
  function buildRunSpec(req, resumeSessionId) {
4324
- const { policy, config } = req;
4222
+ const { config } = req;
4325
4223
  const directory = req.local.cwd ?? "";
4326
4224
  const dialect = readOpencodeDialect(config.runtimeOptions);
4327
- const { tools, allowAllHostTools } = opencodeToolPolicy(policy);
4328
4225
  return {
4329
4226
  resumeSessionId,
4330
4227
  directory,
4331
4228
  model: config.model ? parseOpencodeModel(config.model) : null,
4332
4229
  systemPrompt: req.systemPrompt,
4333
4230
  parts: buildParts(req),
4334
- tools,
4335
- allowAllHostTools,
4231
+ tools: opencodeTools(),
4336
4232
  ...dialect.agent ? { agent: dialect.agent } : {},
4337
4233
  mcp: buildMcp(req),
4338
4234
  // Every server this turn installs with a credential resolved into it: a remote one's
@@ -4480,11 +4376,12 @@ function createHttpOpencodeTransport(opts) {
4480
4376
  const doFetch = opts.fetchImpl ?? fetch;
4481
4377
  return {
4482
4378
  async run(spec, signal) {
4379
+ const url = scopedUrl(base, spec.directory);
4483
4380
  const release = await acquireServerTurnLock(base);
4484
4381
  if (signal.aborted) release();
4485
4382
  else signal.addEventListener("abort", release, { once: true });
4486
4383
  try {
4487
- const eventRes = await doFetch(`${base}/event`, {
4384
+ const eventRes = await doFetch(url("/event"), {
4488
4385
  headers: { accept: "text/event-stream" },
4489
4386
  signal
4490
4387
  });
@@ -4494,7 +4391,7 @@ function createHttpOpencodeTransport(opts) {
4494
4391
  let sessionId = spec.resumeSessionId;
4495
4392
  let created = false;
4496
4393
  if (!sessionId) {
4497
- const res = await doFetch(`${base}/session`, {
4394
+ const res = await doFetch(url("/session"), {
4498
4395
  method: "POST",
4499
4396
  headers: { "content-type": "application/json" },
4500
4397
  body: JSON.stringify({ body: {} }),
@@ -4506,9 +4403,9 @@ function createHttpOpencodeTransport(opts) {
4506
4403
  sessionId = json.id;
4507
4404
  created = true;
4508
4405
  }
4509
- await installMcp(doFetch, base, spec, signal);
4406
+ await installMcp(doFetch, url, spec, signal);
4510
4407
  const promptRes = await doFetch(
4511
- `${base}/session/${encodeURIComponent(sessionId)}/prompt_async`,
4408
+ url(`/session/${encodeURIComponent(sessionId)}/prompt_async`),
4512
4409
  {
4513
4410
  method: "POST",
4514
4411
  headers: { "content-type": "application/json" },
@@ -4527,7 +4424,7 @@ function createHttpOpencodeTransport(opts) {
4527
4424
  }
4528
4425
  const sid = sessionId;
4529
4426
  const onAbort = () => {
4530
- void doFetch(`${base}/session/${encodeURIComponent(sid)}/abort`, {
4427
+ void doFetch(url(`/session/${encodeURIComponent(sid)}/abort`), {
4531
4428
  method: "POST"
4532
4429
  }).catch(() => {
4533
4430
  });
@@ -4539,7 +4436,13 @@ function createHttpOpencodeTransport(opts) {
4539
4436
  created,
4540
4437
  directory: spec.directory,
4541
4438
  // The lock is released when this stream finishes draining.
4542
- events: releaseAfter(parseSseStream(eventRes.body, sessionId, signal), release)
4439
+ events: releaseAfter(
4440
+ approvePermissions(
4441
+ parseSseStream(eventRes.body, sessionId, signal),
4442
+ (ev) => replyToPermission(doFetch, url, ev, signal)
4443
+ ),
4444
+ release
4445
+ )
4543
4446
  };
4544
4447
  } catch (err) {
4545
4448
  release();
@@ -4555,16 +4458,16 @@ async function* releaseAfter(events, release) {
4555
4458
  release();
4556
4459
  }
4557
4460
  }
4558
- async function installMcp(doFetch, base, spec, signal) {
4461
+ async function installMcp(doFetch, url, spec, signal) {
4559
4462
  const [live, configured] = await Promise.all([
4560
- getJson(doFetch, `${base}/mcp`, signal),
4561
- getJson(doFetch, `${base}/config`, signal)
4463
+ getJson(doFetch, url("/mcp"), signal),
4464
+ getJson(doFetch, url("/config"), signal)
4562
4465
  ]);
4563
4466
  const operatorOwned = new Set(Object.keys(asRecord2(asRecord2(configured).mcp)));
4564
4467
  const stale = Object.keys(asRecord2(live)).filter(
4565
4468
  (name) => !(name in spec.mcp) && !operatorOwned.has(name)
4566
4469
  );
4567
- await Promise.all(stale.map((name) => postMcp(doFetch, base, name, SCRUBBED_MCP_CONFIG, signal)));
4470
+ await Promise.all(stale.map((name) => postMcp(doFetch, url, name, SCRUBBED_MCP_CONFIG, signal)));
4568
4471
  const shadowing = (spec.credentialServers ?? []).filter((name) => operatorOwned.has(name));
4569
4472
  if (shadowing.length > 0) {
4570
4473
  throw new Error(
@@ -4572,11 +4475,11 @@ async function installMcp(doFetch, base, spec, signal) {
4572
4475
  );
4573
4476
  }
4574
4477
  await Promise.all(
4575
- Object.entries(spec.mcp).map(([name, config]) => postMcp(doFetch, base, name, config, signal))
4478
+ Object.entries(spec.mcp).map(([name, config]) => postMcp(doFetch, url, name, config, signal))
4576
4479
  );
4577
4480
  }
4578
- async function postMcp(doFetch, base, name, config, signal) {
4579
- const res = await doFetch(`${base}/mcp`, {
4481
+ async function postMcp(doFetch, url, name, config, signal) {
4482
+ const res = await doFetch(url("/mcp"), {
4580
4483
  method: "POST",
4581
4484
  headers: { "content-type": "application/json" },
4582
4485
  body: JSON.stringify({ name, config }),
@@ -4640,6 +4543,33 @@ function belongsToSession(ev, sessionId) {
4640
4543
  if (typeof infoSid === "string") return infoSid === sessionId;
4641
4544
  return true;
4642
4545
  }
4546
+ async function* approvePermissions(events, reply2) {
4547
+ for await (const ev of events) {
4548
+ if (ev.type === "permission.asked" || ev.type === "permission.v2.asked") await reply2(ev);
4549
+ yield ev;
4550
+ }
4551
+ }
4552
+ async function replyToPermission(doFetch, url, ev, signal) {
4553
+ const props = asRecord2(ev.properties);
4554
+ const id = typeof props.id === "string" ? props.id : null;
4555
+ const sessionId = typeof props.sessionID === "string" ? props.sessionID : null;
4556
+ if (!id) throw new Error(`opencode: ${ev.type} carried no request id`);
4557
+ const target = ev.type === "permission.v2.asked" && sessionId ? url(
4558
+ `/api/session/${encodeURIComponent(sessionId)}/permission/${encodeURIComponent(id)}/reply`,
4559
+ { unscoped: true }
4560
+ ) : url(`/permission/${encodeURIComponent(id)}/reply`);
4561
+ const res = await doFetch(target, {
4562
+ method: "POST",
4563
+ headers: { "content-type": "application/json" },
4564
+ body: JSON.stringify({ reply: "once" }),
4565
+ signal
4566
+ });
4567
+ if (!res.ok) throw new Error(`opencode: permission reply failed (HTTP ${res.status})`);
4568
+ }
4569
+ function scopedUrl(base, directory) {
4570
+ const scope = directory ? `directory=${encodeURIComponent(directory)}` : "";
4571
+ return (path, opts) => scope && !opts?.unscoped ? `${base}${path}${path.includes("?") ? "&" : "?"}${scope}` : base + path;
4572
+ }
4643
4573
  function trimSlash(s) {
4644
4574
  return s.endsWith("/") ? s.slice(0, -1) : s;
4645
4575
  }
@@ -4737,7 +4667,6 @@ function makeRequest2(overrides2 = {}) {
4737
4667
  prompt: "hi there",
4738
4668
  content: [{ type: "text", text: "hi there" }],
4739
4669
  config: { model: "deepseek/deepseek-chat" },
4740
- policy: COMPANION_POLICY,
4741
4670
  session: null,
4742
4671
  cabane: { mcpUrl: "https://cabane.test/api/mcp", bearer: "tok", activeConversationId: "conv" },
4743
4672
  local: { cwd: DIR },
@@ -4745,7 +4674,7 @@ function makeRequest2(overrides2 = {}) {
4745
4674
  ...overrides2
4746
4675
  };
4747
4676
  }
4748
- var ABORT_SENTINEL2, NEW_SESSION_ID, BOUNDED_NOTICE, COMPANION_POLICY, DIR, textPart, reasoningPart, toolPart, messageUpdated, echoedUserPart, idle, errored, sessionEvent2, OPENCODE_CONFORMANCE_FIXTURES;
4677
+ var ABORT_SENTINEL2, NEW_SESSION_ID, BOUNDED_NOTICE, DIR, textPart, reasoningPart, toolPart, messageUpdated, echoedUserPart, idle, errored, sessionEvent2, OPENCODE_CONFORMANCE_FIXTURES;
4749
4678
  var init_conformance3 = __esm({
4750
4679
  "packages/agent-runtime/src/opencode/conformance.ts"() {
4751
4680
  "use strict";
@@ -4754,15 +4683,6 @@ var init_conformance3 = __esm({
4754
4683
  ABORT_SENTINEL2 = { __abortHere: true };
4755
4684
  NEW_SESSION_ID = "sess_new";
4756
4685
  BOUNDED_NOTICE = "You've hit your usage limit \xB7 ".padEnd(200, "x");
4757
- COMPANION_POLICY = {
4758
- hostFs: false,
4759
- web: true,
4760
- browser: true,
4761
- userMcp: true,
4762
- subagents: false,
4763
- scheduling: "never",
4764
- uiPrompts: "never"
4765
- };
4766
4686
  DIR = "/env/here";
4767
4687
  textPart = (id, text) => ({
4768
4688
  type: "message.part.updated",
@@ -5590,23 +5510,9 @@ var init_loop3 = __esm({
5590
5510
  });
5591
5511
 
5592
5512
  // packages/agent-runtime/src/codex/policy.ts
5593
- import { z as z13 } from "zod";
5594
- function codexToolPolicy(policy) {
5595
- return policy.hostFs ? {
5596
- sandboxMode: "danger-full-access",
5597
- // Headless: nothing to approve, because nothing is denied.
5598
- approvalPolicy: "never",
5599
- // Full access means the command network is open regardless of the grant —
5600
- // recorded as `true` so the value never claims a restriction that isn't
5601
- // enforced.
5602
- networkAccessEnabled: true
5603
- } : {
5604
- sandboxMode: "read-only",
5605
- // Headless: the sandbox is the boundary; never pause for a human.
5606
- approvalPolicy: "never",
5607
- // Retained in the policy value for symmetry; read-only ignores it.
5608
- networkAccessEnabled: policy.web
5609
- };
5513
+ import { z as z12 } from "zod";
5514
+ function codexSandboxMode(local) {
5515
+ return local.codex?.configSetsSandboxMode ? null : "danger-full-access";
5610
5516
  }
5611
5517
  function readCodexDialect(runtimeOptions) {
5612
5518
  const parsed = codexDialectSchema.safeParse(runtimeOptions?.["codex"] ?? {});
@@ -5617,8 +5523,8 @@ var init_policy3 = __esm({
5617
5523
  "packages/agent-runtime/src/codex/policy.ts"() {
5618
5524
  "use strict";
5619
5525
  CODEX_REASONING_EFFORTS = ["low", "medium", "high", "xhigh", "max", "ultra"];
5620
- codexDialectSchema = z13.object({
5621
- modelReasoningEffort: z13.enum(CODEX_REASONING_EFFORTS).optional()
5526
+ codexDialectSchema = z12.object({
5527
+ modelReasoningEffort: z12.enum(CODEX_REASONING_EFFORTS).optional()
5622
5528
  }).loose();
5623
5529
  }
5624
5530
  });
@@ -5638,11 +5544,10 @@ var init_model3 = __esm({
5638
5544
  });
5639
5545
 
5640
5546
  // packages/agent-runtime/src/codex/run-spec.ts
5641
- function buildRunSpec2(req, resumeThreadId, instructionsFile = null, threadStanding = null, imagePaths = []) {
5642
- const { policy, config } = req;
5547
+ function buildRunSpec2(req, resumeThreadId, threadStanding = null, imagePaths = []) {
5548
+ const { config } = req;
5643
5549
  const directory = req.local.cwd ?? "";
5644
5550
  const dialect = readCodexDialect(config.runtimeOptions);
5645
- const baseInstructionsFile = !policy.hostFs && instructionsFile ? instructionsFile : null;
5646
5551
  const model = config.model ? parseCodexModel(config.model) : null;
5647
5552
  const segments = standingSegments(req);
5648
5553
  const conversationText = segments.conversation.trim();
@@ -5652,25 +5557,24 @@ function buildRunSpec2(req, resumeThreadId, instructionsFile = null, threadStand
5652
5557
  };
5653
5558
  const resumed = resumeThreadId !== null;
5654
5559
  const held = resumed ? threadStanding : null;
5655
- const viaInput = baseInstructionsFile === null;
5656
5560
  const preamble = {
5657
- core: viaInput && (held?.core ?? null) !== fingerprints.core,
5561
+ core: (held?.core ?? null) !== fingerprints.core,
5658
5562
  // Compared both ways: a held segment that is now empty differs from it, and nothing held
5659
5563
  // equals nothing to send.
5660
- conversation: viaInput && (held?.conversation ?? null) !== fingerprints.conversation
5564
+ conversation: (held?.conversation ?? null) !== fingerprints.conversation
5661
5565
  };
5662
5566
  return {
5663
5567
  resumeThreadId,
5664
5568
  directory,
5665
5569
  model,
5666
- policy: codexToolPolicy(policy),
5570
+ sandboxMode: codexSandboxMode(req.local),
5571
+ approvalPolicy: "never",
5667
5572
  skipGitRepoCheck: true,
5668
5573
  ...dialect.modelReasoningEffort ? { modelReasoningEffort: dialect.modelReasoningEffort } : {},
5669
- baseInstructionsFile,
5670
5574
  input: withImages(buildInput(req, segments, preamble, resumed), imagePaths),
5671
5575
  preamble,
5672
5576
  fingerprints,
5673
- config: buildConfig(req, baseInstructionsFile),
5577
+ config: buildConfig(req),
5674
5578
  secretEnv: codexSecretEnv(req)
5675
5579
  };
5676
5580
  }
@@ -5713,7 +5617,7 @@ function withImages(text, imagePaths) {
5713
5617
  ...imagePaths.map((path) => ({ type: "local_image", path }))
5714
5618
  ];
5715
5619
  }
5716
- function buildConfig(req, baseInstructionsFile) {
5620
+ function buildConfig(req) {
5717
5621
  const mcp_servers = {};
5718
5622
  for (const [name, server] of Object.entries(req.local.mcpServers ?? {})) {
5719
5623
  if ("url" in server) {
@@ -5779,9 +5683,6 @@ function buildConfig(req, baseInstructionsFile) {
5779
5683
  return {
5780
5684
  mcp_servers,
5781
5685
  experimental_use_rmcp_client: true,
5782
- // The no-host-access prompt replacement — Cabane's composed prompt becomes Codex's base
5783
- // instructions, and Codex's environment preamble goes with the harness prompt it belonged to.
5784
- ...baseInstructionsFile ? { model_instructions_file: baseInstructionsFile, include_environment_context: false } : {},
5785
5686
  ...Object.keys(shellEnv).length ? { shell_environment_policy: { set: shellEnv } } : {}
5786
5687
  };
5787
5688
  }
@@ -5804,8 +5705,7 @@ var init_run_spec2 = __esm({
5804
5705
  "CABANE_PLAYGROUND_BIN",
5805
5706
  "CABANE_CONVERSATION_ID",
5806
5707
  "CABANE_AGENT_ID",
5807
- "CABANE_CONVERSATION_TITLE",
5808
- "CABANE_HOST_ACCESS"
5708
+ "CABANE_CONVERSATION_TITLE"
5809
5709
  ];
5810
5710
  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.";
5811
5711
  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.";
@@ -5884,10 +5784,10 @@ import {
5884
5784
  function buildSdkThreadOptions(spec) {
5885
5785
  return {
5886
5786
  ...spec.model ? { model: spec.model } : {},
5887
- sandboxMode: spec.policy.sandboxMode,
5787
+ ...spec.sandboxMode ? { sandboxMode: spec.sandboxMode } : {},
5888
5788
  workingDirectory: spec.directory,
5889
5789
  skipGitRepoCheck: spec.skipGitRepoCheck,
5890
- approvalPolicy: spec.policy.approvalPolicy,
5790
+ approvalPolicy: spec.approvalPolicy,
5891
5791
  ...spec.modelReasoningEffort ? { modelReasoningEffort: spec.modelReasoningEffort } : {}
5892
5792
  };
5893
5793
  }
@@ -5989,23 +5889,6 @@ function createCodexAdapter(deps = {}) {
5989
5889
  );
5990
5890
  }
5991
5891
  }
5992
- let instructions = null;
5993
- if (!req.policy.hostFs) {
5994
- if (!deps.writeInstructionsFile) {
5995
- deps.onWarn?.(
5996
- "codex adapter: no instructions-file writer wired on this host \u2014 the composed prompt rides as the input preamble, so Codex keeps its own base instructions (CT871)"
5997
- );
5998
- } else {
5999
- try {
6000
- instructions = await deps.writeInstructionsFile(req.systemPrompt);
6001
- } catch (err) {
6002
- deps.onWarn?.(
6003
- "codex adapter: failed to write the per-turn instructions file \u2014 falling back to the input preamble (CT871)",
6004
- { err: err instanceof Error ? err.message : String(err) }
6005
- );
6006
- }
6007
- }
6008
- }
6009
5892
  let images = null;
6010
5893
  try {
6011
5894
  const imageUrls = req.content.flatMap((b) => b.type === "image" ? [b.source.url] : []);
@@ -6029,13 +5912,7 @@ function createCodexAdapter(deps = {}) {
6029
5912
  }
6030
5913
  if (signal.aborted) return;
6031
5914
  }
6032
- const spec = buildRunSpec2(
6033
- req,
6034
- resumeThreadId,
6035
- instructions?.path ?? null,
6036
- threadStanding,
6037
- images?.paths ?? []
6038
- );
5915
+ const spec = buildRunSpec2(req, resumeThreadId, threadStanding, images?.paths ?? []);
6039
5916
  if (spec.model === null) {
6040
5917
  deps.onWarn?.("Codex is using its default model because no model was resolved", {
6041
5918
  model: req.config.model
@@ -6077,15 +5954,6 @@ function createCodexAdapter(deps = {}) {
6077
5954
  });
6078
5955
  }
6079
5956
  }
6080
- if (instructions) {
6081
- try {
6082
- await instructions.cleanup();
6083
- } catch (err) {
6084
- deps.onWarn?.("codex adapter: instructions-file cleanup failed (CT871)", {
6085
- err: err instanceof Error ? err.message : String(err)
6086
- });
6087
- }
6088
- }
6089
5957
  }
6090
5958
  }
6091
5959
  };
@@ -6122,7 +5990,6 @@ function makeRequest3(overrides2 = {}) {
6122
5990
  // Behavioural fixtures use the model-less token (no `resolvedModel` emitted); a dedicated capture
6123
5991
  // fixture sets a real model and effort.
6124
5992
  config: { model: null },
6125
- policy: COMPANION_POLICY2,
6126
5993
  session: null,
6127
5994
  cabane: { mcpUrl: "https://cabane.test/api/mcp", bearer: "tok", activeConversationId: "conv" },
6128
5995
  local: { cwd: DIR2 },
@@ -6130,7 +5997,7 @@ function makeRequest3(overrides2 = {}) {
6130
5997
  ...overrides2
6131
5998
  };
6132
5999
  }
6133
- var ABORT_SENTINEL3, NEW_THREAD_ID, BOUNDED_NOTICE2, COMPANION_POLICY2, DIR2, PROMPT, threadStarted, agentMessage, reasoning, toolFrame, turnCompleted, turnFailed, fatalError, errorItem, OP_SUCCESS, OP_FAILURE, startedSession, closingSession, CODEX_CONFORMANCE_FIXTURES;
6000
+ var ABORT_SENTINEL3, NEW_THREAD_ID, BOUNDED_NOTICE2, DIR2, PROMPT, threadStarted, agentMessage, reasoning, toolFrame, turnCompleted, turnFailed, fatalError, errorItem, OP_SUCCESS, OP_FAILURE, startedSession, closingSession, CODEX_CONFORMANCE_FIXTURES;
6134
6001
  var init_conformance4 = __esm({
6135
6002
  "packages/agent-runtime/src/codex/conformance.ts"() {
6136
6003
  "use strict";
@@ -6139,15 +6006,6 @@ var init_conformance4 = __esm({
6139
6006
  ABORT_SENTINEL3 = { __abortHere: true };
6140
6007
  NEW_THREAD_ID = "th_new";
6141
6008
  BOUNDED_NOTICE2 = "You've hit your usage limit \xB7 ".padEnd(200, "x");
6142
- COMPANION_POLICY2 = {
6143
- hostFs: false,
6144
- web: true,
6145
- browser: true,
6146
- userMcp: true,
6147
- subagents: false,
6148
- scheduling: "never",
6149
- uiPrompts: "never"
6150
- };
6151
6009
  DIR2 = "/env/here";
6152
6010
  PROMPT = "system";
6153
6011
  threadStarted = (threadId) => ({
@@ -7063,7 +6921,6 @@ var init_src = __esm({
7063
6921
  "packages/agent-runtime/src/index.ts"() {
7064
6922
  "use strict";
7065
6923
  init_version();
7066
- init_host_policy();
7067
6924
  init_turn_event();
7068
6925
  init_turn_diagnostics();
7069
6926
  init_turn_diagnostics_normalize();
@@ -7444,7 +7301,7 @@ var init_turn_containment = __esm({
7444
7301
  });
7445
7302
 
7446
7303
  // src/run-config.ts
7447
- import { z as z14 } from "zod";
7304
+ import { z as z13 } from "zod";
7448
7305
  function parseRunConfig(raw, onWarn) {
7449
7306
  const result = runConfigSchema.safeParse(raw ?? {});
7450
7307
  if (result.success) return result.data;
@@ -7457,48 +7314,43 @@ var mcpStdioServerSchema, mcpHttpServerSchema, mcpSseServerSchema, mcpServerDefS
7457
7314
  var init_run_config = __esm({
7458
7315
  "src/run-config.ts"() {
7459
7316
  "use strict";
7460
- mcpStdioServerSchema = z14.object({
7461
- type: z14.literal("stdio").optional(),
7462
- command: z14.string().min(1),
7463
- args: z14.array(z14.string()).optional(),
7464
- env: z14.record(z14.string(), z14.string()).optional(),
7317
+ mcpStdioServerSchema = z13.object({
7318
+ type: z13.literal("stdio").optional(),
7319
+ command: z13.string().min(1),
7320
+ args: z13.array(z13.string()).optional(),
7321
+ env: z13.record(z13.string(), z13.string()).optional(),
7465
7322
  // Variable → the name of a `secretEnv` entry holding its value. Set by the server on a
7466
7323
  // room's shared browser, whose connect URL is a credential.
7467
- envFromEnv: z14.record(z14.string(), z14.string()).optional()
7324
+ envFromEnv: z13.record(z13.string(), z13.string()).optional()
7468
7325
  });
7469
- mcpHttpServerSchema = z14.object({
7470
- type: z14.literal("http"),
7471
- url: z14.string().url(),
7472
- headers: z14.record(z14.string(), z14.string()).optional(),
7326
+ mcpHttpServerSchema = z13.object({
7327
+ type: z13.literal("http"),
7328
+ url: z13.string().url(),
7329
+ headers: z13.record(z13.string(), z13.string()).optional(),
7473
7330
  // Header → the name of a `secretEnv` entry holding its value. Set by
7474
7331
  // the server on a room connection's entry, and by `resolveMcpSecrets` on a
7475
7332
  // header whose `${VAR}` it resolved.
7476
- headersFromEnv: z14.record(z14.string(), z14.string()).optional()
7333
+ headersFromEnv: z13.record(z13.string(), z13.string()).optional()
7477
7334
  });
7478
- mcpSseServerSchema = z14.object({
7479
- type: z14.literal("sse"),
7480
- url: z14.string().url(),
7481
- headers: z14.record(z14.string(), z14.string()).optional(),
7335
+ mcpSseServerSchema = z13.object({
7336
+ type: z13.literal("sse"),
7337
+ url: z13.string().url(),
7338
+ headers: z13.record(z13.string(), z13.string()).optional(),
7482
7339
  // Header → the name of a `secretEnv` entry holding its value. Set by
7483
7340
  // the server on a room connection's entry, and by `resolveMcpSecrets` on a
7484
7341
  // header whose `${VAR}` it resolved.
7485
- headersFromEnv: z14.record(z14.string(), z14.string()).optional()
7342
+ headersFromEnv: z13.record(z13.string(), z13.string()).optional()
7486
7343
  });
7487
- mcpServerDefSchema = z14.union([mcpHttpServerSchema, mcpSseServerSchema, mcpStdioServerSchema]);
7488
- thinkingConfigSchema = z14.discriminatedUnion("type", [
7489
- z14.object({ type: z14.literal("adaptive") }),
7490
- z14.object({ type: z14.literal("enabled"), budgetTokens: z14.number().int().positive().optional() }),
7491
- z14.object({ type: z14.literal("disabled") })
7344
+ mcpServerDefSchema = z13.union([mcpHttpServerSchema, mcpSseServerSchema, mcpStdioServerSchema]);
7345
+ thinkingConfigSchema = z13.discriminatedUnion("type", [
7346
+ z13.object({ type: z13.literal("adaptive") }),
7347
+ z13.object({ type: z13.literal("enabled"), budgetTokens: z13.number().int().positive().optional() }),
7348
+ z13.object({ type: z13.literal("disabled") })
7492
7349
  ]);
7493
- effortSchema = z14.enum(["low", "medium", "high", "xhigh", "max"]);
7494
- runConfigSchema = z14.object({
7495
- // `true` grants the host filesystem/shell; absent is the locked surface. Kept
7496
- // in lockstep with `@cabane/shared`'s
7497
- // `agentRunConfigSchema` (independent zod, forward-compatible: unknown keys are
7498
- // stripped, so an older companion riding a newer server never rejects the config).
7499
- hostAccess: z14.boolean().optional(),
7500
- mcpServers: z14.record(z14.string(), mcpServerDefSchema).optional(),
7501
- model: z14.string().min(1).optional(),
7350
+ effortSchema = z13.enum(["low", "medium", "high", "xhigh", "max"]);
7351
+ runConfigSchema = z13.object({
7352
+ mcpServers: z13.record(z13.string(), mcpServerDefSchema).optional(),
7353
+ model: z13.string().min(1).optional(),
7502
7354
  thinking: thinkingConfigSchema.optional(),
7503
7355
  effort: effortSchema.optional()
7504
7356
  });
@@ -7507,7 +7359,7 @@ var init_run_config = __esm({
7507
7359
  });
7508
7360
 
7509
7361
  // src/runner/protocol.ts
7510
- import { z as z15 } from "zod";
7362
+ import { z as z14 } from "zod";
7511
7363
  function required(env, name) {
7512
7364
  const value = env[name];
7513
7365
  if (!value) throw new Error(`runner: ${name} is not set`);
@@ -7585,56 +7437,56 @@ var init_protocol = __esm({
7585
7437
  // Everything else the turn is constructed from, as JSON: see `RunnerSpec`.
7586
7438
  spec: "CABANE_RUNNER_SPEC"
7587
7439
  };
7588
- runtimeHealthSchema = z15.object({
7589
- quotaState: z15.enum(["ok", "limited", "auth_expired", "unknown"]),
7590
- limitedUntil: z15.string().nullable(),
7591
- lastError: z15.string().nullable()
7440
+ runtimeHealthSchema = z14.object({
7441
+ quotaState: z14.enum(["ok", "limited", "auth_expired", "unknown"]),
7442
+ limitedUntil: z14.string().nullable(),
7443
+ lastError: z14.string().nullable()
7592
7444
  });
7593
- runnerSpecSchema = z15.object({
7594
- deviceId: z15.string().optional(),
7445
+ runnerSpecSchema = z14.object({
7446
+ deviceId: z14.string().optional(),
7595
7447
  // The launcher's boot id: the one its heartbeat carries, so a runner's lease
7596
7448
  // matches the device that holds it.
7597
- bootId: z15.string(),
7598
- workspaceId: z15.string(),
7599
- workspaceSlug: z15.string(),
7600
- agentId: z15.string(),
7601
- agentUsername: z15.string(),
7602
- agentName: z15.string(),
7449
+ bootId: z14.string(),
7450
+ workspaceId: z14.string(),
7451
+ workspaceSlug: z14.string(),
7452
+ agentId: z14.string(),
7453
+ agentUsername: z14.string(),
7454
+ agentName: z14.string(),
7603
7455
  local: localAgentConfigSchema,
7604
7456
  runConfig: runConfigSchema,
7605
7457
  // The device's `root`, resolved by the launcher: the pair directory the turn
7606
7458
  // stands in when nothing else names one lives under it (`work-dir.ts`).
7607
- workRoot: z15.string(),
7608
- opencodeServerUrl: z15.string().optional(),
7609
- claudeCodeAvailable: z15.boolean(),
7610
- codexAvailable: z15.boolean(),
7611
- idleTimeoutMs: z15.number().int().positive().optional(),
7612
- totalTimeoutMs: z15.number().int().positive().optional(),
7613
- leaseRenewalMs: z15.number().int().positive().optional(),
7614
- preparingRowDelayMs: z15.number().int().nonnegative().optional(),
7459
+ workRoot: z14.string(),
7460
+ opencodeServerUrl: z14.string().optional(),
7461
+ claudeCodeAvailable: z14.boolean(),
7462
+ codexAvailable: z14.boolean(),
7463
+ idleTimeoutMs: z14.number().int().positive().optional(),
7464
+ totalTimeoutMs: z14.number().int().positive().optional(),
7465
+ leaseRenewalMs: z14.number().int().positive().optional(),
7466
+ preparingRowDelayMs: z14.number().int().nonnegative().optional(),
7615
7467
  // Whether the turn writes a transcript, into the device's own directory
7616
7468
  // (`transcriptsDir()`).
7617
- transcripts: z15.boolean(),
7618
- logLevel: z15.string(),
7469
+ transcripts: z14.boolean(),
7470
+ logLevel: z14.string(),
7619
7471
  // The launcher's connector-health observations, by runtime, as of the start.
7620
- connectorHealth: z15.record(z15.string(), runtimeHealthSchema),
7472
+ connectorHealth: z14.record(z14.string(), runtimeHealthSchema),
7621
7473
  // True when this (conversation, agent) pair was already told its session
7622
7474
  // could not be saved: the notice is once per pair, not once per process.
7623
- sessionWriteNoticeClaimed: z15.boolean(),
7475
+ sessionWriteNoticeClaimed: z14.boolean(),
7624
7476
  // The runner's identity, minted with its credential. The start
7625
7477
  // PATCH carries it so the lease knows which runner holds the span.
7626
- runnerId: z15.string()
7478
+ runnerId: z14.string()
7627
7479
  });
7628
- dispatchSchema = z15.object({
7629
- type: z15.literal("device:dispatch_requested"),
7630
- agentId: z15.string(),
7631
- deviceId: z15.string(),
7632
- conversationId: z15.string(),
7633
- messageId: z15.string(),
7634
- episode: z15.number().int().optional()
7480
+ dispatchSchema = z14.object({
7481
+ type: z14.literal("device:dispatch_requested"),
7482
+ agentId: z14.string(),
7483
+ deviceId: z14.string(),
7484
+ conversationId: z14.string(),
7485
+ messageId: z14.string(),
7486
+ episode: z14.number().int().optional()
7635
7487
  });
7636
- credentialsSchema = z15.object({
7637
- credential: z15.string().startsWith("cabrn_")
7488
+ credentialsSchema = z14.object({
7489
+ credential: z14.string().startsWith("cabrn_")
7638
7490
  });
7639
7491
  }
7640
7492
  });
@@ -8030,7 +7882,7 @@ var init_work_dir = __esm({
8030
7882
 
8031
7883
  // src/turn-control-tools.ts
8032
7884
  import { randomUUID as randomUUID2 } from "crypto";
8033
- import { z as z16 } from "zod";
7885
+ import { z as z15 } from "zod";
8034
7886
  function createSkipState() {
8035
7887
  return { skipped: false, reason: null };
8036
7888
  }
@@ -8081,7 +7933,7 @@ function createTurnControlMcpServer(acts, skipState) {
8081
7933
  SKIP_TURN_TOOL,
8082
7934
  TURN_CONTROL_TOOL_DESCRIPTIONS.skip_turn,
8083
7935
  {
8084
- reason: z16.string().min(1).max(MAX_SKIP_REASON_BYTES).describe(TURN_CONTROL_FIELD_DESCRIPTIONS.skip_turn.reason)
7936
+ reason: z15.string().min(1).max(MAX_SKIP_REASON_BYTES).describe(TURN_CONTROL_FIELD_DESCRIPTIONS.skip_turn.reason)
8085
7937
  },
8086
7938
  async (args) => {
8087
7939
  skipState.skipped = true;
@@ -8097,22 +7949,22 @@ function createTurnControlMcpServer(acts, skipState) {
8097
7949
  ASK_TOOL,
8098
7950
  TURN_CONTROL_TOOL_DESCRIPTIONS.ask,
8099
7951
  {
8100
- targetUserId: z16.string().regex(ASK_TARGET_PATTERN, { error: ASK_TARGET_INVALID }).describe(TURN_CONTROL_FIELD_DESCRIPTIONS.ask.targetUserId),
8101
- question: z16.string().min(1).max(MAX_ASK_QUESTION_BYTES).optional().describe(TURN_CONTROL_FIELD_DESCRIPTIONS.ask.question),
8102
- headline: z16.string().min(1).max(MAX_ASK_HEADLINE_BYTES).optional().describe(TURN_CONTROL_FIELD_DESCRIPTIONS.ask.headline),
8103
- options: z16.array(z16.string({ error: ASK_OPTION_NOT_A_STRING }).min(1).max(MAX_ASK_OPTION_BYTES)).min(MIN_ASK_OPTIONS).max(MAX_ASK_OPTIONS).optional().describe(TURN_CONTROL_FIELD_DESCRIPTIONS.ask.options),
8104
- questions: z16.array(
8105
- z16.object({
8106
- headline: z16.string().min(1).max(MAX_ASK_HEADLINE_BYTES).describe(TURN_CONTROL_FIELD_DESCRIPTIONS.ask["questions.headline"]),
8107
- body: z16.string().min(1).max(MAX_ASK_QUESTION_BYTES).optional().describe(TURN_CONTROL_FIELD_DESCRIPTIONS.ask["questions.body"]),
8108
- options: z16.array(
8109
- z16.string({ error: ASK_OPTION_NOT_A_STRING }).min(1).max(MAX_ASK_OPTION_BYTES)
7952
+ targetUserId: z15.string().regex(ASK_TARGET_PATTERN, { error: ASK_TARGET_INVALID }).describe(TURN_CONTROL_FIELD_DESCRIPTIONS.ask.targetUserId),
7953
+ question: z15.string().min(1).max(MAX_ASK_QUESTION_BYTES).optional().describe(TURN_CONTROL_FIELD_DESCRIPTIONS.ask.question),
7954
+ headline: z15.string().min(1).max(MAX_ASK_HEADLINE_BYTES).optional().describe(TURN_CONTROL_FIELD_DESCRIPTIONS.ask.headline),
7955
+ options: z15.array(z15.string({ error: ASK_OPTION_NOT_A_STRING }).min(1).max(MAX_ASK_OPTION_BYTES)).min(MIN_ASK_OPTIONS).max(MAX_ASK_OPTIONS).optional().describe(TURN_CONTROL_FIELD_DESCRIPTIONS.ask.options),
7956
+ questions: z15.array(
7957
+ z15.object({
7958
+ headline: z15.string().min(1).max(MAX_ASK_HEADLINE_BYTES).describe(TURN_CONTROL_FIELD_DESCRIPTIONS.ask["questions.headline"]),
7959
+ body: z15.string().min(1).max(MAX_ASK_QUESTION_BYTES).optional().describe(TURN_CONTROL_FIELD_DESCRIPTIONS.ask["questions.body"]),
7960
+ options: z15.array(
7961
+ z15.string({ error: ASK_OPTION_NOT_A_STRING }).min(1).max(MAX_ASK_OPTION_BYTES)
8110
7962
  ).min(MIN_ASK_OPTIONS).max(MAX_ASK_OPTIONS).optional().describe(TURN_CONTROL_FIELD_DESCRIPTIONS.ask["questions.options"])
8111
7963
  })
8112
7964
  ).min(1).max(MAX_ASK_ITEMS).optional().describe(TURN_CONTROL_FIELD_DESCRIPTIONS.ask.questions),
8113
- replaces: z16.object({
8114
- askId: z16.string().uuid().describe(TURN_CONTROL_FIELD_DESCRIPTIONS.ask["replaces.askId"]),
8115
- reason: z16.string().min(1).max(MAX_WITHDRAW_REASON_BYTES).describe(TURN_CONTROL_FIELD_DESCRIPTIONS.ask["replaces.reason"])
7965
+ replaces: z15.object({
7966
+ askId: z15.string().uuid().describe(TURN_CONTROL_FIELD_DESCRIPTIONS.ask["replaces.askId"]),
7967
+ reason: z15.string().min(1).max(MAX_WITHDRAW_REASON_BYTES).describe(TURN_CONTROL_FIELD_DESCRIPTIONS.ask["replaces.reason"])
8116
7968
  }).optional().describe(TURN_CONTROL_FIELD_DESCRIPTIONS.ask.replaces)
8117
7969
  },
8118
7970
  async (args) => {
@@ -8153,9 +8005,9 @@ function createTurnControlMcpServer(acts, skipState) {
8153
8005
  WAKE_ME_TOOL,
8154
8006
  TURN_CONTROL_TOOL_DESCRIPTIONS.wake_me,
8155
8007
  {
8156
- afterSeconds: z16.number().int().positive().optional().describe(TURN_CONTROL_FIELD_DESCRIPTIONS.wake_me.afterSeconds),
8157
- at: z16.string().datetime({ offset: true }).optional().describe(TURN_CONTROL_FIELD_DESCRIPTIONS.wake_me.at),
8158
- note: z16.string().min(1).max(MAX_WAKE_NOTE_BYTES).describe(TURN_CONTROL_FIELD_DESCRIPTIONS.wake_me.note)
8008
+ afterSeconds: z15.number().int().positive().optional().describe(TURN_CONTROL_FIELD_DESCRIPTIONS.wake_me.afterSeconds),
8009
+ at: z15.string().datetime({ offset: true }).optional().describe(TURN_CONTROL_FIELD_DESCRIPTIONS.wake_me.at),
8010
+ note: z15.string().min(1).max(MAX_WAKE_NOTE_BYTES).describe(TURN_CONTROL_FIELD_DESCRIPTIONS.wake_me.note)
8159
8011
  },
8160
8012
  async (args) => {
8161
8013
  const hasAfter = args.afterSeconds !== void 0;
@@ -8189,8 +8041,8 @@ function createTurnControlMcpServer(acts, skipState) {
8189
8041
  WITHDRAW_ASK_TOOL,
8190
8042
  TURN_CONTROL_TOOL_DESCRIPTIONS.withdraw_ask,
8191
8043
  {
8192
- askId: z16.string().uuid().describe(TURN_CONTROL_FIELD_DESCRIPTIONS.withdraw_ask.askId),
8193
- reason: z16.string().min(1).max(MAX_WITHDRAW_REASON_BYTES).describe(TURN_CONTROL_FIELD_DESCRIPTIONS.withdraw_ask.reason)
8044
+ askId: z15.string().uuid().describe(TURN_CONTROL_FIELD_DESCRIPTIONS.withdraw_ask.askId),
8045
+ reason: z15.string().min(1).max(MAX_WITHDRAW_REASON_BYTES).describe(TURN_CONTROL_FIELD_DESCRIPTIONS.withdraw_ask.reason)
8194
8046
  },
8195
8047
  async (args) => performAct(acts, {
8196
8048
  kind: "withdraw_ask",
@@ -8249,7 +8101,6 @@ function buildCompanionTurnRequest(params) {
8249
8101
  prompt: t.prompt,
8250
8102
  content: t.content,
8251
8103
  config: t.config,
8252
- policy: t.policy,
8253
8104
  session: t.session,
8254
8105
  cabane: {
8255
8106
  mcpUrl: cabaneMcpUrl(params.baseUrl),
@@ -8266,7 +8117,9 @@ function buildCompanionTurnRequest(params) {
8266
8117
  ...Object.keys(params.mcpServers).length > 0 ? { mcpServers: params.mcpServers } : {},
8267
8118
  ...params.secretEnv && Object.keys(params.secretEnv).length > 0 ? { secretEnv: params.secretEnv } : {},
8268
8119
  // The auto-memory escape hatch, when the operator set it.
8269
- ...params.claudeCode ? { claudeCode: params.claudeCode } : {}
8120
+ ...params.claudeCode ? { claudeCode: params.claudeCode } : {},
8121
+ // Whether the person's Codex config sets its own sandbox mode.
8122
+ ...params.codex ? { codex: params.codex } : {}
8270
8123
  },
8271
8124
  // Host-injected turn-control tools, under their own namespace.
8272
8125
  extra: {
@@ -8284,42 +8137,49 @@ var init_build_options = __esm({
8284
8137
  }
8285
8138
  });
8286
8139
 
8287
- // src/codex-instructions.ts
8288
- import { mkdtemp, rm, writeFile } from "fs/promises";
8289
- import { tmpdir } from "os";
8140
+ // src/codex-config.ts
8141
+ import { readFile as readFile2 } from "fs/promises";
8142
+ import { homedir as homedir7 } from "os";
8290
8143
  import { join as join15 } from "path";
8291
- async function writeCodexInstructionsFile(contents) {
8292
- const dir2 = await mkdtemp(join15(tmpdir(), PREFIX));
8293
- const path = join15(dir2, "instructions.md");
8294
- await writeFile(path, contents, { encoding: "utf8", mode: 384 });
8295
- return {
8296
- path,
8297
- cleanup: async () => {
8298
- await rm(dir2, { recursive: true, force: true });
8299
- }
8300
- };
8144
+ import { parse } from "smol-toml";
8145
+ function codexConfigPath(env = process.env, home = homedir7()) {
8146
+ return join15(env.CODEX_HOME || join15(home, ".codex"), "config.toml");
8147
+ }
8148
+ async function readCodexConfigSetsSandboxMode(path = codexConfigPath()) {
8149
+ let text;
8150
+ try {
8151
+ text = await readFile2(path, "utf8");
8152
+ } catch {
8153
+ return false;
8154
+ }
8155
+ return configSetsSandboxMode(text);
8156
+ }
8157
+ function configSetsSandboxMode(text) {
8158
+ try {
8159
+ return parse(text).sandbox_mode !== void 0;
8160
+ } catch {
8161
+ return false;
8162
+ }
8301
8163
  }
8302
- var PREFIX;
8303
- var init_codex_instructions = __esm({
8304
- "src/codex-instructions.ts"() {
8164
+ var init_codex_config = __esm({
8165
+ "src/codex-config.ts"() {
8305
8166
  "use strict";
8306
- PREFIX = "cabane-codex-instructions-";
8307
8167
  }
8308
8168
  });
8309
8169
 
8310
8170
  // src/codex-images.ts
8311
- import { mkdtemp as mkdtemp2, rm as rm2, writeFile as writeFile2 } from "fs/promises";
8312
- import { tmpdir as tmpdir2 } from "os";
8171
+ import { mkdtemp, rm, writeFile } from "fs/promises";
8172
+ import { tmpdir } from "os";
8313
8173
  import { join as join16 } from "path";
8314
8174
  function createCodexImagePreparer(opts) {
8315
8175
  const doFetch = opts.fetch ?? fetch;
8316
8176
  const timeoutMs = opts.timeoutMs ?? FETCH_TIMEOUT_MS;
8317
8177
  return async (urls, signal) => {
8318
8178
  signal.throwIfAborted();
8319
- const dir2 = await mkdtemp2(join16(tmpdir2(), `cabane-codex-images-${opts.turnId}-`));
8179
+ const dir2 = await mkdtemp(join16(tmpdir(), `cabane-codex-images-${opts.turnId}-`));
8320
8180
  const cleanup = async () => {
8321
8181
  try {
8322
- await rm2(dir2, { recursive: true, force: true });
8182
+ await rm(dir2, { recursive: true, force: true });
8323
8183
  } catch (err) {
8324
8184
  opts.warn(
8325
8185
  { dir: dir2, err: message(err) },
@@ -8338,7 +8198,7 @@ function createCodexImagePreparer(opts) {
8338
8198
  if (!ext) throw new Error(`not a vision image type: ${type || "none"}`);
8339
8199
  const bytes = new Uint8Array(await res.arrayBuffer());
8340
8200
  const path = join16(dir2, `image-${index + 1}.${ext}`);
8341
- await writeFile2(path, bytes, { mode: 384 });
8201
+ await writeFile(path, bytes, { mode: 384 });
8342
8202
  return path;
8343
8203
  } catch (err) {
8344
8204
  if (!signal.aborted) {
@@ -8378,10 +8238,10 @@ var init_codex_images = __esm({
8378
8238
  // src/codex-compactions.ts
8379
8239
  import { createReadStream } from "fs";
8380
8240
  import { readdir } from "fs/promises";
8381
- import { homedir as homedir7 } from "os";
8241
+ import { homedir as homedir8 } from "os";
8382
8242
  import { join as join17 } from "path";
8383
8243
  import { createInterface as createInterface2 } from "readline";
8384
- function createCodexCompactionCounter(codexHome = process.env.CODEX_HOME || join17(homedir7(), ".codex")) {
8244
+ function createCodexCompactionCounter(codexHome = process.env.CODEX_HOME || join17(homedir8(), ".codex")) {
8385
8245
  return async (threadId) => {
8386
8246
  try {
8387
8247
  const rollout = await findRollout(codexHome, threadId);
@@ -8592,7 +8452,7 @@ var init_prepared = __esm({
8592
8452
  // src/secrets.ts
8593
8453
  import { existsSync as existsSync10, readFileSync as readFileSync8 } from "fs";
8594
8454
  import { join as join19 } from "path";
8595
- import { z as z17 } from "zod";
8455
+ import { z as z16 } from "zod";
8596
8456
  function secretsPath() {
8597
8457
  return join19(cabaneDir(), "secrets.json");
8598
8458
  }
@@ -8716,7 +8576,7 @@ var init_secrets = __esm({
8716
8576
  init_config();
8717
8577
  init_errors();
8718
8578
  PLACEHOLDER_RE = /\$\{([A-Za-z_][A-Za-z0-9_]*)\}/g;
8719
- secretStoreSchema = z17.record(z17.string(), z17.string());
8579
+ secretStoreSchema = z16.record(z16.string(), z16.string());
8720
8580
  SECRET_ENV_NAME = /^CABANE_MCP_(\d+)$/;
8721
8581
  }
8722
8582
  });
@@ -9100,7 +8960,7 @@ var init_turn_execution = __esm({
9100
8960
  init_work_dir();
9101
8961
  init_build_options();
9102
8962
  init_bundled_binaries();
9103
- init_codex_instructions();
8963
+ init_codex_config();
9104
8964
  init_codex_images();
9105
8965
  init_codex_compactions();
9106
8966
  init_config();
@@ -9181,6 +9041,7 @@ var init_turn_execution = __esm({
9181
9041
  effectiveCwd;
9182
9042
  hookEnv;
9183
9043
  turnEnv;
9044
+ codexLocal;
9184
9045
  skipState;
9185
9046
  turnControlServer;
9186
9047
  request;
@@ -9522,7 +9383,6 @@ var init_turn_execution = __esm({
9522
9383
  agentUsername: this.opts.agentUsername,
9523
9384
  defaultCwd: pairDir,
9524
9385
  runtime: this.turnContext.runtime,
9525
- hostAccess: this.turnContext.policy.hostFs,
9526
9386
  triggerEntryPaths: this.turnContext.conversation.triggerEntryPaths ?? [],
9527
9387
  title: this.turnContext.conversation.title,
9528
9388
  messageBody: this.turnContext.message.body,
@@ -9585,7 +9445,6 @@ var init_turn_execution = __esm({
9585
9445
  // wants to add to it.
9586
9446
  defaultCwd: pairDir,
9587
9447
  runtime: this.turnContext.runtime,
9588
- hostAccess: this.turnContext.policy.hostFs,
9589
9448
  // The trigger message's referenced-entry paths, which a prepare hook
9590
9449
  // may key its per-task env off. `[]` from an older API.
9591
9450
  triggerEntryPaths: this.turnContext.conversation.triggerEntryPaths ?? [],
@@ -9618,9 +9477,9 @@ var init_turn_execution = __esm({
9618
9477
  }
9619
9478
  const turnEnv = {
9620
9479
  ...hookEnv,
9621
- CABANE_HOST_ACCESS: this.turnContext.policy.hostFs ? "1" : "0",
9622
9480
  CABANE_COMPANION_HOME: agentCompanionHome()
9623
9481
  };
9482
+ this.codexLocal = this.turnContext.runtime === "codex" ? { configSetsSandboxMode: await readCodexConfigSetsSandboxMode() } : void 0;
9624
9483
  this.effectiveCwd = effectiveCwd;
9625
9484
  this.hookEnv = hookEnv;
9626
9485
  this.turnEnv = turnEnv;
@@ -9705,7 +9564,8 @@ var init_turn_execution = __esm({
9705
9564
  activeConversationId: payload.conversationId,
9706
9565
  workspaceId,
9707
9566
  // The operator's machine-local auto-memory escape hatch, when set.
9708
- ...this.opts.local.claudeCode ? { claudeCode: this.opts.local.claudeCode } : {}
9567
+ ...this.opts.local.claudeCode ? { claudeCode: this.opts.local.claudeCode } : {},
9568
+ ...this.codexLocal ? { codex: this.codexLocal } : {}
9709
9569
  });
9710
9570
  }
9711
9571
  integrityContext() {
@@ -9772,7 +9632,6 @@ var init_turn_execution = __esm({
9772
9632
  createCodexAdapter({
9773
9633
  enabled: true,
9774
9634
  onWarn,
9775
- writeInstructionsFile: writeCodexInstructionsFile,
9776
9635
  prepareImages: createCodexImagePreparer({
9777
9636
  turnId: this.turnId,
9778
9637
  warn: (meta, msg) => turnLog.warn(meta, msg)
@@ -12182,7 +12041,6 @@ var CompanionStateHub = class {
12182
12041
  agent_id: a.agentId,
12183
12042
  username: a.username,
12184
12043
  display_name: a.displayName,
12185
- mode: a.mode,
12186
12044
  has_credential: a.hasCredential,
12187
12045
  missing_secrets: a.missingSecrets
12188
12046
  }))
@@ -13088,7 +12946,7 @@ init_launch();
13088
12946
  // src/manifest.ts
13089
12947
  var DEVICE_MANIFEST = {
13090
12948
  runtimes: [{ name: "claude-code", version: null }],
13091
- capabilities: { hostFs: true, browser: true, userMcp: true }
12949
+ capabilities: { browser: true, userMcp: true }
13092
12950
  };
13093
12951
  function buildCompanionManifest(opts) {
13094
12952
  const v = opts.versions ?? {};
@@ -13448,27 +13306,27 @@ function compareVersions(a, b) {
13448
13306
  init_config();
13449
13307
  import { mkdirSync as mkdirSync13, readFileSync as readFileSync13, renameSync as renameSync8, writeFileSync as writeFileSync8 } from "fs";
13450
13308
  import { dirname as dirname10, join as join25 } from "path";
13451
- import { z as z18 } from "zod";
13452
- var resultSchema = z18.object({
13453
- kind: z18.enum(["updated", "rolled_back", "failed"]),
13454
- from: z18.string(),
13455
- to: z18.string(),
13456
- at: z18.string(),
13457
- reason: z18.string().optional()
13309
+ import { z as z17 } from "zod";
13310
+ var resultSchema = z17.object({
13311
+ kind: z17.enum(["updated", "rolled_back", "failed"]),
13312
+ from: z17.string(),
13313
+ to: z17.string(),
13314
+ at: z17.string(),
13315
+ reason: z17.string().optional()
13458
13316
  });
13459
- var pendingSchema = z18.object({
13460
- from: z18.string(),
13317
+ var pendingSchema = z17.object({
13318
+ from: z17.string(),
13461
13319
  // The package root `current` pointed at before the swap, so a rollback can point it back.
13462
- fromRoot: z18.string(),
13463
- to: z18.string(),
13464
- at: z18.string(),
13465
- boots: z18.number().int().nonnegative()
13320
+ fromRoot: z17.string(),
13321
+ to: z17.string(),
13322
+ at: z17.string(),
13323
+ boots: z17.number().int().nonnegative()
13466
13324
  });
13467
- var stateSchema = z18.object({
13468
- server: z18.object({ latest: z18.string(), minimum: z18.string(), at: z18.string() }).optional(),
13325
+ var stateSchema = z17.object({
13326
+ server: z17.object({ latest: z17.string(), minimum: z17.string(), at: z17.string() }).optional(),
13469
13327
  pending: pendingSchema.optional(),
13470
13328
  lastResult: resultSchema.optional(),
13471
- failed: z18.object({ version: z18.string(), attempts: z18.number().int(), at: z18.string() }).optional()
13329
+ failed: z17.object({ version: z17.string(), attempts: z17.number().int(), at: z17.string() }).optional()
13472
13330
  });
13473
13331
  function updateStatePath(dir2 = cabaneDir()) {
13474
13332
  return join25(dir2, "update.json");
@@ -14365,7 +14223,6 @@ var CompanionSupervisor = class {
14365
14223
  agentId: it.agentId,
14366
14224
  username: it.agentUsername,
14367
14225
  displayName: it.agentDisplayName,
14368
- mode: runConfig.hostAccess ? "full" : "none",
14369
14226
  hasCredential: false,
14370
14227
  missingSecrets: missing
14371
14228
  });
@@ -14385,7 +14242,6 @@ var CompanionSupervisor = class {
14385
14242
  agentId: it.agentId,
14386
14243
  username: it.agentUsername,
14387
14244
  displayName: it.agentDisplayName,
14388
- mode: runConfig.hostAccess ? "full" : "none",
14389
14245
  hasCredential: true,
14390
14246
  missingSecrets: missing
14391
14247
  });
@@ -15571,7 +15427,7 @@ import {
15571
15427
  rmSync as rmSync12,
15572
15428
  writeFileSync as writeFileSync10
15573
15429
  } from "fs";
15574
- import { homedir as homedir8, userInfo as userInfo3 } from "os";
15430
+ import { homedir as homedir9, userInfo as userInfo3 } from "os";
15575
15431
  import { dirname as dirname12, join as join29, sep as sep3 } from "path";
15576
15432
  function servicePlatform(platform = process.platform) {
15577
15433
  if (platform === "linux") return "systemd";
@@ -15589,7 +15445,7 @@ function launchdLabel(env = process.env) {
15589
15445
  function serviceNode(execPath = process.execPath) {
15590
15446
  return existsSync17(pinnedNodePath()) ? pinnedNodePath() : execPath;
15591
15447
  }
15592
- function servicePaths(platform, env = process.env, home = homedir8(), node = serviceNode()) {
15448
+ function servicePaths(platform, env = process.env, home = homedir9(), node = serviceNode()) {
15593
15449
  const unitFile = platform === "systemd" ? join29(
15594
15450
  env.XDG_CONFIG_HOME || join29(home, ".config"),
15595
15451
  "systemd",
@@ -15831,7 +15687,7 @@ async function seedManagedInstall(deps) {
15831
15687
  return { ok: true, root: target };
15832
15688
  }
15833
15689
  function tildeDir() {
15834
- return cabaneDir().replace(homedir8(), "~");
15690
+ return cabaneDir().replace(homedir9(), "~");
15835
15691
  }
15836
15692
  function unitNode(platform, unitFile) {
15837
15693
  let text;
@@ -16610,7 +16466,7 @@ init_cabane_command();
16610
16466
  init_install_kind();
16611
16467
  init_cabane_command();
16612
16468
  import { readdirSync as readdirSync5, realpathSync as realpathSync6, existsSync as existsSync18 } from "fs";
16613
- import { homedir as homedir9 } from "os";
16469
+ import { homedir as homedir10 } from "os";
16614
16470
  import { dirname as dirname13, join as join30 } from "path";
16615
16471
  init_config();
16616
16472
  init_secrets();
@@ -16895,7 +16751,7 @@ function versionLine() {
16895
16751
  const install = companionInstall();
16896
16752
  const own = installedCommandPath({ install });
16897
16753
  if (install === "script") {
16898
- return `Cabane ${COMPANION_VERSION} \xB7 installed by the install script (${tildePath(join30(homedir9(), ".cabane"))})`;
16754
+ return `Cabane ${COMPANION_VERSION} \xB7 installed by the install script (${tildePath(join30(homedir10(), ".cabane"))})`;
16899
16755
  }
16900
16756
  if (own)
16901
16757
  return `Cabane ${COMPANION_VERSION} \xB7 installed with npm (${tildePath(dirname13(dirname13(own)))})`;
@@ -16922,7 +16778,7 @@ function otherInstall(install, own) {
16922
16778
  };
16923
16779
  if (install === "npm") {
16924
16780
  const script = join30(
16925
- homedir9(),
16781
+ homedir10(),
16926
16782
  ".cabane",
16927
16783
  "node",
16928
16784
  "lib",
@@ -16930,7 +16786,7 @@ function otherInstall(install, own) {
16930
16786
  "@cabane",
16931
16787
  "companion"
16932
16788
  );
16933
- return existsSync18(script) ? join30(homedir9(), ".cabane") : null;
16789
+ return existsSync18(script) ? join30(homedir10(), ".cabane") : null;
16934
16790
  }
16935
16791
  const found = firstOnPath("cabane-companion", process.env.PATH);
16936
16792
  if (!found) return null;