@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/runtime.js
CHANGED
|
@@ -230,7 +230,7 @@ var localAgentConfigSchema = z2.object({
|
|
|
230
230
|
// yourself, `claudeCode: { autoMemory: true }` hands auto-memory back to your
|
|
231
231
|
// own `~/.claude/settings.json` — Cabane then stops
|
|
232
232
|
// injecting the off switch and your normal Claude Code memory workflow applies
|
|
233
|
-
// (
|
|
233
|
+
// (the user and project settings load on every Claude Code turn).
|
|
234
234
|
claudeCode: z2.object({ autoMemory: z2.boolean().optional() }).strict().optional()
|
|
235
235
|
}).strict();
|
|
236
236
|
var agentsConfigSchema = z2.record(z2.string(), localAgentConfigSchema);
|
|
@@ -847,7 +847,6 @@ var CompanionStateHub = class {
|
|
|
847
847
|
agent_id: a.agentId,
|
|
848
848
|
username: a.username,
|
|
849
849
|
display_name: a.displayName,
|
|
850
|
-
mode: a.mode,
|
|
851
850
|
has_credential: a.hasCredential,
|
|
852
851
|
missing_secrets: a.missingSecrets
|
|
853
852
|
}))
|
|
@@ -2620,35 +2619,9 @@ function noResume() {
|
|
|
2620
2619
|
// packages/agent-runtime/src/version.ts
|
|
2621
2620
|
var TURN_PROTOCOL_VERSION = 1;
|
|
2622
2621
|
|
|
2623
|
-
// packages/agent-runtime/src/host-policy.ts
|
|
2624
|
-
import { z as z6 } from "zod";
|
|
2625
|
-
var hostPolicySchema = z6.object({
|
|
2626
|
-
// Host filesystem and shell: `Bash`/`Read`/`Write`/`Edit`/`Glob`/`Grep`, the notebook pair,
|
|
2627
|
-
// git-worktree tools and `REPL`. Off on the locked assistant surface; on in the coding posture.
|
|
2628
|
-
hostFs: z6.boolean(),
|
|
2629
|
-
// Public web (`WebSearch` / `WebFetch`). Not host reach; a grant like the rest.
|
|
2630
|
-
web: z6.boolean(),
|
|
2631
|
-
// Browser automation (the Playwright MCP surface). Varies by host.
|
|
2632
|
-
browser: z6.boolean(),
|
|
2633
|
-
// User-configured MCP servers permitted.
|
|
2634
|
-
userMcp: z6.boolean(),
|
|
2635
|
-
// Subagent dispatch (`Task` / `Agent`) — a grant: `false` on the locked surface, `true` in the
|
|
2636
|
-
// coding posture, where the coding allow-hook reaches sub-agent tool calls. A subagent completes
|
|
2637
|
-
// within the turn, so it's not an invariant like `scheduling`.
|
|
2638
|
-
subagents: z6.boolean(),
|
|
2639
|
-
// ── Hard platform invariants — always denied, never granted ────────────────
|
|
2640
|
-
// Deferred re-invocation / scheduling (`ScheduleWakeup`, the `Cron*` / `Task*` families,
|
|
2641
|
-
// `Monitor`, `Workflow`, …). A turn is one query that resolves on `result`; a scheduled callback
|
|
2642
|
-
// fires after the reply window has closed and strands the agent.
|
|
2643
|
-
scheduling: z6.literal("never"),
|
|
2644
|
-
// Human-facing UI prompts (`AskUserQuestion`). Nothing in a Cabane conversation can answer a
|
|
2645
|
-
// structured prompt, so the call hangs the turn. The agent asks in its reply instead.
|
|
2646
|
-
uiPrompts: z6.literal("never")
|
|
2647
|
-
});
|
|
2648
|
-
|
|
2649
2622
|
// packages/agent-runtime/src/turn-event.ts
|
|
2650
|
-
import { z as
|
|
2651
|
-
var turnEventSchema =
|
|
2623
|
+
import { z as z6 } from "zod";
|
|
2624
|
+
var turnEventSchema = z6.discriminatedUnion("type", [
|
|
2652
2625
|
// The runtime's opaque session state, emitted when the adapter learns it (e.g. the SDK
|
|
2653
2626
|
// `system/init` frame). The platform stores `state` verbatim per (conversation, agent) and
|
|
2654
2627
|
// hands it back next turn; only the adapter knows what it means.
|
|
@@ -2660,21 +2633,21 @@ var turnEventSchema = z7.discriminatedUnion("type", [
|
|
|
2660
2633
|
// server rewinds the mark, so the next turn rebuilds a full catch-up (this turn is unavoidably
|
|
2661
2634
|
// lossy — the degrade is known only after the manifest was committed). A plain boolean; the
|
|
2662
2635
|
// runtime-specific reason stays in the adapter's `onWarn` log. Optional.
|
|
2663
|
-
|
|
2664
|
-
type:
|
|
2665
|
-
state:
|
|
2666
|
-
degraded:
|
|
2636
|
+
z6.object({
|
|
2637
|
+
type: z6.literal("session"),
|
|
2638
|
+
state: z6.string(),
|
|
2639
|
+
degraded: z6.boolean().optional()
|
|
2667
2640
|
}),
|
|
2668
2641
|
// One readable thinking summary. Transient — surfaced live, never persisted as content.
|
|
2669
|
-
|
|
2642
|
+
z6.object({ type: z6.literal("thinking"), text: z6.string() }),
|
|
2670
2643
|
// Assistant text. `terminal: false` is interim narration (commits as `progress`);
|
|
2671
2644
|
// `terminal: true` is the turn's closing reply (commits as `final`).
|
|
2672
|
-
|
|
2645
|
+
z6.object({ type: z6.literal("text"), body: z6.string(), terminal: z6.boolean() }),
|
|
2673
2646
|
// Runtime/provider-authored prose about the turn — a failure's explanation, or a line the
|
|
2674
2647
|
// harness wrote on a turn it recovered. Not the agent's words: the pump persists it as
|
|
2675
2648
|
// `runtime_notice`, drawn in the SystemNote voice. Adapters emit it only from positive runtime
|
|
2676
2649
|
// evidence; the web never classifies English strings.
|
|
2677
|
-
|
|
2650
|
+
z6.object({ type: z6.literal("runtime_notice"), body: z6.string() }),
|
|
2678
2651
|
// A tool-activity transition. `name` is prefix-stripped (`cabane_read`, not
|
|
2679
2652
|
// `mcp__cabane__cabane_read`); `summary` is the short card label; `phase` pairs `start` with a
|
|
2680
2653
|
// later `done`/`error` on the same `id`.
|
|
@@ -2683,15 +2656,15 @@ var turnEventSchema = z7.discriminatedUnion("type", [
|
|
|
2683
2656
|
// log are a consumer concern (docs/turn-protocol.md). `mcpServer` is the MCP server the call
|
|
2684
2657
|
// came from (`cabane`, `playwright`, …), derived before `name` dropped the prefix; null for a
|
|
2685
2658
|
// host tool. Optional, read as null when absent.
|
|
2686
|
-
|
|
2687
|
-
type:
|
|
2688
|
-
id:
|
|
2689
|
-
name:
|
|
2690
|
-
phase:
|
|
2691
|
-
summary:
|
|
2692
|
-
input:
|
|
2693
|
-
result:
|
|
2694
|
-
mcpServer:
|
|
2659
|
+
z6.object({
|
|
2660
|
+
type: z6.literal("tool"),
|
|
2661
|
+
id: z6.string(),
|
|
2662
|
+
name: z6.string(),
|
|
2663
|
+
phase: z6.enum(["start", "done", "error"]),
|
|
2664
|
+
summary: z6.string(),
|
|
2665
|
+
input: z6.unknown().optional(),
|
|
2666
|
+
result: z6.unknown().optional(),
|
|
2667
|
+
mcpServer: z6.string().nullable().optional()
|
|
2695
2668
|
}),
|
|
2696
2669
|
// The turn's terminal outcome. `ok:false` carries a machine reason (`no_session`, an error
|
|
2697
2670
|
// code), surfaced by the host's clear-PATCH as `errorReason`.
|
|
@@ -2712,70 +2685,70 @@ var turnEventSchema = z7.discriminatedUnion("type", [
|
|
|
2712
2685
|
// started with); `resolvedConfig` the knobs the harness reported (`{ reasoningEffort }` for
|
|
2713
2686
|
// codex). Known only after the run streams, so they ride this event home and the host relays
|
|
2714
2687
|
// them on settle. A cancel has no result event at all.
|
|
2715
|
-
|
|
2716
|
-
type:
|
|
2717
|
-
ok:
|
|
2718
|
-
reason:
|
|
2719
|
-
usage:
|
|
2720
|
-
inputTokens:
|
|
2721
|
-
outputTokens:
|
|
2722
|
-
cacheReadTokens:
|
|
2723
|
-
cacheCreationTokens:
|
|
2724
|
-
contextTokens:
|
|
2725
|
-
contextWindow:
|
|
2688
|
+
z6.object({
|
|
2689
|
+
type: z6.literal("result"),
|
|
2690
|
+
ok: z6.boolean(),
|
|
2691
|
+
reason: z6.string().optional(),
|
|
2692
|
+
usage: z6.object({
|
|
2693
|
+
inputTokens: z6.number(),
|
|
2694
|
+
outputTokens: z6.number(),
|
|
2695
|
+
cacheReadTokens: z6.number().optional(),
|
|
2696
|
+
cacheCreationTokens: z6.number().optional(),
|
|
2697
|
+
contextTokens: z6.number().optional(),
|
|
2698
|
+
contextWindow: z6.number().optional(),
|
|
2726
2699
|
// The rest of the harness's context reading, when it gave one: where it will compact, its
|
|
2727
2700
|
// `/context` breakdown, and every compaction it reported. Claude Code only.
|
|
2728
|
-
contextCompactAt:
|
|
2729
|
-
contextCategories:
|
|
2730
|
-
|
|
2731
|
-
name:
|
|
2732
|
-
tokens:
|
|
2733
|
-
kind:
|
|
2701
|
+
contextCompactAt: z6.number().optional(),
|
|
2702
|
+
contextCategories: z6.array(
|
|
2703
|
+
z6.object({
|
|
2704
|
+
name: z6.string(),
|
|
2705
|
+
tokens: z6.number(),
|
|
2706
|
+
kind: z6.enum(["used", "free", "buffer", "deferred"])
|
|
2734
2707
|
})
|
|
2735
2708
|
).optional(),
|
|
2736
|
-
contextCompactions:
|
|
2737
|
-
|
|
2738
|
-
trigger:
|
|
2739
|
-
preTokens:
|
|
2740
|
-
postTokens:
|
|
2709
|
+
contextCompactions: z6.array(
|
|
2710
|
+
z6.object({
|
|
2711
|
+
trigger: z6.enum(["manual", "auto"]),
|
|
2712
|
+
preTokens: z6.number(),
|
|
2713
|
+
postTokens: z6.number().optional()
|
|
2741
2714
|
})
|
|
2742
2715
|
).optional()
|
|
2743
2716
|
}).optional(),
|
|
2744
|
-
resolvedModel:
|
|
2745
|
-
resolvedConfig:
|
|
2746
|
-
effort:
|
|
2747
|
-
thinking:
|
|
2748
|
-
reasoningEffort:
|
|
2717
|
+
resolvedModel: z6.string().optional(),
|
|
2718
|
+
resolvedConfig: z6.object({
|
|
2719
|
+
effort: z6.string().optional(),
|
|
2720
|
+
thinking: z6.string().optional(),
|
|
2721
|
+
reasoningEffort: z6.string().optional()
|
|
2749
2722
|
}).optional(),
|
|
2750
2723
|
// The harness-reported MCP inventory from this turn's init frame. Diagnostic only: names,
|
|
2751
2724
|
// statuses and a count — never server definitions, credentials or session ids.
|
|
2752
2725
|
// `initReceived:false` tells a missing init frame from a real empty inventory.
|
|
2753
|
-
mcpInventory:
|
|
2754
|
-
initReceived:
|
|
2755
|
-
servers:
|
|
2756
|
-
toolCount:
|
|
2726
|
+
mcpInventory: z6.object({
|
|
2727
|
+
initReceived: z6.boolean(),
|
|
2728
|
+
servers: z6.array(z6.object({ name: z6.string(), status: z6.string() })),
|
|
2729
|
+
toolCount: z6.number().int().nonnegative()
|
|
2757
2730
|
}).optional()
|
|
2758
2731
|
})
|
|
2759
2732
|
]);
|
|
2760
2733
|
|
|
2761
2734
|
// packages/agent-runtime/src/turn-diagnostics.ts
|
|
2762
|
-
import { z as
|
|
2763
|
-
var turnResultReasonSchema =
|
|
2764
|
-
|
|
2765
|
-
|
|
2766
|
-
|
|
2767
|
-
|
|
2768
|
-
|
|
2769
|
-
|
|
2770
|
-
|
|
2771
|
-
|
|
2772
|
-
|
|
2773
|
-
|
|
2774
|
-
|
|
2775
|
-
|
|
2776
|
-
|
|
2777
|
-
|
|
2778
|
-
|
|
2735
|
+
import { z as z7 } from "zod";
|
|
2736
|
+
var turnResultReasonSchema = z7.discriminatedUnion("kind", [
|
|
2737
|
+
z7.object({ kind: z7.literal("usage_capped"), resetsAt: z7.string().optional() }),
|
|
2738
|
+
z7.object({ kind: z7.literal("rate_limited") }),
|
|
2739
|
+
z7.object({ kind: z7.literal("server_error") }),
|
|
2740
|
+
z7.object({ kind: z7.literal("auth_expired") }),
|
|
2741
|
+
z7.object({ kind: z7.literal("no_result") }),
|
|
2742
|
+
z7.object({ kind: z7.literal("empty_result") }),
|
|
2743
|
+
z7.object({ kind: z7.literal("empty_result_unverified") }),
|
|
2744
|
+
z7.object({ kind: z7.literal("timeout_idle") }),
|
|
2745
|
+
z7.object({ kind: z7.literal("timeout_total") }),
|
|
2746
|
+
z7.object({ kind: z7.literal("cancelled") }),
|
|
2747
|
+
z7.object({ kind: z7.literal("lease_lost") }),
|
|
2748
|
+
z7.object({ kind: z7.literal("skipped") }),
|
|
2749
|
+
z7.object({ kind: z7.literal("session_start_failed") }),
|
|
2750
|
+
z7.object({ kind: z7.literal("workspace_tools_missing") }),
|
|
2751
|
+
z7.object({ kind: z7.literal("runtime_error") })
|
|
2779
2752
|
]);
|
|
2780
2753
|
var turnOutcomes = ["success", "failure", "cancelled", "skipped"];
|
|
2781
2754
|
var turnSessionModes = ["fresh", "resumed", "degraded"];
|
|
@@ -2787,123 +2760,125 @@ var turnFinalSources = [
|
|
|
2787
2760
|
"marker",
|
|
2788
2761
|
"none"
|
|
2789
2762
|
];
|
|
2790
|
-
var turnDiagnosticsSchema =
|
|
2791
|
-
outcome:
|
|
2763
|
+
var turnDiagnosticsSchema = z7.object({
|
|
2764
|
+
outcome: z7.enum(turnOutcomes),
|
|
2792
2765
|
resultReason: turnResultReasonSchema.nullable(),
|
|
2793
|
-
sessionMode:
|
|
2794
|
-
sessionFingerprint:
|
|
2795
|
-
eventCounts:
|
|
2796
|
-
session:
|
|
2797
|
-
text:
|
|
2798
|
-
runtime_notice:
|
|
2799
|
-
thinking:
|
|
2800
|
-
tool:
|
|
2801
|
-
result:
|
|
2766
|
+
sessionMode: z7.enum(turnSessionModes),
|
|
2767
|
+
sessionFingerprint: z7.string().regex(/^[a-f0-9]{16}$/).nullable(),
|
|
2768
|
+
eventCounts: z7.object({
|
|
2769
|
+
session: z7.number().int().nonnegative(),
|
|
2770
|
+
text: z7.number().int().nonnegative(),
|
|
2771
|
+
runtime_notice: z7.number().int().nonnegative(),
|
|
2772
|
+
thinking: z7.number().int().nonnegative(),
|
|
2773
|
+
tool: z7.number().int().nonnegative(),
|
|
2774
|
+
result: z7.number().int().nonnegative()
|
|
2802
2775
|
}),
|
|
2803
|
-
runtimeResultKind:
|
|
2804
|
-
finalSource:
|
|
2805
|
-
mcpInventory:
|
|
2806
|
-
initReceived:
|
|
2807
|
-
servers:
|
|
2808
|
-
toolCount:
|
|
2776
|
+
runtimeResultKind: z7.enum(turnRuntimeResultKinds).nullable(),
|
|
2777
|
+
finalSource: z7.enum(turnFinalSources),
|
|
2778
|
+
mcpInventory: z7.object({
|
|
2779
|
+
initReceived: z7.boolean(),
|
|
2780
|
+
servers: z7.array(z7.object({ name: z7.string(), status: z7.string() })),
|
|
2781
|
+
toolCount: z7.number().int().nonnegative()
|
|
2809
2782
|
}).optional()
|
|
2810
2783
|
});
|
|
2811
2784
|
|
|
2812
2785
|
// packages/agent-runtime/src/turn-request.ts
|
|
2813
|
-
import { z as
|
|
2814
|
-
var contentBlockSchema =
|
|
2815
|
-
|
|
2816
|
-
|
|
2817
|
-
type:
|
|
2818
|
-
source:
|
|
2786
|
+
import { z as z8 } from "zod";
|
|
2787
|
+
var contentBlockSchema = z8.discriminatedUnion("type", [
|
|
2788
|
+
z8.object({ type: z8.literal("text"), text: z8.string() }),
|
|
2789
|
+
z8.object({
|
|
2790
|
+
type: z8.literal("image"),
|
|
2791
|
+
source: z8.object({ type: z8.literal("url"), url: z8.string() })
|
|
2819
2792
|
}),
|
|
2820
|
-
|
|
2821
|
-
type:
|
|
2822
|
-
source:
|
|
2793
|
+
z8.object({
|
|
2794
|
+
type: z8.literal("document"),
|
|
2795
|
+
source: z8.object({ type: z8.literal("url"), url: z8.string() })
|
|
2823
2796
|
})
|
|
2824
2797
|
]);
|
|
2825
|
-
var effortLevelSchema =
|
|
2826
|
-
var resolvedRunConfigSchema =
|
|
2827
|
-
model:
|
|
2798
|
+
var effortLevelSchema = z8.enum(["low", "medium", "high", "xhigh", "max"]);
|
|
2799
|
+
var resolvedRunConfigSchema = z8.object({
|
|
2800
|
+
model: z8.string().nullable(),
|
|
2828
2801
|
effort: effortLevelSchema.optional(),
|
|
2829
|
-
runtimeOptions:
|
|
2802
|
+
runtimeOptions: z8.record(z8.string(), z8.unknown()).optional()
|
|
2830
2803
|
});
|
|
2831
|
-
var resolvedMcpServerSchema =
|
|
2832
|
-
|
|
2833
|
-
type:
|
|
2834
|
-
command:
|
|
2835
|
-
args:
|
|
2836
|
-
env:
|
|
2837
|
-
envFromEnv:
|
|
2804
|
+
var resolvedMcpServerSchema = z8.union([
|
|
2805
|
+
z8.object({
|
|
2806
|
+
type: z8.literal("stdio").optional(),
|
|
2807
|
+
command: z8.string(),
|
|
2808
|
+
args: z8.array(z8.string()).optional(),
|
|
2809
|
+
env: z8.record(z8.string(), z8.string()).optional(),
|
|
2810
|
+
envFromEnv: z8.record(z8.string(), z8.string()).optional()
|
|
2838
2811
|
}),
|
|
2839
|
-
|
|
2840
|
-
type:
|
|
2841
|
-
url:
|
|
2842
|
-
headers:
|
|
2843
|
-
headersFromEnv:
|
|
2812
|
+
z8.object({
|
|
2813
|
+
type: z8.literal("http"),
|
|
2814
|
+
url: z8.string(),
|
|
2815
|
+
headers: z8.record(z8.string(), z8.string()).optional(),
|
|
2816
|
+
headersFromEnv: z8.record(z8.string(), z8.string()).optional()
|
|
2844
2817
|
}),
|
|
2845
|
-
|
|
2846
|
-
type:
|
|
2847
|
-
url:
|
|
2848
|
-
headers:
|
|
2849
|
-
headersFromEnv:
|
|
2818
|
+
z8.object({
|
|
2819
|
+
type: z8.literal("sse"),
|
|
2820
|
+
url: z8.string(),
|
|
2821
|
+
headers: z8.record(z8.string(), z8.string()).optional(),
|
|
2822
|
+
headersFromEnv: z8.record(z8.string(), z8.string()).optional()
|
|
2850
2823
|
})
|
|
2851
2824
|
]);
|
|
2852
|
-
var resolvedMcpServersSchema =
|
|
2853
|
-
var hostInjectedServersSchema =
|
|
2854
|
-
var turnRequestSchema =
|
|
2825
|
+
var resolvedMcpServersSchema = z8.record(z8.string(), resolvedMcpServerSchema);
|
|
2826
|
+
var hostInjectedServersSchema = z8.record(z8.string(), z8.unknown());
|
|
2827
|
+
var turnRequestSchema = z8.object({
|
|
2855
2828
|
// Server-composed standing instructions: the core segment (body, tool naming, identity, agent
|
|
2856
2829
|
// charter) and, after it, the conversation segment (workspace and room charters, skill indexes,
|
|
2857
2830
|
// roster). One string to the adapter, current as of this dispatch.
|
|
2858
|
-
systemPrompt:
|
|
2831
|
+
systemPrompt: z8.string(),
|
|
2859
2832
|
// The same text as its two ordered segments, so an adapter that writes standing text into the
|
|
2860
2833
|
// conversation (Codex's input preamble) can tell which half changed. `systemPrompt` is
|
|
2861
2834
|
// `joinStanding(standing)`. Optional: absent from an API older than the split, where
|
|
2862
2835
|
// `systemPrompt` is the core alone and the conversation material rides `prompt`.
|
|
2863
|
-
standing:
|
|
2836
|
+
standing: z8.object({ core: z8.string(), conversation: z8.string() }).optional(),
|
|
2864
2837
|
// Server-composed per-turn user text (anchor reminder + the triggering message).
|
|
2865
|
-
prompt:
|
|
2838
|
+
prompt: z8.string(),
|
|
2866
2839
|
// The multi-block user-message body (text + vision).
|
|
2867
|
-
content:
|
|
2840
|
+
content: z8.array(contentBlockSchema),
|
|
2868
2841
|
// Portable-or-dialect run-config (above).
|
|
2869
2842
|
config: resolvedRunConfigSchema,
|
|
2870
|
-
// Abstract capability grants; the adapter maps them to tool names.
|
|
2871
|
-
policy: hostPolicySchema,
|
|
2872
2843
|
// Prior opaque session state, or null for a fresh session.
|
|
2873
|
-
session:
|
|
2844
|
+
session: z8.string().nullable(),
|
|
2874
2845
|
// The cabane control-plane coordinates for this turn's MCP + post-back.
|
|
2875
|
-
cabane:
|
|
2876
|
-
mcpUrl:
|
|
2877
|
-
bearer:
|
|
2878
|
-
activeConversationId:
|
|
2846
|
+
cabane: z8.object({
|
|
2847
|
+
mcpUrl: z8.string(),
|
|
2848
|
+
bearer: z8.string(),
|
|
2849
|
+
activeConversationId: z8.string(),
|
|
2879
2850
|
// Scoped turn-control MCP URL. Codex and opencode mount it as `cabane_companion` with the bearer
|
|
2880
2851
|
// and active-conversation header, for ask, withdraw_ask, wake_me, cancel_wake and skip_turn.
|
|
2881
2852
|
// Claude Code mounts the companion's in-process instance instead. Optional; the companion
|
|
2882
2853
|
// populates it.
|
|
2883
|
-
turnControlUrl:
|
|
2854
|
+
turnControlUrl: z8.string().optional(),
|
|
2884
2855
|
// Workspace coordinate retained for envelope compatibility. Current
|
|
2885
2856
|
// adapters use MCP, whose workspace operations take workspaceId explicitly.
|
|
2886
2857
|
// The companion supplies this field; it is not required by those adapters.
|
|
2887
|
-
workspaceId:
|
|
2858
|
+
workspaceId: z8.string().optional()
|
|
2888
2859
|
}),
|
|
2889
2860
|
// Machine-local resolution (host-filled): the checkout cwd, extra env from a
|
|
2890
2861
|
// prepare hook, and the resolved user MCP servers.
|
|
2891
|
-
local:
|
|
2892
|
-
cwd:
|
|
2893
|
-
env:
|
|
2862
|
+
local: z8.object({
|
|
2863
|
+
cwd: z8.string().optional(),
|
|
2864
|
+
env: z8.record(z8.string(), z8.string()).optional(),
|
|
2894
2865
|
mcpServers: resolvedMcpServersSchema.optional(),
|
|
2895
2866
|
// The values `headersFromEnv` names, per turn (`CABANE_MCP_<n>` → complete header value). The
|
|
2896
2867
|
// adapter merges them into the harness process's environment and nowhere else; the host never
|
|
2897
2868
|
// merges them into its own. Absent when no server references one.
|
|
2898
|
-
secretEnv:
|
|
2869
|
+
secretEnv: z8.record(z8.string(), z8.string()).optional(),
|
|
2899
2870
|
// Machine-local claude-code knobs for an operator running their own companion — the auto-memory
|
|
2900
2871
|
// escape hatch. `autoMemory: true` opts back into Claude Code's auto-memory (governed by the
|
|
2901
2872
|
// operator's `.claude/settings.json`); absent/false keeps the adapter's force-off default
|
|
2902
2873
|
// (`buildClaudeCodeOptions`).
|
|
2903
|
-
claudeCode:
|
|
2874
|
+
claudeCode: z8.object({ autoMemory: z8.boolean().optional() }).optional(),
|
|
2875
|
+
// Machine-local Codex facts the host read before the turn. `configSetsSandboxMode`: the
|
|
2876
|
+
// person's own Codex `config.toml` names a `sandbox_mode`, so the adapter passes no sandbox
|
|
2877
|
+
// flag and the file governs (`codexSandboxMode`). Absent/false → `danger-full-access`.
|
|
2878
|
+
codex: z8.object({ configSetsSandboxMode: z8.boolean().optional() }).optional()
|
|
2904
2879
|
}),
|
|
2905
2880
|
// Host-owned injected servers (host-filled).
|
|
2906
|
-
extra:
|
|
2881
|
+
extra: z8.object({
|
|
2907
2882
|
mcpServers: hostInjectedServersSchema
|
|
2908
2883
|
})
|
|
2909
2884
|
});
|
|
@@ -2919,12 +2894,12 @@ function standingSegments(req) {
|
|
|
2919
2894
|
}
|
|
2920
2895
|
|
|
2921
2896
|
// packages/agent-runtime/src/conformance.ts
|
|
2922
|
-
import { z as
|
|
2923
|
-
var conformanceFixtureSchema =
|
|
2924
|
-
name:
|
|
2897
|
+
import { z as z9 } from "zod";
|
|
2898
|
+
var conformanceFixtureSchema = z9.object({
|
|
2899
|
+
name: z9.string(),
|
|
2925
2900
|
request: turnRequestSchema,
|
|
2926
|
-
nativeStream:
|
|
2927
|
-
expected:
|
|
2901
|
+
nativeStream: z9.array(z9.unknown()),
|
|
2902
|
+
expected: z9.array(turnEventSchema)
|
|
2928
2903
|
});
|
|
2929
2904
|
|
|
2930
2905
|
// packages/agent-runtime/src/transcript.ts
|
|
@@ -3189,24 +3164,7 @@ function envResolvedFrom(server, secretEnv) {
|
|
|
3189
3164
|
}
|
|
3190
3165
|
|
|
3191
3166
|
// packages/agent-runtime/src/claude-code/policy.ts
|
|
3192
|
-
import { z as
|
|
3193
|
-
var HOST_FS_TOOLS = [
|
|
3194
|
-
// shell + local filesystem
|
|
3195
|
-
"Bash",
|
|
3196
|
-
"Read",
|
|
3197
|
-
"Write",
|
|
3198
|
-
"Edit",
|
|
3199
|
-
"Glob",
|
|
3200
|
-
"Grep",
|
|
3201
|
-
// notebook tools (host-fs, Jupyter) — same host reach as Read/Write/Edit
|
|
3202
|
-
"NotebookEdit",
|
|
3203
|
-
"NotebookRead",
|
|
3204
|
-
// git-worktree manipulation on the host checkout
|
|
3205
|
-
"EnterWorktree",
|
|
3206
|
-
"ExitWorktree",
|
|
3207
|
-
// host code execution
|
|
3208
|
-
"REPL"
|
|
3209
|
-
];
|
|
3167
|
+
import { z as z10 } from "zod";
|
|
3210
3168
|
var SUBAGENT_TOOLS = ["Task", "Agent"];
|
|
3211
3169
|
var UNSUPPORTED_TOOLS = ["AskUserQuestion"];
|
|
3212
3170
|
var STRANDING_TOOLS = [
|
|
@@ -3228,29 +3186,23 @@ var STRANDING_TOOLS = [
|
|
|
3228
3186
|
"Workflow"
|
|
3229
3187
|
];
|
|
3230
3188
|
var DEFAULT_WEB_TOOLS = ["WebSearch", "WebFetch"];
|
|
3231
|
-
function disallowedToolsFor(policy) {
|
|
3232
|
-
const tools = [...UNSUPPORTED_TOOLS, ...STRANDING_TOOLS];
|
|
3233
|
-
if (!policy.subagents) tools.unshift(...SUBAGENT_TOOLS);
|
|
3234
|
-
if (!policy.hostFs) tools.unshift(...HOST_FS_TOOLS);
|
|
3235
|
-
return tools;
|
|
3236
|
-
}
|
|
3237
3189
|
function withThinkingSummaries(thinking) {
|
|
3238
3190
|
if (!thinking) return { type: "adaptive", display: "summarized" };
|
|
3239
3191
|
if (thinking.type === "disabled") return thinking;
|
|
3240
3192
|
return { display: "summarized", ...thinking };
|
|
3241
3193
|
}
|
|
3242
|
-
var claudeCodeDialectSchema =
|
|
3243
|
-
thinking:
|
|
3244
|
-
|
|
3245
|
-
type:
|
|
3246
|
-
display:
|
|
3194
|
+
var claudeCodeDialectSchema = z10.object({
|
|
3195
|
+
thinking: z10.discriminatedUnion("type", [
|
|
3196
|
+
z10.object({
|
|
3197
|
+
type: z10.literal("adaptive"),
|
|
3198
|
+
display: z10.enum(["summarized", "omitted"]).optional()
|
|
3247
3199
|
}),
|
|
3248
|
-
|
|
3249
|
-
type:
|
|
3250
|
-
budgetTokens:
|
|
3251
|
-
display:
|
|
3200
|
+
z10.object({
|
|
3201
|
+
type: z10.literal("enabled"),
|
|
3202
|
+
budgetTokens: z10.number().int().positive().optional(),
|
|
3203
|
+
display: z10.enum(["summarized", "omitted"]).optional()
|
|
3252
3204
|
}),
|
|
3253
|
-
|
|
3205
|
+
z10.object({ type: z10.literal("disabled") })
|
|
3254
3206
|
]).optional()
|
|
3255
3207
|
}).loose();
|
|
3256
3208
|
function readThinking(runtimeOptions) {
|
|
@@ -3313,13 +3265,13 @@ async function preToolUseHook(input) {
|
|
|
3313
3265
|
hookSpecificOutput: {
|
|
3314
3266
|
hookEventName: "PreToolUse",
|
|
3315
3267
|
permissionDecision: "allow",
|
|
3316
|
-
permissionDecisionReason: "
|
|
3268
|
+
permissionDecisionReason: "headless never-prompt (CT680)",
|
|
3317
3269
|
updatedInput: toolInput
|
|
3318
3270
|
}
|
|
3319
3271
|
};
|
|
3320
3272
|
}
|
|
3321
3273
|
function buildClaudeCodeOptions(req, augment) {
|
|
3322
|
-
const {
|
|
3274
|
+
const { config } = req;
|
|
3323
3275
|
const cwd = req.local.cwd;
|
|
3324
3276
|
const userServers = {};
|
|
3325
3277
|
for (const [name, server] of Object.entries(req.local.mcpServers ?? {})) {
|
|
@@ -3352,15 +3304,10 @@ function buildClaudeCodeOptions(req, augment) {
|
|
|
3352
3304
|
alwaysLoad: true
|
|
3353
3305
|
};
|
|
3354
3306
|
}
|
|
3355
|
-
const useCodingPreset = policy.hostFs;
|
|
3356
3307
|
const cabaneGlob = `mcp__${CABANE_MCP_SERVER}__*`;
|
|
3357
3308
|
const extraServerGlobs = Object.keys(req.extra.mcpServers).map((name) => `mcp__${name}__*`);
|
|
3358
|
-
const allowedTools = dedupe([
|
|
3359
|
-
|
|
3360
|
-
...extraServerGlobs,
|
|
3361
|
-
...policy.web ? DEFAULT_WEB_TOOLS : []
|
|
3362
|
-
]);
|
|
3363
|
-
const disallowedTools = dedupe([...disallowedToolsFor(policy)]);
|
|
3309
|
+
const allowedTools = dedupe([cabaneGlob, ...extraServerGlobs, ...DEFAULT_WEB_TOOLS]);
|
|
3310
|
+
const disallowedTools = dedupe([...UNSUPPORTED_TOOLS, ...STRANDING_TOOLS]);
|
|
3364
3311
|
const resumeDecision = decideResume(req.session, cwd);
|
|
3365
3312
|
const resume = "resume" in resumeDecision ? resumeDecision.resume : null;
|
|
3366
3313
|
const freshReason = "fresh" in resumeDecision ? resumeDecision.reason : void 0;
|
|
@@ -3378,9 +3325,7 @@ function buildClaudeCodeOptions(req, augment) {
|
|
|
3378
3325
|
// (`runtimeOptions['claude-code']`).
|
|
3379
3326
|
thinking: withThinkingSummaries(readThinking(config.runtimeOptions)),
|
|
3380
3327
|
...config.effort ? { effort: config.effort } : {},
|
|
3381
|
-
//
|
|
3382
|
-
// user's existing `cabane` MCP registration could shadow ours.
|
|
3383
|
-
settingSources: [],
|
|
3328
|
+
// Without `strictMcpConfig` the user's existing `cabane` MCP registration could shadow ours.
|
|
3384
3329
|
strictMcpConfig: true,
|
|
3385
3330
|
// Auto-memory off unless the operator opted back in (see above).
|
|
3386
3331
|
...devControlsAutoMemory ? {} : { settings: { autoMemoryEnabled: false } },
|
|
@@ -3416,31 +3361,19 @@ function buildClaudeCodeOptions(req, augment) {
|
|
|
3416
3361
|
},
|
|
3417
3362
|
...resume ? { resume } : {}
|
|
3418
3363
|
};
|
|
3419
|
-
|
|
3420
|
-
|
|
3421
|
-
|
|
3422
|
-
|
|
3423
|
-
|
|
3424
|
-
|
|
3425
|
-
|
|
3426
|
-
|
|
3427
|
-
|
|
3428
|
-
|
|
3429
|
-
|
|
3430
|
-
|
|
3431
|
-
|
|
3432
|
-
hooks: { PreToolUse: [{ hooks: [preToolUseHook] }] }
|
|
3433
|
-
};
|
|
3434
|
-
} else {
|
|
3435
|
-
options = {
|
|
3436
|
-
...base,
|
|
3437
|
-
systemPrompt: { type: "custom", prompt: req.systemPrompt, snapshot: false },
|
|
3438
|
-
allowedTools,
|
|
3439
|
-
disallowedTools,
|
|
3440
|
-
permissionMode: "bypassPermissions",
|
|
3441
|
-
allowDangerouslySkipPermissions: true
|
|
3442
|
-
};
|
|
3443
|
-
}
|
|
3364
|
+
const options = {
|
|
3365
|
+
...base,
|
|
3366
|
+
systemPrompt: {
|
|
3367
|
+
type: "preset",
|
|
3368
|
+
preset: "claude_code",
|
|
3369
|
+
append: req.systemPrompt,
|
|
3370
|
+
snapshot: false
|
|
3371
|
+
},
|
|
3372
|
+
settingSources: ["user", "project"],
|
|
3373
|
+
allowedTools,
|
|
3374
|
+
disallowedTools,
|
|
3375
|
+
hooks: { PreToolUse: [{ hooks: [preToolUseHook] }] }
|
|
3376
|
+
};
|
|
3444
3377
|
return { options: augment ? augment(options, req) : options, resume, freshReason };
|
|
3445
3378
|
}
|
|
3446
3379
|
function dedupe(xs) {
|
|
@@ -3920,15 +3853,6 @@ var claudeCodeAdapter = createClaudeCodeAdapter();
|
|
|
3920
3853
|
|
|
3921
3854
|
// packages/agent-runtime/src/claude-code/conformance.ts
|
|
3922
3855
|
var ABORT_SENTINEL = { __abortHere: true };
|
|
3923
|
-
var CABANE_POLICY = {
|
|
3924
|
-
hostFs: false,
|
|
3925
|
-
web: true,
|
|
3926
|
-
browser: false,
|
|
3927
|
-
userMcp: false,
|
|
3928
|
-
subagents: false,
|
|
3929
|
-
scheduling: "never",
|
|
3930
|
-
uiPrompts: "never"
|
|
3931
|
-
};
|
|
3932
3856
|
var CWD = "/env/here";
|
|
3933
3857
|
var HEALTHY_MCP_INVENTORY = {
|
|
3934
3858
|
initReceived: true,
|
|
@@ -3942,7 +3866,6 @@ function makeRequest(overrides2 = {}) {
|
|
|
3942
3866
|
content: [{ type: "text", text: "hi there" }],
|
|
3943
3867
|
// The adapter rejects a null model, so the fixture carries a real bare SDK id.
|
|
3944
3868
|
config: { model: "claude-opus-4-8" },
|
|
3945
|
-
policy: CABANE_POLICY,
|
|
3946
3869
|
session: null,
|
|
3947
3870
|
cabane: { mcpUrl: "https://cabane.test/api/mcp", bearer: "tok", activeConversationId: "conv" },
|
|
3948
3871
|
local: { cwd: CWD },
|
|
@@ -4689,35 +4612,17 @@ function sealHeld(held, terminal) {
|
|
|
4689
4612
|
}
|
|
4690
4613
|
|
|
4691
4614
|
// packages/agent-runtime/src/opencode/policy.ts
|
|
4692
|
-
import { z as
|
|
4693
|
-
var OPENCODE_HOST_TOOLS = [
|
|
4694
|
-
"bash",
|
|
4695
|
-
"edit",
|
|
4696
|
-
"write",
|
|
4697
|
-
"read",
|
|
4698
|
-
"grep",
|
|
4699
|
-
"glob",
|
|
4700
|
-
"list",
|
|
4701
|
-
"patch"
|
|
4702
|
-
];
|
|
4703
|
-
var OPENCODE_WEB_TOOLS = ["webfetch"];
|
|
4704
|
-
var OPENCODE_SUBAGENT_TOOLS = ["task"];
|
|
4615
|
+
import { z as z11 } from "zod";
|
|
4705
4616
|
var OPENCODE_SCHEDULING_TOOLS = [];
|
|
4706
4617
|
var OPENCODE_UI_PROMPT_TOOLS = ["question"];
|
|
4707
|
-
function
|
|
4618
|
+
function opencodeTools() {
|
|
4708
4619
|
const tools = {};
|
|
4709
|
-
const
|
|
4710
|
-
|
|
4711
|
-
|
|
4712
|
-
|
|
4713
|
-
|
|
4714
|
-
|
|
4715
|
-
deny(OPENCODE_SCHEDULING_TOOLS);
|
|
4716
|
-
deny(OPENCODE_UI_PROMPT_TOOLS);
|
|
4717
|
-
return { tools, allowAllHostTools: policy.hostFs };
|
|
4718
|
-
}
|
|
4719
|
-
var opencodeDialectSchema = z12.object({
|
|
4720
|
-
agent: z12.string().min(1).optional()
|
|
4620
|
+
for (const name of [...OPENCODE_SCHEDULING_TOOLS, ...OPENCODE_UI_PROMPT_TOOLS])
|
|
4621
|
+
tools[name] = false;
|
|
4622
|
+
return tools;
|
|
4623
|
+
}
|
|
4624
|
+
var opencodeDialectSchema = z11.object({
|
|
4625
|
+
agent: z11.string().min(1).optional()
|
|
4721
4626
|
}).loose();
|
|
4722
4627
|
function readOpencodeDialect(runtimeOptions) {
|
|
4723
4628
|
const parsed = opencodeDialectSchema.safeParse(runtimeOptions?.["opencode"] ?? {});
|
|
@@ -4736,18 +4641,16 @@ var CABANE_MCP_SERVER2 = "cabane";
|
|
|
4736
4641
|
var TURN_CONTROL_MCP_SERVER = "cabane_companion";
|
|
4737
4642
|
var ACTIVE_CONVERSATION_HEADER2 = "x-cabane-active-conversation";
|
|
4738
4643
|
function buildRunSpec(req, resumeSessionId) {
|
|
4739
|
-
const {
|
|
4644
|
+
const { config } = req;
|
|
4740
4645
|
const directory = req.local.cwd ?? "";
|
|
4741
4646
|
const dialect = readOpencodeDialect(config.runtimeOptions);
|
|
4742
|
-
const { tools, allowAllHostTools } = opencodeToolPolicy(policy);
|
|
4743
4647
|
return {
|
|
4744
4648
|
resumeSessionId,
|
|
4745
4649
|
directory,
|
|
4746
4650
|
model: config.model ? parseOpencodeModel(config.model) : null,
|
|
4747
4651
|
systemPrompt: req.systemPrompt,
|
|
4748
4652
|
parts: buildParts(req),
|
|
4749
|
-
tools,
|
|
4750
|
-
allowAllHostTools,
|
|
4653
|
+
tools: opencodeTools(),
|
|
4751
4654
|
...dialect.agent ? { agent: dialect.agent } : {},
|
|
4752
4655
|
mcp: buildMcp(req),
|
|
4753
4656
|
// Every server this turn installs with a credential resolved into it: a remote one's
|
|
@@ -4879,11 +4782,12 @@ function createHttpOpencodeTransport(opts) {
|
|
|
4879
4782
|
const doFetch = opts.fetchImpl ?? fetch;
|
|
4880
4783
|
return {
|
|
4881
4784
|
async run(spec, signal) {
|
|
4785
|
+
const url = scopedUrl(base, spec.directory);
|
|
4882
4786
|
const release = await acquireServerTurnLock(base);
|
|
4883
4787
|
if (signal.aborted) release();
|
|
4884
4788
|
else signal.addEventListener("abort", release, { once: true });
|
|
4885
4789
|
try {
|
|
4886
|
-
const eventRes = await doFetch(
|
|
4790
|
+
const eventRes = await doFetch(url("/event"), {
|
|
4887
4791
|
headers: { accept: "text/event-stream" },
|
|
4888
4792
|
signal
|
|
4889
4793
|
});
|
|
@@ -4893,7 +4797,7 @@ function createHttpOpencodeTransport(opts) {
|
|
|
4893
4797
|
let sessionId = spec.resumeSessionId;
|
|
4894
4798
|
let created = false;
|
|
4895
4799
|
if (!sessionId) {
|
|
4896
|
-
const res = await doFetch(
|
|
4800
|
+
const res = await doFetch(url("/session"), {
|
|
4897
4801
|
method: "POST",
|
|
4898
4802
|
headers: { "content-type": "application/json" },
|
|
4899
4803
|
body: JSON.stringify({ body: {} }),
|
|
@@ -4905,9 +4809,9 @@ function createHttpOpencodeTransport(opts) {
|
|
|
4905
4809
|
sessionId = json.id;
|
|
4906
4810
|
created = true;
|
|
4907
4811
|
}
|
|
4908
|
-
await installMcp(doFetch,
|
|
4812
|
+
await installMcp(doFetch, url, spec, signal);
|
|
4909
4813
|
const promptRes = await doFetch(
|
|
4910
|
-
|
|
4814
|
+
url(`/session/${encodeURIComponent(sessionId)}/prompt_async`),
|
|
4911
4815
|
{
|
|
4912
4816
|
method: "POST",
|
|
4913
4817
|
headers: { "content-type": "application/json" },
|
|
@@ -4926,7 +4830,7 @@ function createHttpOpencodeTransport(opts) {
|
|
|
4926
4830
|
}
|
|
4927
4831
|
const sid = sessionId;
|
|
4928
4832
|
const onAbort = () => {
|
|
4929
|
-
void doFetch(
|
|
4833
|
+
void doFetch(url(`/session/${encodeURIComponent(sid)}/abort`), {
|
|
4930
4834
|
method: "POST"
|
|
4931
4835
|
}).catch(() => {
|
|
4932
4836
|
});
|
|
@@ -4938,7 +4842,13 @@ function createHttpOpencodeTransport(opts) {
|
|
|
4938
4842
|
created,
|
|
4939
4843
|
directory: spec.directory,
|
|
4940
4844
|
// The lock is released when this stream finishes draining.
|
|
4941
|
-
events: releaseAfter(
|
|
4845
|
+
events: releaseAfter(
|
|
4846
|
+
approvePermissions(
|
|
4847
|
+
parseSseStream(eventRes.body, sessionId, signal),
|
|
4848
|
+
(ev) => replyToPermission(doFetch, url, ev, signal)
|
|
4849
|
+
),
|
|
4850
|
+
release
|
|
4851
|
+
)
|
|
4942
4852
|
};
|
|
4943
4853
|
} catch (err) {
|
|
4944
4854
|
release();
|
|
@@ -4959,16 +4869,16 @@ var SCRUBBED_MCP_CONFIG = {
|
|
|
4959
4869
|
url: "http://127.0.0.1:9/cabane-removed",
|
|
4960
4870
|
enabled: false
|
|
4961
4871
|
};
|
|
4962
|
-
async function installMcp(doFetch,
|
|
4872
|
+
async function installMcp(doFetch, url, spec, signal) {
|
|
4963
4873
|
const [live, configured] = await Promise.all([
|
|
4964
|
-
getJson(doFetch,
|
|
4965
|
-
getJson(doFetch,
|
|
4874
|
+
getJson(doFetch, url("/mcp"), signal),
|
|
4875
|
+
getJson(doFetch, url("/config"), signal)
|
|
4966
4876
|
]);
|
|
4967
4877
|
const operatorOwned = new Set(Object.keys(asRecord2(asRecord2(configured).mcp)));
|
|
4968
4878
|
const stale = Object.keys(asRecord2(live)).filter(
|
|
4969
4879
|
(name) => !(name in spec.mcp) && !operatorOwned.has(name)
|
|
4970
4880
|
);
|
|
4971
|
-
await Promise.all(stale.map((name) => postMcp(doFetch,
|
|
4881
|
+
await Promise.all(stale.map((name) => postMcp(doFetch, url, name, SCRUBBED_MCP_CONFIG, signal)));
|
|
4972
4882
|
const shadowing = (spec.credentialServers ?? []).filter((name) => operatorOwned.has(name));
|
|
4973
4883
|
if (shadowing.length > 0) {
|
|
4974
4884
|
throw new Error(
|
|
@@ -4976,11 +4886,11 @@ async function installMcp(doFetch, base, spec, signal) {
|
|
|
4976
4886
|
);
|
|
4977
4887
|
}
|
|
4978
4888
|
await Promise.all(
|
|
4979
|
-
Object.entries(spec.mcp).map(([name, config]) => postMcp(doFetch,
|
|
4889
|
+
Object.entries(spec.mcp).map(([name, config]) => postMcp(doFetch, url, name, config, signal))
|
|
4980
4890
|
);
|
|
4981
4891
|
}
|
|
4982
|
-
async function postMcp(doFetch,
|
|
4983
|
-
const res = await doFetch(
|
|
4892
|
+
async function postMcp(doFetch, url, name, config, signal) {
|
|
4893
|
+
const res = await doFetch(url("/mcp"), {
|
|
4984
4894
|
method: "POST",
|
|
4985
4895
|
headers: { "content-type": "application/json" },
|
|
4986
4896
|
body: JSON.stringify({ name, config }),
|
|
@@ -5044,6 +4954,33 @@ function belongsToSession(ev, sessionId) {
|
|
|
5044
4954
|
if (typeof infoSid === "string") return infoSid === sessionId;
|
|
5045
4955
|
return true;
|
|
5046
4956
|
}
|
|
4957
|
+
async function* approvePermissions(events, reply2) {
|
|
4958
|
+
for await (const ev of events) {
|
|
4959
|
+
if (ev.type === "permission.asked" || ev.type === "permission.v2.asked") await reply2(ev);
|
|
4960
|
+
yield ev;
|
|
4961
|
+
}
|
|
4962
|
+
}
|
|
4963
|
+
async function replyToPermission(doFetch, url, ev, signal) {
|
|
4964
|
+
const props = asRecord2(ev.properties);
|
|
4965
|
+
const id = typeof props.id === "string" ? props.id : null;
|
|
4966
|
+
const sessionId = typeof props.sessionID === "string" ? props.sessionID : null;
|
|
4967
|
+
if (!id) throw new Error(`opencode: ${ev.type} carried no request id`);
|
|
4968
|
+
const target = ev.type === "permission.v2.asked" && sessionId ? url(
|
|
4969
|
+
`/api/session/${encodeURIComponent(sessionId)}/permission/${encodeURIComponent(id)}/reply`,
|
|
4970
|
+
{ unscoped: true }
|
|
4971
|
+
) : url(`/permission/${encodeURIComponent(id)}/reply`);
|
|
4972
|
+
const res = await doFetch(target, {
|
|
4973
|
+
method: "POST",
|
|
4974
|
+
headers: { "content-type": "application/json" },
|
|
4975
|
+
body: JSON.stringify({ reply: "once" }),
|
|
4976
|
+
signal
|
|
4977
|
+
});
|
|
4978
|
+
if (!res.ok) throw new Error(`opencode: permission reply failed (HTTP ${res.status})`);
|
|
4979
|
+
}
|
|
4980
|
+
function scopedUrl(base, directory) {
|
|
4981
|
+
const scope = directory ? `directory=${encodeURIComponent(directory)}` : "";
|
|
4982
|
+
return (path, opts) => scope && !opts?.unscoped ? `${base}${path}${path.includes("?") ? "&" : "?"}${scope}` : base + path;
|
|
4983
|
+
}
|
|
5047
4984
|
function trimSlash(s) {
|
|
5048
4985
|
return s.endsWith("/") ? s.slice(0, -1) : s;
|
|
5049
4986
|
}
|
|
@@ -5106,15 +5043,6 @@ var opencodeAdapter = createOpencodeAdapter();
|
|
|
5106
5043
|
var ABORT_SENTINEL2 = { __abortHere: true };
|
|
5107
5044
|
var NEW_SESSION_ID = "sess_new";
|
|
5108
5045
|
var BOUNDED_NOTICE = "You've hit your usage limit \xB7 ".padEnd(200, "x");
|
|
5109
|
-
var COMPANION_POLICY = {
|
|
5110
|
-
hostFs: false,
|
|
5111
|
-
web: true,
|
|
5112
|
-
browser: true,
|
|
5113
|
-
userMcp: true,
|
|
5114
|
-
subagents: false,
|
|
5115
|
-
scheduling: "never",
|
|
5116
|
-
uiPrompts: "never"
|
|
5117
|
-
};
|
|
5118
5046
|
var DIR = "/env/here";
|
|
5119
5047
|
function makeRequest2(overrides2 = {}) {
|
|
5120
5048
|
return {
|
|
@@ -5122,7 +5050,6 @@ function makeRequest2(overrides2 = {}) {
|
|
|
5122
5050
|
prompt: "hi there",
|
|
5123
5051
|
content: [{ type: "text", text: "hi there" }],
|
|
5124
5052
|
config: { model: "deepseek/deepseek-chat" },
|
|
5125
|
-
policy: COMPANION_POLICY,
|
|
5126
5053
|
session: null,
|
|
5127
5054
|
cabane: { mcpUrl: "https://cabane.test/api/mcp", bearer: "tok", activeConversationId: "conv" },
|
|
5128
5055
|
local: { cwd: DIR },
|
|
@@ -5928,27 +5855,13 @@ function sealHeld2(held, terminal) {
|
|
|
5928
5855
|
}
|
|
5929
5856
|
|
|
5930
5857
|
// packages/agent-runtime/src/codex/policy.ts
|
|
5931
|
-
import { z as
|
|
5932
|
-
function
|
|
5933
|
-
return
|
|
5934
|
-
sandboxMode: "danger-full-access",
|
|
5935
|
-
// Headless: nothing to approve, because nothing is denied.
|
|
5936
|
-
approvalPolicy: "never",
|
|
5937
|
-
// Full access means the command network is open regardless of the grant —
|
|
5938
|
-
// recorded as `true` so the value never claims a restriction that isn't
|
|
5939
|
-
// enforced.
|
|
5940
|
-
networkAccessEnabled: true
|
|
5941
|
-
} : {
|
|
5942
|
-
sandboxMode: "read-only",
|
|
5943
|
-
// Headless: the sandbox is the boundary; never pause for a human.
|
|
5944
|
-
approvalPolicy: "never",
|
|
5945
|
-
// Retained in the policy value for symmetry; read-only ignores it.
|
|
5946
|
-
networkAccessEnabled: policy.web
|
|
5947
|
-
};
|
|
5858
|
+
import { z as z12 } from "zod";
|
|
5859
|
+
function codexSandboxMode(local) {
|
|
5860
|
+
return local.codex?.configSetsSandboxMode ? null : "danger-full-access";
|
|
5948
5861
|
}
|
|
5949
5862
|
var CODEX_REASONING_EFFORTS = ["low", "medium", "high", "xhigh", "max", "ultra"];
|
|
5950
|
-
var codexDialectSchema =
|
|
5951
|
-
modelReasoningEffort:
|
|
5863
|
+
var codexDialectSchema = z12.object({
|
|
5864
|
+
modelReasoningEffort: z12.enum(CODEX_REASONING_EFFORTS).optional()
|
|
5952
5865
|
}).loose();
|
|
5953
5866
|
function readCodexDialect(runtimeOptions) {
|
|
5954
5867
|
const parsed = codexDialectSchema.safeParse(runtimeOptions?.["codex"] ?? {});
|
|
@@ -5972,14 +5885,12 @@ var ENV_ENVELOPE_KEYS = [
|
|
|
5972
5885
|
"CABANE_PLAYGROUND_BIN",
|
|
5973
5886
|
"CABANE_CONVERSATION_ID",
|
|
5974
5887
|
"CABANE_AGENT_ID",
|
|
5975
|
-
"CABANE_CONVERSATION_TITLE"
|
|
5976
|
-
"CABANE_HOST_ACCESS"
|
|
5888
|
+
"CABANE_CONVERSATION_TITLE"
|
|
5977
5889
|
];
|
|
5978
|
-
function buildRunSpec2(req, resumeThreadId,
|
|
5979
|
-
const {
|
|
5890
|
+
function buildRunSpec2(req, resumeThreadId, threadStanding = null, imagePaths = []) {
|
|
5891
|
+
const { config } = req;
|
|
5980
5892
|
const directory = req.local.cwd ?? "";
|
|
5981
5893
|
const dialect = readCodexDialect(config.runtimeOptions);
|
|
5982
|
-
const baseInstructionsFile = !policy.hostFs && instructionsFile ? instructionsFile : null;
|
|
5983
5894
|
const model = config.model ? parseCodexModel(config.model) : null;
|
|
5984
5895
|
const segments = standingSegments(req);
|
|
5985
5896
|
const conversationText = segments.conversation.trim();
|
|
@@ -5989,25 +5900,24 @@ function buildRunSpec2(req, resumeThreadId, instructionsFile = null, threadStand
|
|
|
5989
5900
|
};
|
|
5990
5901
|
const resumed = resumeThreadId !== null;
|
|
5991
5902
|
const held = resumed ? threadStanding : null;
|
|
5992
|
-
const viaInput = baseInstructionsFile === null;
|
|
5993
5903
|
const preamble = {
|
|
5994
|
-
core:
|
|
5904
|
+
core: (held?.core ?? null) !== fingerprints.core,
|
|
5995
5905
|
// Compared both ways: a held segment that is now empty differs from it, and nothing held
|
|
5996
5906
|
// equals nothing to send.
|
|
5997
|
-
conversation:
|
|
5907
|
+
conversation: (held?.conversation ?? null) !== fingerprints.conversation
|
|
5998
5908
|
};
|
|
5999
5909
|
return {
|
|
6000
5910
|
resumeThreadId,
|
|
6001
5911
|
directory,
|
|
6002
5912
|
model,
|
|
6003
|
-
|
|
5913
|
+
sandboxMode: codexSandboxMode(req.local),
|
|
5914
|
+
approvalPolicy: "never",
|
|
6004
5915
|
skipGitRepoCheck: true,
|
|
6005
5916
|
...dialect.modelReasoningEffort ? { modelReasoningEffort: dialect.modelReasoningEffort } : {},
|
|
6006
|
-
baseInstructionsFile,
|
|
6007
5917
|
input: withImages(buildInput(req, segments, preamble, resumed), imagePaths),
|
|
6008
5918
|
preamble,
|
|
6009
5919
|
fingerprints,
|
|
6010
|
-
config: buildConfig(req
|
|
5920
|
+
config: buildConfig(req),
|
|
6011
5921
|
secretEnv: codexSecretEnv(req)
|
|
6012
5922
|
};
|
|
6013
5923
|
}
|
|
@@ -6052,7 +5962,7 @@ function withImages(text, imagePaths) {
|
|
|
6052
5962
|
...imagePaths.map((path) => ({ type: "local_image", path }))
|
|
6053
5963
|
];
|
|
6054
5964
|
}
|
|
6055
|
-
function buildConfig(req
|
|
5965
|
+
function buildConfig(req) {
|
|
6056
5966
|
const mcp_servers = {};
|
|
6057
5967
|
for (const [name, server] of Object.entries(req.local.mcpServers ?? {})) {
|
|
6058
5968
|
if ("url" in server) {
|
|
@@ -6118,9 +6028,6 @@ function buildConfig(req, baseInstructionsFile) {
|
|
|
6118
6028
|
return {
|
|
6119
6029
|
mcp_servers,
|
|
6120
6030
|
experimental_use_rmcp_client: true,
|
|
6121
|
-
// The no-host-access prompt replacement — Cabane's composed prompt becomes Codex's base
|
|
6122
|
-
// instructions, and Codex's environment preamble goes with the harness prompt it belonged to.
|
|
6123
|
-
...baseInstructionsFile ? { model_instructions_file: baseInstructionsFile, include_environment_context: false } : {},
|
|
6124
6031
|
...Object.keys(shellEnv).length ? { shell_environment_policy: { set: shellEnv } } : {}
|
|
6125
6032
|
};
|
|
6126
6033
|
}
|
|
@@ -6196,10 +6103,10 @@ function buildConfigOverrides(config) {
|
|
|
6196
6103
|
function buildSdkThreadOptions(spec) {
|
|
6197
6104
|
return {
|
|
6198
6105
|
...spec.model ? { model: spec.model } : {},
|
|
6199
|
-
sandboxMode: spec.
|
|
6106
|
+
...spec.sandboxMode ? { sandboxMode: spec.sandboxMode } : {},
|
|
6200
6107
|
workingDirectory: spec.directory,
|
|
6201
6108
|
skipGitRepoCheck: spec.skipGitRepoCheck,
|
|
6202
|
-
approvalPolicy: spec.
|
|
6109
|
+
approvalPolicy: spec.approvalPolicy,
|
|
6203
6110
|
...spec.modelReasoningEffort ? { modelReasoningEffort: spec.modelReasoningEffort } : {}
|
|
6204
6111
|
};
|
|
6205
6112
|
}
|
|
@@ -6295,23 +6202,6 @@ function createCodexAdapter(deps = {}) {
|
|
|
6295
6202
|
);
|
|
6296
6203
|
}
|
|
6297
6204
|
}
|
|
6298
|
-
let instructions = null;
|
|
6299
|
-
if (!req.policy.hostFs) {
|
|
6300
|
-
if (!deps.writeInstructionsFile) {
|
|
6301
|
-
deps.onWarn?.(
|
|
6302
|
-
"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)"
|
|
6303
|
-
);
|
|
6304
|
-
} else {
|
|
6305
|
-
try {
|
|
6306
|
-
instructions = await deps.writeInstructionsFile(req.systemPrompt);
|
|
6307
|
-
} catch (err) {
|
|
6308
|
-
deps.onWarn?.(
|
|
6309
|
-
"codex adapter: failed to write the per-turn instructions file \u2014 falling back to the input preamble (CT871)",
|
|
6310
|
-
{ err: err instanceof Error ? err.message : String(err) }
|
|
6311
|
-
);
|
|
6312
|
-
}
|
|
6313
|
-
}
|
|
6314
|
-
}
|
|
6315
6205
|
let images = null;
|
|
6316
6206
|
try {
|
|
6317
6207
|
const imageUrls = req.content.flatMap((b) => b.type === "image" ? [b.source.url] : []);
|
|
@@ -6335,13 +6225,7 @@ function createCodexAdapter(deps = {}) {
|
|
|
6335
6225
|
}
|
|
6336
6226
|
if (signal.aborted) return;
|
|
6337
6227
|
}
|
|
6338
|
-
const spec = buildRunSpec2(
|
|
6339
|
-
req,
|
|
6340
|
-
resumeThreadId,
|
|
6341
|
-
instructions?.path ?? null,
|
|
6342
|
-
threadStanding,
|
|
6343
|
-
images?.paths ?? []
|
|
6344
|
-
);
|
|
6228
|
+
const spec = buildRunSpec2(req, resumeThreadId, threadStanding, images?.paths ?? []);
|
|
6345
6229
|
if (spec.model === null) {
|
|
6346
6230
|
deps.onWarn?.("Codex is using its default model because no model was resolved", {
|
|
6347
6231
|
model: req.config.model
|
|
@@ -6383,15 +6267,6 @@ function createCodexAdapter(deps = {}) {
|
|
|
6383
6267
|
});
|
|
6384
6268
|
}
|
|
6385
6269
|
}
|
|
6386
|
-
if (instructions) {
|
|
6387
|
-
try {
|
|
6388
|
-
await instructions.cleanup();
|
|
6389
|
-
} catch (err) {
|
|
6390
|
-
deps.onWarn?.("codex adapter: instructions-file cleanup failed (CT871)", {
|
|
6391
|
-
err: err instanceof Error ? err.message : String(err)
|
|
6392
|
-
});
|
|
6393
|
-
}
|
|
6394
|
-
}
|
|
6395
6270
|
}
|
|
6396
6271
|
}
|
|
6397
6272
|
};
|
|
@@ -6402,15 +6277,6 @@ var codexAdapter = createCodexAdapter();
|
|
|
6402
6277
|
var ABORT_SENTINEL3 = { __abortHere: true };
|
|
6403
6278
|
var NEW_THREAD_ID = "th_new";
|
|
6404
6279
|
var BOUNDED_NOTICE2 = "You've hit your usage limit \xB7 ".padEnd(200, "x");
|
|
6405
|
-
var COMPANION_POLICY2 = {
|
|
6406
|
-
hostFs: false,
|
|
6407
|
-
web: true,
|
|
6408
|
-
browser: true,
|
|
6409
|
-
userMcp: true,
|
|
6410
|
-
subagents: false,
|
|
6411
|
-
scheduling: "never",
|
|
6412
|
-
uiPrompts: "never"
|
|
6413
|
-
};
|
|
6414
6280
|
var DIR2 = "/env/here";
|
|
6415
6281
|
var PROMPT = "system";
|
|
6416
6282
|
function makeRequest3(overrides2 = {}) {
|
|
@@ -6422,7 +6288,6 @@ function makeRequest3(overrides2 = {}) {
|
|
|
6422
6288
|
// Behavioural fixtures use the model-less token (no `resolvedModel` emitted); a dedicated capture
|
|
6423
6289
|
// fixture sets a real model and effort.
|
|
6424
6290
|
config: { model: null },
|
|
6425
|
-
policy: COMPANION_POLICY2,
|
|
6426
6291
|
session: null,
|
|
6427
6292
|
cabane: { mcpUrl: "https://cabane.test/api/mcp", bearer: "tok", activeConversationId: "conv" },
|
|
6428
6293
|
local: { cwd: DIR2 },
|
|
@@ -7454,52 +7319,47 @@ function classifyStopError(message) {
|
|
|
7454
7319
|
}
|
|
7455
7320
|
|
|
7456
7321
|
// src/runner/protocol.ts
|
|
7457
|
-
import { z as
|
|
7322
|
+
import { z as z14 } from "zod";
|
|
7458
7323
|
|
|
7459
7324
|
// src/run-config.ts
|
|
7460
|
-
import { z as
|
|
7461
|
-
var mcpStdioServerSchema =
|
|
7462
|
-
type:
|
|
7463
|
-
command:
|
|
7464
|
-
args:
|
|
7465
|
-
env:
|
|
7325
|
+
import { z as z13 } from "zod";
|
|
7326
|
+
var mcpStdioServerSchema = z13.object({
|
|
7327
|
+
type: z13.literal("stdio").optional(),
|
|
7328
|
+
command: z13.string().min(1),
|
|
7329
|
+
args: z13.array(z13.string()).optional(),
|
|
7330
|
+
env: z13.record(z13.string(), z13.string()).optional(),
|
|
7466
7331
|
// Variable → the name of a `secretEnv` entry holding its value. Set by the server on a
|
|
7467
7332
|
// room's shared browser, whose connect URL is a credential.
|
|
7468
|
-
envFromEnv:
|
|
7333
|
+
envFromEnv: z13.record(z13.string(), z13.string()).optional()
|
|
7469
7334
|
});
|
|
7470
|
-
var mcpHttpServerSchema =
|
|
7471
|
-
type:
|
|
7472
|
-
url:
|
|
7473
|
-
headers:
|
|
7335
|
+
var mcpHttpServerSchema = z13.object({
|
|
7336
|
+
type: z13.literal("http"),
|
|
7337
|
+
url: z13.string().url(),
|
|
7338
|
+
headers: z13.record(z13.string(), z13.string()).optional(),
|
|
7474
7339
|
// Header → the name of a `secretEnv` entry holding its value. Set by
|
|
7475
7340
|
// the server on a room connection's entry, and by `resolveMcpSecrets` on a
|
|
7476
7341
|
// header whose `${VAR}` it resolved.
|
|
7477
|
-
headersFromEnv:
|
|
7342
|
+
headersFromEnv: z13.record(z13.string(), z13.string()).optional()
|
|
7478
7343
|
});
|
|
7479
|
-
var mcpSseServerSchema =
|
|
7480
|
-
type:
|
|
7481
|
-
url:
|
|
7482
|
-
headers:
|
|
7344
|
+
var mcpSseServerSchema = z13.object({
|
|
7345
|
+
type: z13.literal("sse"),
|
|
7346
|
+
url: z13.string().url(),
|
|
7347
|
+
headers: z13.record(z13.string(), z13.string()).optional(),
|
|
7483
7348
|
// Header → the name of a `secretEnv` entry holding its value. Set by
|
|
7484
7349
|
// the server on a room connection's entry, and by `resolveMcpSecrets` on a
|
|
7485
7350
|
// header whose `${VAR}` it resolved.
|
|
7486
|
-
headersFromEnv:
|
|
7351
|
+
headersFromEnv: z13.record(z13.string(), z13.string()).optional()
|
|
7487
7352
|
});
|
|
7488
|
-
var mcpServerDefSchema =
|
|
7489
|
-
var thinkingConfigSchema =
|
|
7490
|
-
|
|
7491
|
-
|
|
7492
|
-
|
|
7353
|
+
var mcpServerDefSchema = z13.union([mcpHttpServerSchema, mcpSseServerSchema, mcpStdioServerSchema]);
|
|
7354
|
+
var thinkingConfigSchema = z13.discriminatedUnion("type", [
|
|
7355
|
+
z13.object({ type: z13.literal("adaptive") }),
|
|
7356
|
+
z13.object({ type: z13.literal("enabled"), budgetTokens: z13.number().int().positive().optional() }),
|
|
7357
|
+
z13.object({ type: z13.literal("disabled") })
|
|
7493
7358
|
]);
|
|
7494
|
-
var effortSchema =
|
|
7495
|
-
var runConfigSchema =
|
|
7496
|
-
|
|
7497
|
-
|
|
7498
|
-
// `agentRunConfigSchema` (independent zod, forward-compatible: unknown keys are
|
|
7499
|
-
// stripped, so an older companion riding a newer server never rejects the config).
|
|
7500
|
-
hostAccess: z14.boolean().optional(),
|
|
7501
|
-
mcpServers: z14.record(z14.string(), mcpServerDefSchema).optional(),
|
|
7502
|
-
model: z14.string().min(1).optional(),
|
|
7359
|
+
var effortSchema = z13.enum(["low", "medium", "high", "xhigh", "max"]);
|
|
7360
|
+
var runConfigSchema = z13.object({
|
|
7361
|
+
mcpServers: z13.record(z13.string(), mcpServerDefSchema).optional(),
|
|
7362
|
+
model: z13.string().min(1).optional(),
|
|
7503
7363
|
thinking: thinkingConfigSchema.optional(),
|
|
7504
7364
|
effort: effortSchema.optional()
|
|
7505
7365
|
});
|
|
@@ -7527,56 +7387,56 @@ var RUNNER_ENV = {
|
|
|
7527
7387
|
// Everything else the turn is constructed from, as JSON: see `RunnerSpec`.
|
|
7528
7388
|
spec: "CABANE_RUNNER_SPEC"
|
|
7529
7389
|
};
|
|
7530
|
-
var runtimeHealthSchema =
|
|
7531
|
-
quotaState:
|
|
7532
|
-
limitedUntil:
|
|
7533
|
-
lastError:
|
|
7390
|
+
var runtimeHealthSchema = z14.object({
|
|
7391
|
+
quotaState: z14.enum(["ok", "limited", "auth_expired", "unknown"]),
|
|
7392
|
+
limitedUntil: z14.string().nullable(),
|
|
7393
|
+
lastError: z14.string().nullable()
|
|
7534
7394
|
});
|
|
7535
|
-
var runnerSpecSchema =
|
|
7536
|
-
deviceId:
|
|
7395
|
+
var runnerSpecSchema = z14.object({
|
|
7396
|
+
deviceId: z14.string().optional(),
|
|
7537
7397
|
// The launcher's boot id: the one its heartbeat carries, so a runner's lease
|
|
7538
7398
|
// matches the device that holds it.
|
|
7539
|
-
bootId:
|
|
7540
|
-
workspaceId:
|
|
7541
|
-
workspaceSlug:
|
|
7542
|
-
agentId:
|
|
7543
|
-
agentUsername:
|
|
7544
|
-
agentName:
|
|
7399
|
+
bootId: z14.string(),
|
|
7400
|
+
workspaceId: z14.string(),
|
|
7401
|
+
workspaceSlug: z14.string(),
|
|
7402
|
+
agentId: z14.string(),
|
|
7403
|
+
agentUsername: z14.string(),
|
|
7404
|
+
agentName: z14.string(),
|
|
7545
7405
|
local: localAgentConfigSchema,
|
|
7546
7406
|
runConfig: runConfigSchema,
|
|
7547
7407
|
// The device's `root`, resolved by the launcher: the pair directory the turn
|
|
7548
7408
|
// stands in when nothing else names one lives under it (`work-dir.ts`).
|
|
7549
|
-
workRoot:
|
|
7550
|
-
opencodeServerUrl:
|
|
7551
|
-
claudeCodeAvailable:
|
|
7552
|
-
codexAvailable:
|
|
7553
|
-
idleTimeoutMs:
|
|
7554
|
-
totalTimeoutMs:
|
|
7555
|
-
leaseRenewalMs:
|
|
7556
|
-
preparingRowDelayMs:
|
|
7409
|
+
workRoot: z14.string(),
|
|
7410
|
+
opencodeServerUrl: z14.string().optional(),
|
|
7411
|
+
claudeCodeAvailable: z14.boolean(),
|
|
7412
|
+
codexAvailable: z14.boolean(),
|
|
7413
|
+
idleTimeoutMs: z14.number().int().positive().optional(),
|
|
7414
|
+
totalTimeoutMs: z14.number().int().positive().optional(),
|
|
7415
|
+
leaseRenewalMs: z14.number().int().positive().optional(),
|
|
7416
|
+
preparingRowDelayMs: z14.number().int().nonnegative().optional(),
|
|
7557
7417
|
// Whether the turn writes a transcript, into the device's own directory
|
|
7558
7418
|
// (`transcriptsDir()`).
|
|
7559
|
-
transcripts:
|
|
7560
|
-
logLevel:
|
|
7419
|
+
transcripts: z14.boolean(),
|
|
7420
|
+
logLevel: z14.string(),
|
|
7561
7421
|
// The launcher's connector-health observations, by runtime, as of the start.
|
|
7562
|
-
connectorHealth:
|
|
7422
|
+
connectorHealth: z14.record(z14.string(), runtimeHealthSchema),
|
|
7563
7423
|
// True when this (conversation, agent) pair was already told its session
|
|
7564
7424
|
// could not be saved: the notice is once per pair, not once per process.
|
|
7565
|
-
sessionWriteNoticeClaimed:
|
|
7425
|
+
sessionWriteNoticeClaimed: z14.boolean(),
|
|
7566
7426
|
// The runner's identity, minted with its credential. The start
|
|
7567
7427
|
// PATCH carries it so the lease knows which runner holds the span.
|
|
7568
|
-
runnerId:
|
|
7428
|
+
runnerId: z14.string()
|
|
7569
7429
|
});
|
|
7570
|
-
var dispatchSchema =
|
|
7571
|
-
type:
|
|
7572
|
-
agentId:
|
|
7573
|
-
deviceId:
|
|
7574
|
-
conversationId:
|
|
7575
|
-
messageId:
|
|
7576
|
-
episode:
|
|
7430
|
+
var dispatchSchema = z14.object({
|
|
7431
|
+
type: z14.literal("device:dispatch_requested"),
|
|
7432
|
+
agentId: z14.string(),
|
|
7433
|
+
deviceId: z14.string(),
|
|
7434
|
+
conversationId: z14.string(),
|
|
7435
|
+
messageId: z14.string(),
|
|
7436
|
+
episode: z14.number().int().optional()
|
|
7577
7437
|
});
|
|
7578
|
-
var credentialsSchema =
|
|
7579
|
-
credential:
|
|
7438
|
+
var credentialsSchema = z14.object({
|
|
7439
|
+
credential: z14.string().startsWith("cabrn_")
|
|
7580
7440
|
});
|
|
7581
7441
|
function runnerEnv(input) {
|
|
7582
7442
|
return {
|
|
@@ -7965,7 +7825,7 @@ import { join as join13 } from "path";
|
|
|
7965
7825
|
|
|
7966
7826
|
// src/turn-control-tools.ts
|
|
7967
7827
|
import { randomUUID as randomUUID2 } from "crypto";
|
|
7968
|
-
import { z as
|
|
7828
|
+
import { z as z15 } from "zod";
|
|
7969
7829
|
var COMPANION_LOCAL_MCP_SERVER = "cabane_companion";
|
|
7970
7830
|
var COMPANION_LOCAL_TOOL_GLOB = `mcp__${COMPANION_LOCAL_MCP_SERVER}__*`;
|
|
7971
7831
|
var ASK_TOOL = "ask";
|
|
@@ -7977,20 +7837,21 @@ var WAKE_ME_TOOL_NAME = `mcp__${COMPANION_LOCAL_MCP_SERVER}__${WAKE_ME_TOOL}`;
|
|
|
7977
7837
|
var CANCEL_WAKE_TOOL = "cancel_wake";
|
|
7978
7838
|
var CANCEL_WAKE_TOOL_NAME = `mcp__${COMPANION_LOCAL_MCP_SERVER}__${CANCEL_WAKE_TOOL}`;
|
|
7979
7839
|
|
|
7980
|
-
// src/codex-
|
|
7981
|
-
import {
|
|
7982
|
-
import {
|
|
7840
|
+
// src/codex-config.ts
|
|
7841
|
+
import { readFile as readFile2 } from "fs/promises";
|
|
7842
|
+
import { homedir as homedir6 } from "os";
|
|
7983
7843
|
import { join as join14 } from "path";
|
|
7844
|
+
import { parse } from "smol-toml";
|
|
7984
7845
|
|
|
7985
7846
|
// src/codex-images.ts
|
|
7986
|
-
import { mkdtemp
|
|
7987
|
-
import { tmpdir
|
|
7847
|
+
import { mkdtemp, rm, writeFile } from "fs/promises";
|
|
7848
|
+
import { tmpdir } from "os";
|
|
7988
7849
|
import { join as join15 } from "path";
|
|
7989
7850
|
|
|
7990
7851
|
// src/codex-compactions.ts
|
|
7991
7852
|
import { createReadStream } from "fs";
|
|
7992
7853
|
import { readdir } from "fs/promises";
|
|
7993
|
-
import { homedir as
|
|
7854
|
+
import { homedir as homedir7 } from "os";
|
|
7994
7855
|
import { join as join16 } from "path";
|
|
7995
7856
|
import { createInterface as createInterface2 } from "readline";
|
|
7996
7857
|
|
|
@@ -8005,12 +7866,12 @@ import { join as join17 } from "path";
|
|
|
8005
7866
|
// src/secrets.ts
|
|
8006
7867
|
import { existsSync as existsSync10, readFileSync as readFileSync8 } from "fs";
|
|
8007
7868
|
import { join as join18 } from "path";
|
|
8008
|
-
import { z as
|
|
7869
|
+
import { z as z16 } from "zod";
|
|
8009
7870
|
var PLACEHOLDER_RE = /\$\{([A-Za-z_][A-Za-z0-9_]*)\}/g;
|
|
8010
7871
|
function secretsPath() {
|
|
8011
7872
|
return join18(cabaneDir(), "secrets.json");
|
|
8012
7873
|
}
|
|
8013
|
-
var secretStoreSchema =
|
|
7874
|
+
var secretStoreSchema = z16.record(z16.string(), z16.string());
|
|
8014
7875
|
function loadSecretStore() {
|
|
8015
7876
|
const path = secretsPath();
|
|
8016
7877
|
if (!existsSync10(path)) return makeStore({});
|
|
@@ -8361,7 +8222,7 @@ var DeviceLocks = class {
|
|
|
8361
8222
|
// src/manifest.ts
|
|
8362
8223
|
var DEVICE_MANIFEST = {
|
|
8363
8224
|
runtimes: [{ name: "claude-code", version: null }],
|
|
8364
|
-
capabilities: {
|
|
8225
|
+
capabilities: { browser: true, userMcp: true }
|
|
8365
8226
|
};
|
|
8366
8227
|
function buildCompanionManifest(opts) {
|
|
8367
8228
|
const v = opts.versions ?? {};
|
|
@@ -8465,7 +8326,7 @@ function emptyHarnessVersions() {
|
|
|
8465
8326
|
}
|
|
8466
8327
|
|
|
8467
8328
|
// src/harness-copy.ts
|
|
8468
|
-
import { homedir as
|
|
8329
|
+
import { homedir as homedir8 } from "os";
|
|
8469
8330
|
import { join as join21 } from "path";
|
|
8470
8331
|
var HARNESS_LABELS = {
|
|
8471
8332
|
"claude-code": "Claude Code",
|
|
@@ -8480,7 +8341,7 @@ function failureText(runtime, reason) {
|
|
|
8480
8341
|
case "spawn":
|
|
8481
8342
|
return `Couldn't check whether ${label} is signed in: Cabane's bundled ${label} wouldn't start. Repair it with ${repairSteps()} and try again.${spaced(repairCost())}`;
|
|
8482
8343
|
case "config":
|
|
8483
|
-
return `Couldn't check whether ${label} is signed in: its configuration file didn't load${runtime === "codex" ? ` (${tildePath(join21(
|
|
8344
|
+
return `Couldn't check whether ${label} is signed in: its configuration file didn't load${runtime === "codex" ? ` (${tildePath(join21(homedir8(), ".codex", "config.toml"))})` : ""}. Fix it, then try again.`;
|
|
8484
8345
|
case "unreadable":
|
|
8485
8346
|
return `Couldn't check whether ${label} is signed in: it answered in a way Cabane couldn't read. Try again, and if it keeps happening, update Cabane.`;
|
|
8486
8347
|
}
|
|
@@ -9227,27 +9088,27 @@ function compareVersions(a, b) {
|
|
|
9227
9088
|
// src/update-state.ts
|
|
9228
9089
|
import { mkdirSync as mkdirSync13, readFileSync as readFileSync13, renameSync as renameSync8, writeFileSync as writeFileSync8 } from "fs";
|
|
9229
9090
|
import { dirname as dirname10, join as join25 } from "path";
|
|
9230
|
-
import { z as
|
|
9231
|
-
var resultSchema =
|
|
9232
|
-
kind:
|
|
9233
|
-
from:
|
|
9234
|
-
to:
|
|
9235
|
-
at:
|
|
9236
|
-
reason:
|
|
9091
|
+
import { z as z17 } from "zod";
|
|
9092
|
+
var resultSchema = z17.object({
|
|
9093
|
+
kind: z17.enum(["updated", "rolled_back", "failed"]),
|
|
9094
|
+
from: z17.string(),
|
|
9095
|
+
to: z17.string(),
|
|
9096
|
+
at: z17.string(),
|
|
9097
|
+
reason: z17.string().optional()
|
|
9237
9098
|
});
|
|
9238
|
-
var pendingSchema =
|
|
9239
|
-
from:
|
|
9099
|
+
var pendingSchema = z17.object({
|
|
9100
|
+
from: z17.string(),
|
|
9240
9101
|
// The package root `current` pointed at before the swap, so a rollback can point it back.
|
|
9241
|
-
fromRoot:
|
|
9242
|
-
to:
|
|
9243
|
-
at:
|
|
9244
|
-
boots:
|
|
9102
|
+
fromRoot: z17.string(),
|
|
9103
|
+
to: z17.string(),
|
|
9104
|
+
at: z17.string(),
|
|
9105
|
+
boots: z17.number().int().nonnegative()
|
|
9245
9106
|
});
|
|
9246
|
-
var stateSchema =
|
|
9247
|
-
server:
|
|
9107
|
+
var stateSchema = z17.object({
|
|
9108
|
+
server: z17.object({ latest: z17.string(), minimum: z17.string(), at: z17.string() }).optional(),
|
|
9248
9109
|
pending: pendingSchema.optional(),
|
|
9249
9110
|
lastResult: resultSchema.optional(),
|
|
9250
|
-
failed:
|
|
9111
|
+
failed: z17.object({ version: z17.string(), attempts: z17.number().int(), at: z17.string() }).optional()
|
|
9251
9112
|
});
|
|
9252
9113
|
function updateStatePath(dir2 = cabaneDir()) {
|
|
9253
9114
|
return join25(dir2, "update.json");
|
|
@@ -10143,7 +10004,6 @@ var CompanionSupervisor = class {
|
|
|
10143
10004
|
agentId: it.agentId,
|
|
10144
10005
|
username: it.agentUsername,
|
|
10145
10006
|
displayName: it.agentDisplayName,
|
|
10146
|
-
mode: runConfig.hostAccess ? "full" : "none",
|
|
10147
10007
|
hasCredential: false,
|
|
10148
10008
|
missingSecrets: missing
|
|
10149
10009
|
});
|
|
@@ -10163,7 +10023,6 @@ var CompanionSupervisor = class {
|
|
|
10163
10023
|
agentId: it.agentId,
|
|
10164
10024
|
username: it.agentUsername,
|
|
10165
10025
|
displayName: it.agentDisplayName,
|
|
10166
|
-
mode: runConfig.hostAccess ? "full" : "none",
|
|
10167
10026
|
hasCredential: true,
|
|
10168
10027
|
missingSecrets: missing
|
|
10169
10028
|
});
|