@edspencer/paddock 0.61.1 → 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.
Files changed (92) hide show
  1. package/README.md +35 -14
  2. package/package.json +1 -1
  3. package/packages/server/dist/app.js +35 -8
  4. package/packages/server/dist/claude-credentials.d.ts +116 -0
  5. package/packages/server/dist/claude-credentials.js +103 -0
  6. package/packages/server/dist/claude-home.d.ts +102 -30
  7. package/packages/server/dist/claude-home.js +437 -97
  8. package/packages/server/dist/claude-instructions.d.ts +121 -0
  9. package/packages/server/dist/claude-instructions.js +114 -0
  10. package/packages/server/dist/claude-mcp.d.ts +146 -0
  11. package/packages/server/dist/claude-mcp.js +367 -0
  12. package/packages/server/dist/claude-settings.d.ts +159 -0
  13. package/packages/server/dist/claude-settings.js +159 -0
  14. package/packages/server/dist/cli/args.d.ts +1 -9
  15. package/packages/server/dist/cli/args.js +36 -18
  16. package/packages/server/dist/cli/paddock.js +20 -39
  17. package/packages/server/dist/config.d.ts +166 -30
  18. package/packages/server/dist/config.js +106 -26
  19. package/packages/server/dist/herdctl-agent-config.d.ts +11 -1
  20. package/packages/server/dist/herdctl-agent-config.js +53 -7
  21. package/packages/server/dist/herdctl-agent-names.d.ts +11 -0
  22. package/packages/server/dist/herdctl-agent-names.js +31 -0
  23. package/packages/server/dist/herdctl.d.ts +69 -13
  24. package/packages/server/dist/herdctl.js +70 -18
  25. package/packages/server/dist/instance-config.js +36 -0
  26. package/packages/server/dist/mcp-servers.d.ts +168 -0
  27. package/packages/server/dist/mcp-servers.js +305 -0
  28. package/packages/server/dist/routes/chats.js +10 -4
  29. package/packages/server/dist/transcripts.d.ts +61 -30
  30. package/packages/server/dist/transcripts.js +141 -46
  31. package/packages/server/package.json +1 -1
  32. package/packages/web/dist/assets/{InstanceConfigPage-BgNXqAox.js → InstanceConfigPage-Ca905oey.js} +1 -1
  33. package/packages/web/dist/assets/{MarkdownRenderer-DfD_UtqU.js → MarkdownRenderer-ChlC1ezH.js} +1 -1
  34. package/packages/web/dist/assets/{ProjectRedirect-1EXdHXmO.js → ProjectRedirect-CslqbhUb.js} +1 -1
  35. package/packages/web/dist/assets/{ProjectView-DHb5vNUp.js → ProjectView-DkNdilGo.js} +3 -3
  36. package/packages/web/dist/assets/{ProjectsGrid-Br-EhLZE.js → ProjectsGrid-BrlvLc-Y.js} +1 -1
  37. package/packages/web/dist/assets/{arc-C2Jekujs.js → arc-CGqCI5nQ.js} +1 -1
  38. package/packages/web/dist/assets/{architectureDiagram-3BPJPVTR-CflCA-em.js → architectureDiagram-3BPJPVTR-Cp4KTxE2.js} +1 -1
  39. package/packages/web/dist/assets/{blockDiagram-GPEHLZMM-Ds7GLNnC.js → blockDiagram-GPEHLZMM-yFxaTv04.js} +1 -1
  40. package/packages/web/dist/assets/{c4Diagram-AAUBKEIU-D4WyGO6I.js → c4Diagram-AAUBKEIU-59lhWjRt.js} +1 -1
  41. package/packages/web/dist/assets/channel-CZs6Z1i5.js +2 -0
  42. package/packages/web/dist/assets/{chunk-2J33WTMH-tQunO_M5.js → chunk-2J33WTMH-BrpXGnJg.js} +1 -1
  43. package/packages/web/dist/assets/{chunk-4BX2VUAB-DT5dOWd2.js → chunk-4BX2VUAB-UxBDb5pi.js} +1 -1
  44. package/packages/web/dist/assets/{chunk-55IACEB6-CfTUqUEF.js → chunk-55IACEB6-D4ZJyUHW.js} +1 -1
  45. package/packages/web/dist/assets/{chunk-727SXJPM-sK5bOAA0.js → chunk-727SXJPM-DWdPj_8E.js} +1 -1
  46. package/packages/web/dist/assets/{chunk-AQP2D5EJ-DcMgVe-P.js → chunk-AQP2D5EJ-BIpNbflY.js} +1 -1
  47. package/packages/web/dist/assets/{chunk-FMBD7UC4-In3h_-7v.js → chunk-FMBD7UC4-f6iJDfdI.js} +1 -1
  48. package/packages/web/dist/assets/{chunk-ND2GUHAM-DuaIeRaC.js → chunk-ND2GUHAM-Bz3TKIJk.js} +1 -1
  49. package/packages/web/dist/assets/{chunk-QZHKN3VN-DeT5mR5T.js → chunk-QZHKN3VN-buQmkafK.js} +1 -1
  50. package/packages/web/dist/assets/classDiagram-4FO5ZUOK-CrbEUUCd.js +2 -0
  51. package/packages/web/dist/assets/classDiagram-v2-Q7XG4LA2-CrbEUUCd.js +2 -0
  52. package/packages/web/dist/assets/{core-DgOgLvnM.js → core-TyFI6p0n.js} +1 -1
  53. package/packages/web/dist/assets/{cose-bilkent-S5V4N54A-CyO-rznJ.js → cose-bilkent-S5V4N54A-CIkdi0XF.js} +1 -1
  54. package/packages/web/dist/assets/{dagre-BM42HDAG-B_9Ihzgn.js → dagre-BM42HDAG-BnLJCfNs.js} +1 -1
  55. package/packages/web/dist/assets/{diagram-2AECGRRQ-z5mvZ5YT.js → diagram-2AECGRRQ-D0OqfDB9.js} +1 -1
  56. package/packages/web/dist/assets/{diagram-5GNKFQAL-Bsz0cgfn.js → diagram-5GNKFQAL-DQ2spGrK.js} +1 -1
  57. package/packages/web/dist/assets/{diagram-KO2AKTUF-B29k5f4q.js → diagram-KO2AKTUF-RDIVQ_S3.js} +1 -1
  58. package/packages/web/dist/assets/{diagram-LMA3HP47-CFrwsHoI.js → diagram-LMA3HP47-DKoTfh2C.js} +1 -1
  59. package/packages/web/dist/assets/{diagram-OG6HWLK6-D9Sjc2HR.js → diagram-OG6HWLK6-6k0OuSAL.js} +1 -1
  60. package/packages/web/dist/assets/{erDiagram-TEJ5UH35-C3vbkD7M.js → erDiagram-TEJ5UH35-B-oQaYAC.js} +1 -1
  61. package/packages/web/dist/assets/{flowDiagram-I6XJVG4X-DkMIgntd.js → flowDiagram-I6XJVG4X-B7qpYe9C.js} +1 -1
  62. package/packages/web/dist/assets/{format-BFDqyFuw.js → format-PHdEBNOi.js} +1 -1
  63. package/packages/web/dist/assets/{ganttDiagram-6RSMTGT7-nvHanjpW.js → ganttDiagram-6RSMTGT7-SfBsqMmx.js} +1 -1
  64. package/packages/web/dist/assets/{gitGraphDiagram-PVQCEYII-DbCNfOu7.js → gitGraphDiagram-PVQCEYII-CuM4Rl_i.js} +1 -1
  65. package/packages/web/dist/assets/{index-DGCs1YIO.js → index-D_1ogxg1.js} +2 -2
  66. package/packages/web/dist/assets/{infoDiagram-5YYISTIA-aJjH9x3D.js → infoDiagram-5YYISTIA-Dq-32Oj4.js} +1 -1
  67. package/packages/web/dist/assets/{ishikawaDiagram-YF4QCWOH-DoifwNnZ.js → ishikawaDiagram-YF4QCWOH-BLFHCj_o.js} +1 -1
  68. package/packages/web/dist/assets/{journeyDiagram-JHISSGLW-Cz9kG9HN.js → journeyDiagram-JHISSGLW-CHP-Yu63.js} +1 -1
  69. package/packages/web/dist/assets/{kanban-definition-UN3LZRKU-BoXnfr7A.js → kanban-definition-UN3LZRKU-DRuehSqn.js} +1 -1
  70. package/packages/web/dist/assets/{linear-BlTTO9yR.js → linear-Bwz2vnH7.js} +1 -1
  71. package/packages/web/dist/assets/{mermaid.core-YAG8eSPQ.js → mermaid.core-CeMMnCip.js} +4 -4
  72. package/packages/web/dist/assets/{mindmap-definition-RKZ34NQL-DtUBKfkr.js → mindmap-definition-RKZ34NQL-CEdqeoRW.js} +1 -1
  73. package/packages/web/dist/assets/{pieDiagram-4H26LBE5-B3Rwpmy0.js → pieDiagram-4H26LBE5-BdDXBx87.js} +1 -1
  74. package/packages/web/dist/assets/{quadrantDiagram-W4KKPZXB-B8eJtTyk.js → quadrantDiagram-W4KKPZXB-Bovd1Zhx.js} +1 -1
  75. package/packages/web/dist/assets/{requirementDiagram-4Y6WPE33-CpAluiY9.js → requirementDiagram-4Y6WPE33-DiyrKnJ2.js} +1 -1
  76. package/packages/web/dist/assets/{sankeyDiagram-5OEKKPKP-Cl_Rd1tN.js → sankeyDiagram-5OEKKPKP-BuX7TRVw.js} +1 -1
  77. package/packages/web/dist/assets/{sequenceDiagram-3UESZ5HK-CRpqKSGm.js → sequenceDiagram-3UESZ5HK-BjetZWJo.js} +1 -1
  78. package/packages/web/dist/assets/{stateDiagram-AJRCARHV-h3h8gXv_.js → stateDiagram-AJRCARHV-4AUBV6dF.js} +1 -1
  79. package/packages/web/dist/assets/stateDiagram-v2-BHNVJYJU-Cq84MOtb.js +2 -0
  80. package/packages/web/dist/assets/{timeline-definition-PNZ67QCA-PVr5V_pG.js → timeline-definition-PNZ67QCA-BpQ8g8Bm.js} +1 -1
  81. package/packages/web/dist/assets/{vennDiagram-CIIHVFJN-De-4NPAX.js → vennDiagram-CIIHVFJN-Cj99BWER.js} +1 -1
  82. package/packages/web/dist/assets/{wardley-L42UT6IY-Dtv10D2d.js → wardley-L42UT6IY-S7AGTOWw.js} +1 -1
  83. package/packages/web/dist/assets/{wardleyDiagram-YWT4CUSO-p2fJuQ6C.js → wardleyDiagram-YWT4CUSO-LNXkUA7S.js} +1 -1
  84. package/packages/web/dist/assets/{xychartDiagram-2RQKCTM6-DyYF-k92.js → xychartDiagram-2RQKCTM6-DGdTh4Xk.js} +1 -1
  85. package/packages/web/dist/index.html +1 -1
  86. package/packages/web/dist/sw.js +1 -1
  87. package/packages/server/dist/cli/claude-home-choice.d.ts +0 -44
  88. package/packages/server/dist/cli/claude-home-choice.js +0 -108
  89. package/packages/web/dist/assets/channel-B1K_gwAH.js +0 -2
  90. package/packages/web/dist/assets/classDiagram-4FO5ZUOK-DYQQOKrW.js +0 -2
  91. package/packages/web/dist/assets/classDiagram-v2-Q7XG4LA2-DYQQOKrW.js +0 -2
  92. package/packages/web/dist/assets/stateDiagram-v2-BHNVJYJU-BKRI9TnH.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>;