@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/README.md +16 -10
- package/dist/cli.js +396 -540
- package/dist/launch.js +1 -1
- package/dist/pairing-config.js +1 -1
- package/dist/runtime.js +336 -477
- package/dist/static/app.js +1 -2
- package/dist/static/styles.css +0 -7
- package/package.json +2 -1
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
|
-
// (
|
|
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
|
|
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 =
|
|
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
|
-
|
|
1776
|
-
type:
|
|
1777
|
-
state:
|
|
1778
|
-
degraded:
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
1799
|
-
type:
|
|
1800
|
-
id:
|
|
1801
|
-
name:
|
|
1802
|
-
phase:
|
|
1803
|
-
summary:
|
|
1804
|
-
input:
|
|
1805
|
-
result:
|
|
1806
|
-
mcpServer:
|
|
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
|
-
|
|
1828
|
-
type:
|
|
1829
|
-
ok:
|
|
1830
|
-
reason:
|
|
1831
|
-
usage:
|
|
1832
|
-
inputTokens:
|
|
1833
|
-
outputTokens:
|
|
1834
|
-
cacheReadTokens:
|
|
1835
|
-
cacheCreationTokens:
|
|
1836
|
-
contextTokens:
|
|
1837
|
-
contextWindow:
|
|
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:
|
|
1841
|
-
contextCategories:
|
|
1842
|
-
|
|
1843
|
-
name:
|
|
1844
|
-
tokens:
|
|
1845
|
-
kind:
|
|
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:
|
|
1849
|
-
|
|
1850
|
-
trigger:
|
|
1851
|
-
preTokens:
|
|
1852
|
-
postTokens:
|
|
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:
|
|
1857
|
-
resolvedConfig:
|
|
1858
|
-
effort:
|
|
1859
|
-
thinking:
|
|
1860
|
-
reasoningEffort:
|
|
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:
|
|
1866
|
-
initReceived:
|
|
1867
|
-
servers:
|
|
1868
|
-
toolCount:
|
|
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
|
|
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 =
|
|
1882
|
-
|
|
1883
|
-
|
|
1884
|
-
|
|
1885
|
-
|
|
1886
|
-
|
|
1887
|
-
|
|
1888
|
-
|
|
1889
|
-
|
|
1890
|
-
|
|
1891
|
-
|
|
1892
|
-
|
|
1893
|
-
|
|
1894
|
-
|
|
1895
|
-
|
|
1896
|
-
|
|
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 =
|
|
1909
|
-
outcome:
|
|
1875
|
+
turnDiagnosticsSchema = z7.object({
|
|
1876
|
+
outcome: z7.enum(turnOutcomes),
|
|
1910
1877
|
resultReason: turnResultReasonSchema.nullable(),
|
|
1911
|
-
sessionMode:
|
|
1912
|
-
sessionFingerprint:
|
|
1913
|
-
eventCounts:
|
|
1914
|
-
session:
|
|
1915
|
-
text:
|
|
1916
|
-
runtime_notice:
|
|
1917
|
-
thinking:
|
|
1918
|
-
tool:
|
|
1919
|
-
result:
|
|
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:
|
|
1922
|
-
finalSource:
|
|
1923
|
-
mcpInventory:
|
|
1924
|
-
initReceived:
|
|
1925
|
-
servers:
|
|
1926
|
-
toolCount:
|
|
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
|
|
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
|
-
|
|
2006
|
-
|
|
2007
|
-
|
|
2008
|
-
|
|
2009
|
-
type:
|
|
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
|
-
|
|
2013
|
-
type:
|
|
2014
|
-
source:
|
|
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 =
|
|
2018
|
-
resolvedRunConfigSchema =
|
|
2019
|
-
model:
|
|
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:
|
|
1987
|
+
runtimeOptions: z8.record(z8.string(), z8.unknown()).optional()
|
|
2022
1988
|
});
|
|
2023
|
-
resolvedMcpServerSchema =
|
|
2024
|
-
|
|
2025
|
-
type:
|
|
2026
|
-
command:
|
|
2027
|
-
args:
|
|
2028
|
-
env:
|
|
2029
|
-
envFromEnv:
|
|
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
|
-
|
|
2032
|
-
type:
|
|
2033
|
-
url:
|
|
2034
|
-
headers:
|
|
2035
|
-
headersFromEnv:
|
|
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
|
-
|
|
2038
|
-
type:
|
|
2039
|
-
url:
|
|
2040
|
-
headers:
|
|
2041
|
-
headersFromEnv:
|
|
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 =
|
|
2045
|
-
hostInjectedServersSchema =
|
|
2046
|
-
turnRequestSchema =
|
|
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:
|
|
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:
|
|
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:
|
|
2023
|
+
prompt: z8.string(),
|
|
2058
2024
|
// The multi-block user-message body (text + vision).
|
|
2059
|
-
content:
|
|
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:
|
|
2029
|
+
session: z8.string().nullable(),
|
|
2066
2030
|
// The cabane control-plane coordinates for this turn's MCP + post-back.
|
|
2067
|
-
cabane:
|
|
2068
|
-
mcpUrl:
|
|
2069
|
-
bearer:
|
|
2070
|
-
activeConversationId:
|
|
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:
|
|
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:
|
|
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:
|
|
2084
|
-
cwd:
|
|
2085
|
-
env:
|
|
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:
|
|
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:
|
|
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:
|
|
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
|
|
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 =
|
|
2130
|
-
name:
|
|
2097
|
+
conformanceFixtureSchema = z9.object({
|
|
2098
|
+
name: z9.string(),
|
|
2131
2099
|
request: turnRequestSchema,
|
|
2132
|
-
nativeStream:
|
|
2133
|
-
expected:
|
|
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
|
|
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
|
|
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 =
|
|
2691
|
-
thinking:
|
|
2692
|
-
|
|
2693
|
-
type:
|
|
2694
|
-
display:
|
|
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
|
-
|
|
2697
|
-
type:
|
|
2698
|
-
budgetTokens:
|
|
2699
|
-
display:
|
|
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
|
-
|
|
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: "
|
|
2714
|
+
permissionDecisionReason: "headless never-prompt (CT680)",
|
|
2770
2715
|
updatedInput: toolInput
|
|
2771
2716
|
}
|
|
2772
2717
|
};
|
|
2773
2718
|
}
|
|
2774
2719
|
function buildClaudeCodeOptions(req, augment) {
|
|
2775
|
-
const {
|
|
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
|
-
|
|
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
|
-
//
|
|
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
|
-
|
|
2873
|
-
|
|
2874
|
-
|
|
2875
|
-
|
|
2876
|
-
|
|
2877
|
-
|
|
2878
|
-
|
|
2879
|
-
|
|
2880
|
-
|
|
2881
|
-
|
|
2882
|
-
|
|
2883
|
-
|
|
2884
|
-
|
|
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,
|
|
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
|
|
4270
|
-
function
|
|
4185
|
+
import { z as z11 } from "zod";
|
|
4186
|
+
function opencodeTools() {
|
|
4271
4187
|
const tools = {};
|
|
4272
|
-
const
|
|
4273
|
-
|
|
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
|
|
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 =
|
|
4305
|
-
agent:
|
|
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 {
|
|
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(
|
|
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(
|
|
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,
|
|
4406
|
+
await installMcp(doFetch, url, spec, signal);
|
|
4510
4407
|
const promptRes = await doFetch(
|
|
4511
|
-
|
|
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(
|
|
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(
|
|
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,
|
|
4461
|
+
async function installMcp(doFetch, url, spec, signal) {
|
|
4559
4462
|
const [live, configured] = await Promise.all([
|
|
4560
|
-
getJson(doFetch,
|
|
4561
|
-
getJson(doFetch,
|
|
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,
|
|
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,
|
|
4478
|
+
Object.entries(spec.mcp).map(([name, config]) => postMcp(doFetch, url, name, config, signal))
|
|
4576
4479
|
);
|
|
4577
4480
|
}
|
|
4578
|
-
async function postMcp(doFetch,
|
|
4579
|
-
const res = await doFetch(
|
|
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,
|
|
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
|
|
5594
|
-
function
|
|
5595
|
-
return
|
|
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 =
|
|
5621
|
-
modelReasoningEffort:
|
|
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,
|
|
5642
|
-
const {
|
|
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:
|
|
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:
|
|
5564
|
+
conversation: (held?.conversation ?? null) !== fingerprints.conversation
|
|
5661
5565
|
};
|
|
5662
5566
|
return {
|
|
5663
5567
|
resumeThreadId,
|
|
5664
5568
|
directory,
|
|
5665
5569
|
model,
|
|
5666
|
-
|
|
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
|
|
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
|
|
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.
|
|
5787
|
+
...spec.sandboxMode ? { sandboxMode: spec.sandboxMode } : {},
|
|
5888
5788
|
workingDirectory: spec.directory,
|
|
5889
5789
|
skipGitRepoCheck: spec.skipGitRepoCheck,
|
|
5890
|
-
approvalPolicy: spec.
|
|
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,
|
|
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
|
|
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 =
|
|
7461
|
-
type:
|
|
7462
|
-
command:
|
|
7463
|
-
args:
|
|
7464
|
-
env:
|
|
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:
|
|
7324
|
+
envFromEnv: z13.record(z13.string(), z13.string()).optional()
|
|
7468
7325
|
});
|
|
7469
|
-
mcpHttpServerSchema =
|
|
7470
|
-
type:
|
|
7471
|
-
url:
|
|
7472
|
-
headers:
|
|
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:
|
|
7333
|
+
headersFromEnv: z13.record(z13.string(), z13.string()).optional()
|
|
7477
7334
|
});
|
|
7478
|
-
mcpSseServerSchema =
|
|
7479
|
-
type:
|
|
7480
|
-
url:
|
|
7481
|
-
headers:
|
|
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:
|
|
7342
|
+
headersFromEnv: z13.record(z13.string(), z13.string()).optional()
|
|
7486
7343
|
});
|
|
7487
|
-
mcpServerDefSchema =
|
|
7488
|
-
thinkingConfigSchema =
|
|
7489
|
-
|
|
7490
|
-
|
|
7491
|
-
|
|
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 =
|
|
7494
|
-
runConfigSchema =
|
|
7495
|
-
|
|
7496
|
-
|
|
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
|
|
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 =
|
|
7589
|
-
quotaState:
|
|
7590
|
-
limitedUntil:
|
|
7591
|
-
lastError:
|
|
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 =
|
|
7594
|
-
deviceId:
|
|
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:
|
|
7598
|
-
workspaceId:
|
|
7599
|
-
workspaceSlug:
|
|
7600
|
-
agentId:
|
|
7601
|
-
agentUsername:
|
|
7602
|
-
agentName:
|
|
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:
|
|
7608
|
-
opencodeServerUrl:
|
|
7609
|
-
claudeCodeAvailable:
|
|
7610
|
-
codexAvailable:
|
|
7611
|
-
idleTimeoutMs:
|
|
7612
|
-
totalTimeoutMs:
|
|
7613
|
-
leaseRenewalMs:
|
|
7614
|
-
preparingRowDelayMs:
|
|
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:
|
|
7618
|
-
logLevel:
|
|
7469
|
+
transcripts: z14.boolean(),
|
|
7470
|
+
logLevel: z14.string(),
|
|
7619
7471
|
// The launcher's connector-health observations, by runtime, as of the start.
|
|
7620
|
-
connectorHealth:
|
|
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:
|
|
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:
|
|
7478
|
+
runnerId: z14.string()
|
|
7627
7479
|
});
|
|
7628
|
-
dispatchSchema =
|
|
7629
|
-
type:
|
|
7630
|
-
agentId:
|
|
7631
|
-
deviceId:
|
|
7632
|
-
conversationId:
|
|
7633
|
-
messageId:
|
|
7634
|
-
episode:
|
|
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 =
|
|
7637
|
-
credential:
|
|
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
|
|
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:
|
|
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:
|
|
8101
|
-
question:
|
|
8102
|
-
headline:
|
|
8103
|
-
options:
|
|
8104
|
-
questions:
|
|
8105
|
-
|
|
8106
|
-
headline:
|
|
8107
|
-
body:
|
|
8108
|
-
options:
|
|
8109
|
-
|
|
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:
|
|
8114
|
-
askId:
|
|
8115
|
-
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:
|
|
8157
|
-
at:
|
|
8158
|
-
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:
|
|
8193
|
-
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-
|
|
8288
|
-
import {
|
|
8289
|
-
import {
|
|
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
|
-
|
|
8292
|
-
|
|
8293
|
-
|
|
8294
|
-
|
|
8295
|
-
|
|
8296
|
-
|
|
8297
|
-
|
|
8298
|
-
|
|
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
|
|
8303
|
-
|
|
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
|
|
8312
|
-
import { tmpdir
|
|
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
|
|
8179
|
+
const dir2 = await mkdtemp(join16(tmpdir(), `cabane-codex-images-${opts.turnId}-`));
|
|
8320
8180
|
const cleanup = async () => {
|
|
8321
8181
|
try {
|
|
8322
|
-
await
|
|
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
|
|
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
|
|
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(
|
|
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
|
|
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 =
|
|
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
|
-
|
|
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: {
|
|
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
|
|
13452
|
-
var resultSchema =
|
|
13453
|
-
kind:
|
|
13454
|
-
from:
|
|
13455
|
-
to:
|
|
13456
|
-
at:
|
|
13457
|
-
reason:
|
|
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 =
|
|
13460
|
-
from:
|
|
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:
|
|
13463
|
-
to:
|
|
13464
|
-
at:
|
|
13465
|
-
boots:
|
|
13320
|
+
fromRoot: z17.string(),
|
|
13321
|
+
to: z17.string(),
|
|
13322
|
+
at: z17.string(),
|
|
13323
|
+
boots: z17.number().int().nonnegative()
|
|
13466
13324
|
});
|
|
13467
|
-
var stateSchema =
|
|
13468
|
-
server:
|
|
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:
|
|
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
|
|
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 =
|
|
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(
|
|
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
|
|
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(
|
|
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
|
-
|
|
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(
|
|
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;
|