@edspencer/paddock 0.61.0 → 0.62.0
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 +36 -4
- package/package.json +1 -1
- package/packages/server/dist/agent-errors.d.ts +41 -0
- package/packages/server/dist/agent-errors.js +127 -0
- package/packages/server/dist/app.js +57 -9
- package/packages/server/dist/claude-credentials.d.ts +116 -0
- package/packages/server/dist/claude-credentials.js +103 -0
- package/packages/server/dist/claude-home.d.ts +164 -25
- package/packages/server/dist/claude-home.js +528 -77
- package/packages/server/dist/claude-instructions.d.ts +121 -0
- package/packages/server/dist/claude-instructions.js +114 -0
- package/packages/server/dist/claude-mcp.d.ts +146 -0
- package/packages/server/dist/claude-mcp.js +367 -0
- package/packages/server/dist/claude-settings.d.ts +159 -0
- package/packages/server/dist/claude-settings.js +159 -0
- package/packages/server/dist/cli/args.d.ts +1 -1
- package/packages/server/dist/cli/args.js +39 -5
- package/packages/server/dist/cli/paddock.js +30 -6
- package/packages/server/dist/config.d.ts +166 -30
- package/packages/server/dist/config.js +106 -26
- package/packages/server/dist/herdctl-agent-config.d.ts +11 -1
- package/packages/server/dist/herdctl-agent-config.js +53 -7
- package/packages/server/dist/herdctl-agent-names.d.ts +11 -0
- package/packages/server/dist/herdctl-agent-names.js +31 -0
- package/packages/server/dist/herdctl.d.ts +69 -13
- package/packages/server/dist/herdctl.js +70 -18
- package/packages/server/dist/instance-config.js +36 -0
- package/packages/server/dist/mcp-servers.d.ts +168 -0
- package/packages/server/dist/mcp-servers.js +305 -0
- package/packages/server/dist/routes/chats.js +10 -4
- package/packages/server/dist/sweep.js +13 -1
- package/packages/server/dist/transcripts.d.ts +62 -24
- package/packages/server/dist/transcripts.js +141 -28
- package/packages/server/package.json +1 -1
- package/packages/web/dist/assets/{InstanceConfigPage-CzMqTdUU.js → InstanceConfigPage-Ca905oey.js} +1 -1
- package/packages/web/dist/assets/{MarkdownRenderer-YSEZHWDe.js → MarkdownRenderer-ChlC1ezH.js} +1 -1
- package/packages/web/dist/assets/{ProjectRedirect-DLWxZbqK.js → ProjectRedirect-CslqbhUb.js} +1 -1
- package/packages/web/dist/assets/{ProjectView-BFX8ff2n.js → ProjectView-DkNdilGo.js} +3 -3
- package/packages/web/dist/assets/{ProjectsGrid-DLOeY_ww.js → ProjectsGrid-BrlvLc-Y.js} +1 -1
- package/packages/web/dist/assets/{arc-BwC1ik-b.js → arc-CGqCI5nQ.js} +1 -1
- package/packages/web/dist/assets/{architectureDiagram-3BPJPVTR-CsVvXQWw.js → architectureDiagram-3BPJPVTR-Cp4KTxE2.js} +1 -1
- package/packages/web/dist/assets/{blockDiagram-GPEHLZMM-DXQk2bIa.js → blockDiagram-GPEHLZMM-yFxaTv04.js} +1 -1
- package/packages/web/dist/assets/{c4Diagram-AAUBKEIU-DXiA26It.js → c4Diagram-AAUBKEIU-59lhWjRt.js} +1 -1
- package/packages/web/dist/assets/channel-CZs6Z1i5.js +2 -0
- package/packages/web/dist/assets/{chunk-2J33WTMH-Dt5nC02A.js → chunk-2J33WTMH-BrpXGnJg.js} +1 -1
- package/packages/web/dist/assets/{chunk-4BX2VUAB-DcjnWvl6.js → chunk-4BX2VUAB-UxBDb5pi.js} +1 -1
- package/packages/web/dist/assets/{chunk-55IACEB6-CRa3LkU4.js → chunk-55IACEB6-D4ZJyUHW.js} +1 -1
- package/packages/web/dist/assets/{chunk-727SXJPM-H3V-11qu.js → chunk-727SXJPM-DWdPj_8E.js} +1 -1
- package/packages/web/dist/assets/{chunk-AQP2D5EJ-DPCrENYV.js → chunk-AQP2D5EJ-BIpNbflY.js} +1 -1
- package/packages/web/dist/assets/{chunk-FMBD7UC4-C4UO0ZTc.js → chunk-FMBD7UC4-f6iJDfdI.js} +1 -1
- package/packages/web/dist/assets/{chunk-ND2GUHAM-BtI37CnI.js → chunk-ND2GUHAM-Bz3TKIJk.js} +1 -1
- package/packages/web/dist/assets/{chunk-QZHKN3VN-C5bTaK5j.js → chunk-QZHKN3VN-buQmkafK.js} +1 -1
- package/packages/web/dist/assets/classDiagram-4FO5ZUOK-CrbEUUCd.js +2 -0
- package/packages/web/dist/assets/classDiagram-v2-Q7XG4LA2-CrbEUUCd.js +2 -0
- package/packages/web/dist/assets/{core-DB3cpm5N.js → core-TyFI6p0n.js} +1 -1
- package/packages/web/dist/assets/{cose-bilkent-S5V4N54A-q-cjTZO4.js → cose-bilkent-S5V4N54A-CIkdi0XF.js} +1 -1
- package/packages/web/dist/assets/{dagre-BM42HDAG-DYEV5HFo.js → dagre-BM42HDAG-BnLJCfNs.js} +1 -1
- package/packages/web/dist/assets/{diagram-2AECGRRQ-D16XCw78.js → diagram-2AECGRRQ-D0OqfDB9.js} +1 -1
- package/packages/web/dist/assets/{diagram-5GNKFQAL-CeztryYE.js → diagram-5GNKFQAL-DQ2spGrK.js} +1 -1
- package/packages/web/dist/assets/{diagram-KO2AKTUF-D5SLIMDS.js → diagram-KO2AKTUF-RDIVQ_S3.js} +1 -1
- package/packages/web/dist/assets/{diagram-LMA3HP47-Bw-sVPxM.js → diagram-LMA3HP47-DKoTfh2C.js} +1 -1
- package/packages/web/dist/assets/{diagram-OG6HWLK6-DsRMITgx.js → diagram-OG6HWLK6-6k0OuSAL.js} +1 -1
- package/packages/web/dist/assets/{erDiagram-TEJ5UH35-T8Qqc_ku.js → erDiagram-TEJ5UH35-B-oQaYAC.js} +1 -1
- package/packages/web/dist/assets/{flowDiagram-I6XJVG4X-Cyx47UWU.js → flowDiagram-I6XJVG4X-B7qpYe9C.js} +1 -1
- package/packages/web/dist/assets/{format-D2I0duZa.js → format-PHdEBNOi.js} +1 -1
- package/packages/web/dist/assets/{ganttDiagram-6RSMTGT7-DxYJmG9o.js → ganttDiagram-6RSMTGT7-SfBsqMmx.js} +1 -1
- package/packages/web/dist/assets/{gitGraphDiagram-PVQCEYII-COK5YOTD.js → gitGraphDiagram-PVQCEYII-CuM4Rl_i.js} +1 -1
- package/packages/web/dist/assets/{index-wBXQMkGI.js → index-D_1ogxg1.js} +2 -2
- package/packages/web/dist/assets/{infoDiagram-5YYISTIA-BamRN_Nn.js → infoDiagram-5YYISTIA-Dq-32Oj4.js} +1 -1
- package/packages/web/dist/assets/{ishikawaDiagram-YF4QCWOH-DuOHdpEH.js → ishikawaDiagram-YF4QCWOH-BLFHCj_o.js} +1 -1
- package/packages/web/dist/assets/{journeyDiagram-JHISSGLW-Bri7GKTW.js → journeyDiagram-JHISSGLW-CHP-Yu63.js} +1 -1
- package/packages/web/dist/assets/{kanban-definition-UN3LZRKU-BdkgUnzI.js → kanban-definition-UN3LZRKU-DRuehSqn.js} +1 -1
- package/packages/web/dist/assets/{linear-DOcNPCpB.js → linear-Bwz2vnH7.js} +1 -1
- package/packages/web/dist/assets/{mermaid.core-D9SbVBpN.js → mermaid.core-CeMMnCip.js} +4 -4
- package/packages/web/dist/assets/{mindmap-definition-RKZ34NQL-CVmLm7zn.js → mindmap-definition-RKZ34NQL-CEdqeoRW.js} +1 -1
- package/packages/web/dist/assets/{pieDiagram-4H26LBE5-D0N10eVU.js → pieDiagram-4H26LBE5-BdDXBx87.js} +1 -1
- package/packages/web/dist/assets/{quadrantDiagram-W4KKPZXB-B5gnYdTa.js → quadrantDiagram-W4KKPZXB-Bovd1Zhx.js} +1 -1
- package/packages/web/dist/assets/{requirementDiagram-4Y6WPE33-CwtxezNZ.js → requirementDiagram-4Y6WPE33-DiyrKnJ2.js} +1 -1
- package/packages/web/dist/assets/{sankeyDiagram-5OEKKPKP-D79O3cux.js → sankeyDiagram-5OEKKPKP-BuX7TRVw.js} +1 -1
- package/packages/web/dist/assets/{sequenceDiagram-3UESZ5HK-xhKcI6tI.js → sequenceDiagram-3UESZ5HK-BjetZWJo.js} +1 -1
- package/packages/web/dist/assets/{stateDiagram-AJRCARHV-DBYMAjcX.js → stateDiagram-AJRCARHV-4AUBV6dF.js} +1 -1
- package/packages/web/dist/assets/stateDiagram-v2-BHNVJYJU-Cq84MOtb.js +2 -0
- package/packages/web/dist/assets/{timeline-definition-PNZ67QCA-e-MYF4lm.js → timeline-definition-PNZ67QCA-BpQ8g8Bm.js} +1 -1
- package/packages/web/dist/assets/{vennDiagram-CIIHVFJN-B8UsvRDM.js → vennDiagram-CIIHVFJN-Cj99BWER.js} +1 -1
- package/packages/web/dist/assets/{wardley-L42UT6IY-1ucACjTl.js → wardley-L42UT6IY-S7AGTOWw.js} +1 -1
- package/packages/web/dist/assets/{wardleyDiagram-YWT4CUSO-DJufLd_u.js → wardleyDiagram-YWT4CUSO-LNXkUA7S.js} +1 -1
- package/packages/web/dist/assets/{xychartDiagram-2RQKCTM6-qqaZNlu9.js → xychartDiagram-2RQKCTM6-DGdTh4Xk.js} +1 -1
- package/packages/web/dist/index.html +1 -1
- package/packages/web/dist/sw.js +1 -1
- package/packages/web/dist/assets/channel-DDgTXrGP.js +0 -2
- package/packages/web/dist/assets/classDiagram-4FO5ZUOK-DU1kd_Vu.js +0 -2
- package/packages/web/dist/assets/classDiagram-v2-Q7XG4LA2-DU1kd_Vu.js +0 -2
- package/packages/web/dist/assets/stateDiagram-v2-BHNVJYJU-CZtr9Jvq.js +0 -2
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The `claude.instructions` lever (#691): whose CLAUDE.md, subagents and slash
|
|
3
|
+
* commands this instance runs with.
|
|
4
|
+
*
|
|
5
|
+
* Paddock always owns its Claude home (`<dataDir>/claude-home`, #691), and
|
|
6
|
+
* relocating a home means the user-level config that lives in `~/.claude` is no
|
|
7
|
+
* longer on Claude Code's path. Since #620 paddock has symlinked it back in
|
|
8
|
+
* unconditionally. This key makes that a choice.
|
|
9
|
+
*
|
|
10
|
+
* ## What is in scope
|
|
11
|
+
*
|
|
12
|
+
* {@link INSTRUCTION_ENTRIES} — `CLAUDE.md`, `agents/`, `commands/`, `plugins/`.
|
|
13
|
+
* Content the model reads, or definitions it can invoke by name: prompts,
|
|
14
|
+
* subagent descriptions, slash commands. Nothing here runs a command on this
|
|
15
|
+
* machine of its own accord, which is what separates it from `claude.hooks`.
|
|
16
|
+
*
|
|
17
|
+
* Bridged by SYMLINK, as before — user-level config is the user's to maintain,
|
|
18
|
+
* and a copy would go stale the moment they edited it.
|
|
19
|
+
*
|
|
20
|
+
* ## The case against `own` as the default, which is real
|
|
21
|
+
*
|
|
22
|
+
* This default reverses the argument #620 shipped with, and that argument is
|
|
23
|
+
* worth keeping rather than deleting. Verbatim, from the docstring that used to
|
|
24
|
+
* sit on `BRIDGED_ENTRIES`:
|
|
25
|
+
*
|
|
26
|
+
* > Without this, relocating the home silently changes agent behaviour: the
|
|
27
|
+
* > user's `~/.claude/CLAUDE.md` is auto-loaded into every session,
|
|
28
|
+
* > `settings.json` carries permissions and hooks, and `agents/` `commands/`
|
|
29
|
+
* > `plugins/` are capability. Dropping them is not "a clean home", it is a
|
|
30
|
+
* > behaviour regression nobody asked for.
|
|
31
|
+
*
|
|
32
|
+
* The reasoning is sound and the premise is **false for the runtime paddock
|
|
33
|
+
* actually uses**, which is worth knowing before weighing the default.
|
|
34
|
+
*
|
|
35
|
+
* `~/.claude/CLAUDE.md` is NOT "auto-loaded into every session". User memory,
|
|
36
|
+
* `agents/` and `commands/` all move as one unit with Claude Code's `user`
|
|
37
|
+
* setting source, and herdctl invokes the Agent SDK with
|
|
38
|
+
* `--setting-sources=project` for every agent that has a working directory —
|
|
39
|
+
* which is every paddock keeper. Verified by capturing the outbound request
|
|
40
|
+
* body: under the default sources the prompt carries a `# claudeMd` block naming
|
|
41
|
+
* `<claudeHome>/CLAUDE.md`; under `["project"]` that block is absent entirely,
|
|
42
|
+
* while the PROJECT's own `CLAUDE.md` still loads. `system/init` likewise drops
|
|
43
|
+
* the home's subagents and slash commands from `agents` / `slash_commands`.
|
|
44
|
+
* (The one thing in the home that is NOT gated is `projects/<enc>/memory/` —
|
|
45
|
+
* auto-memory reaches the agent either way.)
|
|
46
|
+
*
|
|
47
|
+
* So on a default chat turn these four entries have been inert since chats moved
|
|
48
|
+
* to the SDK runtime, bridged or not. Where they DO bite is the CLI paths — the
|
|
49
|
+
* post-turn sweeper, triggers, and `driveMode: batch` chats — which pass no
|
|
50
|
+
* `--setting-sources` and therefore run on the default `user,project,local`.
|
|
51
|
+
*
|
|
52
|
+
* That shrinks the case against `own` rather than answering it: the behaviour
|
|
53
|
+
* regression the docstring warned about has, for the main path, already
|
|
54
|
+
* happened, silently, and nobody filed it. What is left is a real change to the
|
|
55
|
+
* CLI paths, and a lever that is correct before herdctl's default changes rather
|
|
56
|
+
* than after.
|
|
57
|
+
*
|
|
58
|
+
* `own` is the default (#691) because the remaining argument is about what a
|
|
59
|
+
* user can *state*. "`own` everywhere means nothing outside the data dir is read
|
|
60
|
+
* or written" is a guarantee an operator can read off a config file; "…except
|
|
61
|
+
* your CLAUDE.md, agents, commands and plugins, always, with no key to turn them
|
|
62
|
+
* off" is not a guarantee, it is a footnote. A regression one documented key away
|
|
63
|
+
* from being undone is recoverable; an inherited capability with no lever at all
|
|
64
|
+
* is the thing #691 exists to end.
|
|
65
|
+
*
|
|
66
|
+
* The residual cost lands on exactly the users who invested most in their own
|
|
67
|
+
* Claude Code setup, so the boot notice names the key rather than leaving them to
|
|
68
|
+
* find it — see `ensureClaudeHome`.
|
|
69
|
+
*
|
|
70
|
+
* ## Not in scope, deliberately
|
|
71
|
+
*
|
|
72
|
+
* - **`settings.json`** — a mixed bag whose executable half is `claude.hooks`
|
|
73
|
+
* and whose remaining keys (permissions, model, statusline) are inherited
|
|
74
|
+
* either way. See `claude-settings.ts`.
|
|
75
|
+
* - **`enabledPlugins`**, which lives inside `settings.json` and is therefore
|
|
76
|
+
* still inherited under `instructions: own`, orphaned from the `plugins/` dir
|
|
77
|
+
* it names. Harmless as long as bridging `plugins/` is inert (below) — and step
|
|
78
|
+
* 5 has now been built without changing that: `claude.mcpServers: host` reads
|
|
79
|
+
* `~/.claude.json` and touches no setting source, so the flag is still never
|
|
80
|
+
* loaded and a bridged plugin still never switches on. If that ever changes,
|
|
81
|
+
* this key has to move under this lever with the directory it names.
|
|
82
|
+
* - **`.credentials.json`** — `claude.credentials`, step 3.
|
|
83
|
+
* - **`projects/`, `todos/`, `shell-snapshots/`, `statsig/`, `sessions/`** — never
|
|
84
|
+
* bridged in either mode. Per-instance runtime state, which is exactly what
|
|
85
|
+
* should be per-instance.
|
|
86
|
+
*/
|
|
87
|
+
/**
|
|
88
|
+
* Whose user-level instructions this instance uses — the `claude.instructions`
|
|
89
|
+
* key.
|
|
90
|
+
*
|
|
91
|
+
* `own` (default) = only what is inside paddock's own Claude home, plus whatever
|
|
92
|
+
* each project's own directory provides. `host` = the user's `~/.claude`
|
|
93
|
+
* CLAUDE.md, agents, commands and plugins as well, symlinked in.
|
|
94
|
+
*/
|
|
95
|
+
export type InstructionsMode = "own" | "host";
|
|
96
|
+
/** Isolation is the default. See the module doc for the case against it. */
|
|
97
|
+
export declare const DEFAULT_INSTRUCTIONS_MODE: InstructionsMode;
|
|
98
|
+
/** Type guard, so an unknown config value falls back instead of failing a boot. */
|
|
99
|
+
export declare function isKnownInstructionsMode(value: string): value is InstructionsMode;
|
|
100
|
+
/**
|
|
101
|
+
* The entries of the user's Claude home this lever governs.
|
|
102
|
+
*
|
|
103
|
+
* `plugins` is here on the strength of the files rather than their effect —
|
|
104
|
+
* though NOT for the reason #691 gives. The design says the SDK "does not
|
|
105
|
+
* auto-discover installed plugins" and that bridging the directory is therefore
|
|
106
|
+
* inert. That is wrong on the mechanism: the runtime's plugin root IS the Claude
|
|
107
|
+
* home (`join(CLAUDE_CONFIG_DIR, "plugins")`), the `plugins?: SdkPluginConfig[]`
|
|
108
|
+
* option is a sideload channel that gets MERGED with what is discovered there,
|
|
109
|
+
* and a live probe loaded a plugin from a planted home with no `plugins` option
|
|
110
|
+
* passed at all.
|
|
111
|
+
*
|
|
112
|
+
* What makes it inert for paddock is one step further along: discovery is driven
|
|
113
|
+
* by `enabledPlugins`, which lives in `settings.json`, and herdctl runs the SDK
|
|
114
|
+
* with `--setting-sources=project` so the HOME's `settings.json` is never read
|
|
115
|
+
* (see `claude-settings.ts`). Bridge the directory and the flag that turns its
|
|
116
|
+
* contents on is still not loaded. That is a property of two callers rather than
|
|
117
|
+
* of the files, which is exactly why this lever governs them anyway: step 5 is
|
|
118
|
+
* about to change one of those callers, and a lever that silently omitted
|
|
119
|
+
* plugins would then start leaking them.
|
|
120
|
+
*/
|
|
121
|
+
export declare const INSTRUCTION_ENTRIES: readonly ["CLAUDE.md", "agents", "commands", "plugins"];
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The `claude.instructions` lever (#691): whose CLAUDE.md, subagents and slash
|
|
3
|
+
* commands this instance runs with.
|
|
4
|
+
*
|
|
5
|
+
* Paddock always owns its Claude home (`<dataDir>/claude-home`, #691), and
|
|
6
|
+
* relocating a home means the user-level config that lives in `~/.claude` is no
|
|
7
|
+
* longer on Claude Code's path. Since #620 paddock has symlinked it back in
|
|
8
|
+
* unconditionally. This key makes that a choice.
|
|
9
|
+
*
|
|
10
|
+
* ## What is in scope
|
|
11
|
+
*
|
|
12
|
+
* {@link INSTRUCTION_ENTRIES} — `CLAUDE.md`, `agents/`, `commands/`, `plugins/`.
|
|
13
|
+
* Content the model reads, or definitions it can invoke by name: prompts,
|
|
14
|
+
* subagent descriptions, slash commands. Nothing here runs a command on this
|
|
15
|
+
* machine of its own accord, which is what separates it from `claude.hooks`.
|
|
16
|
+
*
|
|
17
|
+
* Bridged by SYMLINK, as before — user-level config is the user's to maintain,
|
|
18
|
+
* and a copy would go stale the moment they edited it.
|
|
19
|
+
*
|
|
20
|
+
* ## The case against `own` as the default, which is real
|
|
21
|
+
*
|
|
22
|
+
* This default reverses the argument #620 shipped with, and that argument is
|
|
23
|
+
* worth keeping rather than deleting. Verbatim, from the docstring that used to
|
|
24
|
+
* sit on `BRIDGED_ENTRIES`:
|
|
25
|
+
*
|
|
26
|
+
* > Without this, relocating the home silently changes agent behaviour: the
|
|
27
|
+
* > user's `~/.claude/CLAUDE.md` is auto-loaded into every session,
|
|
28
|
+
* > `settings.json` carries permissions and hooks, and `agents/` `commands/`
|
|
29
|
+
* > `plugins/` are capability. Dropping them is not "a clean home", it is a
|
|
30
|
+
* > behaviour regression nobody asked for.
|
|
31
|
+
*
|
|
32
|
+
* The reasoning is sound and the premise is **false for the runtime paddock
|
|
33
|
+
* actually uses**, which is worth knowing before weighing the default.
|
|
34
|
+
*
|
|
35
|
+
* `~/.claude/CLAUDE.md` is NOT "auto-loaded into every session". User memory,
|
|
36
|
+
* `agents/` and `commands/` all move as one unit with Claude Code's `user`
|
|
37
|
+
* setting source, and herdctl invokes the Agent SDK with
|
|
38
|
+
* `--setting-sources=project` for every agent that has a working directory —
|
|
39
|
+
* which is every paddock keeper. Verified by capturing the outbound request
|
|
40
|
+
* body: under the default sources the prompt carries a `# claudeMd` block naming
|
|
41
|
+
* `<claudeHome>/CLAUDE.md`; under `["project"]` that block is absent entirely,
|
|
42
|
+
* while the PROJECT's own `CLAUDE.md` still loads. `system/init` likewise drops
|
|
43
|
+
* the home's subagents and slash commands from `agents` / `slash_commands`.
|
|
44
|
+
* (The one thing in the home that is NOT gated is `projects/<enc>/memory/` —
|
|
45
|
+
* auto-memory reaches the agent either way.)
|
|
46
|
+
*
|
|
47
|
+
* So on a default chat turn these four entries have been inert since chats moved
|
|
48
|
+
* to the SDK runtime, bridged or not. Where they DO bite is the CLI paths — the
|
|
49
|
+
* post-turn sweeper, triggers, and `driveMode: batch` chats — which pass no
|
|
50
|
+
* `--setting-sources` and therefore run on the default `user,project,local`.
|
|
51
|
+
*
|
|
52
|
+
* That shrinks the case against `own` rather than answering it: the behaviour
|
|
53
|
+
* regression the docstring warned about has, for the main path, already
|
|
54
|
+
* happened, silently, and nobody filed it. What is left is a real change to the
|
|
55
|
+
* CLI paths, and a lever that is correct before herdctl's default changes rather
|
|
56
|
+
* than after.
|
|
57
|
+
*
|
|
58
|
+
* `own` is the default (#691) because the remaining argument is about what a
|
|
59
|
+
* user can *state*. "`own` everywhere means nothing outside the data dir is read
|
|
60
|
+
* or written" is a guarantee an operator can read off a config file; "…except
|
|
61
|
+
* your CLAUDE.md, agents, commands and plugins, always, with no key to turn them
|
|
62
|
+
* off" is not a guarantee, it is a footnote. A regression one documented key away
|
|
63
|
+
* from being undone is recoverable; an inherited capability with no lever at all
|
|
64
|
+
* is the thing #691 exists to end.
|
|
65
|
+
*
|
|
66
|
+
* The residual cost lands on exactly the users who invested most in their own
|
|
67
|
+
* Claude Code setup, so the boot notice names the key rather than leaving them to
|
|
68
|
+
* find it — see `ensureClaudeHome`.
|
|
69
|
+
*
|
|
70
|
+
* ## Not in scope, deliberately
|
|
71
|
+
*
|
|
72
|
+
* - **`settings.json`** — a mixed bag whose executable half is `claude.hooks`
|
|
73
|
+
* and whose remaining keys (permissions, model, statusline) are inherited
|
|
74
|
+
* either way. See `claude-settings.ts`.
|
|
75
|
+
* - **`enabledPlugins`**, which lives inside `settings.json` and is therefore
|
|
76
|
+
* still inherited under `instructions: own`, orphaned from the `plugins/` dir
|
|
77
|
+
* it names. Harmless as long as bridging `plugins/` is inert (below) — and step
|
|
78
|
+
* 5 has now been built without changing that: `claude.mcpServers: host` reads
|
|
79
|
+
* `~/.claude.json` and touches no setting source, so the flag is still never
|
|
80
|
+
* loaded and a bridged plugin still never switches on. If that ever changes,
|
|
81
|
+
* this key has to move under this lever with the directory it names.
|
|
82
|
+
* - **`.credentials.json`** — `claude.credentials`, step 3.
|
|
83
|
+
* - **`projects/`, `todos/`, `shell-snapshots/`, `statsig/`, `sessions/`** — never
|
|
84
|
+
* bridged in either mode. Per-instance runtime state, which is exactly what
|
|
85
|
+
* should be per-instance.
|
|
86
|
+
*/
|
|
87
|
+
/** Isolation is the default. See the module doc for the case against it. */
|
|
88
|
+
export const DEFAULT_INSTRUCTIONS_MODE = "own";
|
|
89
|
+
/** Type guard, so an unknown config value falls back instead of failing a boot. */
|
|
90
|
+
export function isKnownInstructionsMode(value) {
|
|
91
|
+
return value === "own" || value === "host";
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* The entries of the user's Claude home this lever governs.
|
|
95
|
+
*
|
|
96
|
+
* `plugins` is here on the strength of the files rather than their effect —
|
|
97
|
+
* though NOT for the reason #691 gives. The design says the SDK "does not
|
|
98
|
+
* auto-discover installed plugins" and that bridging the directory is therefore
|
|
99
|
+
* inert. That is wrong on the mechanism: the runtime's plugin root IS the Claude
|
|
100
|
+
* home (`join(CLAUDE_CONFIG_DIR, "plugins")`), the `plugins?: SdkPluginConfig[]`
|
|
101
|
+
* option is a sideload channel that gets MERGED with what is discovered there,
|
|
102
|
+
* and a live probe loaded a plugin from a planted home with no `plugins` option
|
|
103
|
+
* passed at all.
|
|
104
|
+
*
|
|
105
|
+
* What makes it inert for paddock is one step further along: discovery is driven
|
|
106
|
+
* by `enabledPlugins`, which lives in `settings.json`, and herdctl runs the SDK
|
|
107
|
+
* with `--setting-sources=project` so the HOME's `settings.json` is never read
|
|
108
|
+
* (see `claude-settings.ts`). Bridge the directory and the flag that turns its
|
|
109
|
+
* contents on is still not loaded. That is a property of two callers rather than
|
|
110
|
+
* of the files, which is exactly why this lever governs them anyway: step 5 is
|
|
111
|
+
* about to change one of those callers, and a lever that silently omitted
|
|
112
|
+
* plugins would then start leaking them.
|
|
113
|
+
*/
|
|
114
|
+
export const INSTRUCTION_ENTRIES = ["CLAUDE.md", "agents", "commands", "plugins"];
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Whose MCP servers this instance's agents get — the `claude.mcpServers` key.
|
|
3
|
+
*
|
|
4
|
+
* `own` (default) = only the servers paddock itself attaches (`send_file`, the
|
|
5
|
+
* optional self-management tools, the optional browser server). `host` = the
|
|
6
|
+
* servers declared in the user's `~/.claude.json` as well, both the user-scope
|
|
7
|
+
* ones and the ones scoped to a project's own directory.
|
|
8
|
+
*/
|
|
9
|
+
export type McpServersMode = "own" | "host";
|
|
10
|
+
/** Isolation is the default, as everywhere except `credentials`. */
|
|
11
|
+
export declare const DEFAULT_MCP_SERVERS_MODE: McpServersMode;
|
|
12
|
+
/** Type guard, so an unknown config value falls back instead of failing a boot. */
|
|
13
|
+
export declare function isKnownMcpServersMode(value: string): value is McpServersMode;
|
|
14
|
+
/**
|
|
15
|
+
* The file MCP servers are declared in — a SIBLING of the Claude home, not an
|
|
16
|
+
* entry inside it. See the module doc for the SDK expression that settles this.
|
|
17
|
+
*/
|
|
18
|
+
export declare const HOST_MCP_CONFIG_FILE = ".claude.json";
|
|
19
|
+
/**
|
|
20
|
+
* Where the user's own `.claude.json` is.
|
|
21
|
+
*
|
|
22
|
+
* Derived from `cfg.legacyClaudeHome` (always `~/.claude`) rather than read from
|
|
23
|
+
* `os.homedir()` again, so it moves with the one value the rest of the bridge
|
|
24
|
+
* already treats as "the host's Claude Code" — and so a test can point the whole
|
|
25
|
+
* lever at a temp dir by setting that one field.
|
|
26
|
+
*/
|
|
27
|
+
export declare function hostMcpConfigPath(legacyClaudeHome: string): string;
|
|
28
|
+
/**
|
|
29
|
+
* One MCP server, in the only shape herdctl's `McpServerSchema` can carry.
|
|
30
|
+
*
|
|
31
|
+
* Deliberately NOT `SDKMcpServerConfig`: that is what herdctl produces on the
|
|
32
|
+
* far side of `transformMcpServer`, and pinning the narrower agent-config shape
|
|
33
|
+
* here is what makes the lossiness above visible at the type level rather than
|
|
34
|
+
* at runtime.
|
|
35
|
+
*/
|
|
36
|
+
export interface McpServerDef {
|
|
37
|
+
command?: string;
|
|
38
|
+
args?: string[];
|
|
39
|
+
env?: Record<string, string>;
|
|
40
|
+
url?: string;
|
|
41
|
+
}
|
|
42
|
+
/** A set of MCP servers, keyed by the name their tools are namespaced under. */
|
|
43
|
+
export type McpServerDefs = Record<string, McpServerDef>;
|
|
44
|
+
/** Something about a declared server that could not be carried through. */
|
|
45
|
+
export interface HostMcpCaveat {
|
|
46
|
+
/** The server's name in `.claude.json`. */
|
|
47
|
+
name: string;
|
|
48
|
+
/** `dropped` = not passed at all; `degraded` = passed, but not faithfully. */
|
|
49
|
+
kind: "dropped" | "degraded";
|
|
50
|
+
/** Human-readable, and specific enough to act on. */
|
|
51
|
+
reason: string;
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Every MCP server this instance will attach, from every source, plus what could
|
|
55
|
+
* not be carried.
|
|
56
|
+
*
|
|
57
|
+
* The host's `~/.claude.json` supplies two scopes, because that file has two: a
|
|
58
|
+
* top-level `mcpServers` that applies everywhere, and a
|
|
59
|
+
* `projects[<absolute dir>].mcpServers` that applies only in that directory. The
|
|
60
|
+
* per-directory one is keyed by the LITERAL absolute path — not the `-`-encoded
|
|
61
|
+
* form the transcript folders use — and it is the scope a `--here` workspace
|
|
62
|
+
* hits, because `claude mcp add` without `--scope user` writes there.
|
|
63
|
+
*
|
|
64
|
+
* {@link declared} is the third contributor and the one that is not the host's at
|
|
65
|
+
* all: paddock's own top-level `mcpServers:` config block (#691 step 6), resolved
|
|
66
|
+
* by `mcp-servers.ts`. It is carried here rather than threaded separately so that
|
|
67
|
+
* everything downstream of this type — {@link mcpServersFor}, the allowlist
|
|
68
|
+
* widening in `buildAgentConfig` — stays source-agnostic and had to change not at
|
|
69
|
+
* all when it was added.
|
|
70
|
+
*/
|
|
71
|
+
export interface McpSources {
|
|
72
|
+
/** Host `~/.claude.json` top-level `mcpServers`: every keeper gets these. */
|
|
73
|
+
user: McpServerDefs;
|
|
74
|
+
/** Host `projects[<dir>].mcpServers`, keyed by the literal absolute directory. */
|
|
75
|
+
byDir: Record<string, McpServerDefs>;
|
|
76
|
+
/** Declared by this instance in `paddock.config.yaml`; every keeper gets these. */
|
|
77
|
+
declared: McpServerDefs;
|
|
78
|
+
/** Everything the host file could not carry faithfully, for the boot notice. */
|
|
79
|
+
caveats: HostMcpCaveat[];
|
|
80
|
+
}
|
|
81
|
+
/** No servers from anywhere: `mcpServers: own` + an empty block, and where tests start. */
|
|
82
|
+
export declare const EMPTY_MCP_SOURCES: McpSources;
|
|
83
|
+
/** The allowlist entry that lets a server's tools actually be called. */
|
|
84
|
+
export declare function mcpToolPattern(name: string): string;
|
|
85
|
+
/**
|
|
86
|
+
* Parse a `.claude.json` into the two server scopes. Pure, so the whole
|
|
87
|
+
* selection is testable from a string with no filesystem and no real home.
|
|
88
|
+
*
|
|
89
|
+
* Fails soft in both directions on purpose. Unparseable JSON, a non-object top
|
|
90
|
+
* level, a `projects` value that is not a map — none of them throw, because the
|
|
91
|
+
* user's `.claude.json` is a file paddock does not own, cannot validate and must
|
|
92
|
+
* never turn into a boot failure. What it does instead is return nothing and let
|
|
93
|
+
* the caller say so.
|
|
94
|
+
*/
|
|
95
|
+
export declare function parseHostMcpConfig(raw: string): McpSources;
|
|
96
|
+
/**
|
|
97
|
+
* The servers that apply to one agent's working directory.
|
|
98
|
+
*
|
|
99
|
+
* Precedence, weakest first: host user scope, host directory scope, then this
|
|
100
|
+
* instance's own `mcpServers:` block.
|
|
101
|
+
*
|
|
102
|
+
* Host per-directory wins over host user scope because it is the more specific
|
|
103
|
+
* declaration, and it is the one `claude mcp add` writes by default, so a user
|
|
104
|
+
* who re-declared a server inside a project meant that one. {@link
|
|
105
|
+
* McpSources.declared} wins over both because it is a statement about THIS
|
|
106
|
+
* instance while `~/.claude.json` is ambient machine state — a user who wrote a
|
|
107
|
+
* server into paddock's own config was answering "what should paddock have?",
|
|
108
|
+
* which is a narrower question than "what does this machine have?".
|
|
109
|
+
*
|
|
110
|
+
* The host lookup is exact rather than a prefix walk. `.claude.json`'s `projects`
|
|
111
|
+
* keys are the literal cwd Claude Code was started in, and Claude Code does not
|
|
112
|
+
* inherit a parent directory's entry either — matching that keeps paddock's
|
|
113
|
+
* answer the same as the terminal's, which is the whole point of `host`.
|
|
114
|
+
*/
|
|
115
|
+
export declare function mcpServersFor(source: McpSources, workingDir: string): McpServerDefs;
|
|
116
|
+
/** Every directory-scoped key, for the boot notice. */
|
|
117
|
+
export declare function hostMcpScopedDirs(source: McpSources): string[];
|
|
118
|
+
/** A line for the boot log, at a level (mirrors `ClaudeHomeReport.notices`). */
|
|
119
|
+
export interface HostMcpNotice {
|
|
120
|
+
level: "info" | "warn";
|
|
121
|
+
message: string;
|
|
122
|
+
}
|
|
123
|
+
/** What {@link loadHostMcpSource} found. */
|
|
124
|
+
export interface HostMcpReport {
|
|
125
|
+
source: McpSources;
|
|
126
|
+
notices: HostMcpNotice[];
|
|
127
|
+
}
|
|
128
|
+
/**
|
|
129
|
+
* Read the host's `.claude.json` — once, at boot — and say what came of it.
|
|
130
|
+
*
|
|
131
|
+
* Under `own` the file is not opened at all. That is not an optimisation: "own
|
|
132
|
+
* everywhere means nothing outside the data dir is read" is the guarantee #691
|
|
133
|
+
* exists to make sayable, and a lever that read the file and then discarded it
|
|
134
|
+
* would make the guarantee false in the only place anyone could check.
|
|
135
|
+
*
|
|
136
|
+
* Read once rather than per turn, for the same reason `claude.hooks` materialises
|
|
137
|
+
* its `settings.json` once: a `.claude.json` that grows a server mid-run is picked
|
|
138
|
+
* up at the next restart, and the boot notice is where a user looks to confirm
|
|
139
|
+
* what this instance actually has.
|
|
140
|
+
*/
|
|
141
|
+
export declare function loadHostMcpSource(cfg: {
|
|
142
|
+
legacyClaudeHome: string;
|
|
143
|
+
claude: {
|
|
144
|
+
mcpServers: McpServersMode;
|
|
145
|
+
};
|
|
146
|
+
}): Promise<HostMcpReport>;
|