@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.
Files changed (93) hide show
  1. package/README.md +36 -4
  2. package/package.json +1 -1
  3. package/packages/server/dist/agent-errors.d.ts +41 -0
  4. package/packages/server/dist/agent-errors.js +127 -0
  5. package/packages/server/dist/app.js +57 -9
  6. package/packages/server/dist/claude-credentials.d.ts +116 -0
  7. package/packages/server/dist/claude-credentials.js +103 -0
  8. package/packages/server/dist/claude-home.d.ts +164 -25
  9. package/packages/server/dist/claude-home.js +528 -77
  10. package/packages/server/dist/claude-instructions.d.ts +121 -0
  11. package/packages/server/dist/claude-instructions.js +114 -0
  12. package/packages/server/dist/claude-mcp.d.ts +146 -0
  13. package/packages/server/dist/claude-mcp.js +367 -0
  14. package/packages/server/dist/claude-settings.d.ts +159 -0
  15. package/packages/server/dist/claude-settings.js +159 -0
  16. package/packages/server/dist/cli/args.d.ts +1 -1
  17. package/packages/server/dist/cli/args.js +39 -5
  18. package/packages/server/dist/cli/paddock.js +30 -6
  19. package/packages/server/dist/config.d.ts +166 -30
  20. package/packages/server/dist/config.js +106 -26
  21. package/packages/server/dist/herdctl-agent-config.d.ts +11 -1
  22. package/packages/server/dist/herdctl-agent-config.js +53 -7
  23. package/packages/server/dist/herdctl-agent-names.d.ts +11 -0
  24. package/packages/server/dist/herdctl-agent-names.js +31 -0
  25. package/packages/server/dist/herdctl.d.ts +69 -13
  26. package/packages/server/dist/herdctl.js +70 -18
  27. package/packages/server/dist/instance-config.js +36 -0
  28. package/packages/server/dist/mcp-servers.d.ts +168 -0
  29. package/packages/server/dist/mcp-servers.js +305 -0
  30. package/packages/server/dist/routes/chats.js +10 -4
  31. package/packages/server/dist/sweep.js +13 -1
  32. package/packages/server/dist/transcripts.d.ts +62 -24
  33. package/packages/server/dist/transcripts.js +141 -28
  34. package/packages/server/package.json +1 -1
  35. package/packages/web/dist/assets/{InstanceConfigPage-CzMqTdUU.js → InstanceConfigPage-Ca905oey.js} +1 -1
  36. package/packages/web/dist/assets/{MarkdownRenderer-YSEZHWDe.js → MarkdownRenderer-ChlC1ezH.js} +1 -1
  37. package/packages/web/dist/assets/{ProjectRedirect-DLWxZbqK.js → ProjectRedirect-CslqbhUb.js} +1 -1
  38. package/packages/web/dist/assets/{ProjectView-BFX8ff2n.js → ProjectView-DkNdilGo.js} +3 -3
  39. package/packages/web/dist/assets/{ProjectsGrid-DLOeY_ww.js → ProjectsGrid-BrlvLc-Y.js} +1 -1
  40. package/packages/web/dist/assets/{arc-BwC1ik-b.js → arc-CGqCI5nQ.js} +1 -1
  41. package/packages/web/dist/assets/{architectureDiagram-3BPJPVTR-CsVvXQWw.js → architectureDiagram-3BPJPVTR-Cp4KTxE2.js} +1 -1
  42. package/packages/web/dist/assets/{blockDiagram-GPEHLZMM-DXQk2bIa.js → blockDiagram-GPEHLZMM-yFxaTv04.js} +1 -1
  43. package/packages/web/dist/assets/{c4Diagram-AAUBKEIU-DXiA26It.js → c4Diagram-AAUBKEIU-59lhWjRt.js} +1 -1
  44. package/packages/web/dist/assets/channel-CZs6Z1i5.js +2 -0
  45. package/packages/web/dist/assets/{chunk-2J33WTMH-Dt5nC02A.js → chunk-2J33WTMH-BrpXGnJg.js} +1 -1
  46. package/packages/web/dist/assets/{chunk-4BX2VUAB-DcjnWvl6.js → chunk-4BX2VUAB-UxBDb5pi.js} +1 -1
  47. package/packages/web/dist/assets/{chunk-55IACEB6-CRa3LkU4.js → chunk-55IACEB6-D4ZJyUHW.js} +1 -1
  48. package/packages/web/dist/assets/{chunk-727SXJPM-H3V-11qu.js → chunk-727SXJPM-DWdPj_8E.js} +1 -1
  49. package/packages/web/dist/assets/{chunk-AQP2D5EJ-DPCrENYV.js → chunk-AQP2D5EJ-BIpNbflY.js} +1 -1
  50. package/packages/web/dist/assets/{chunk-FMBD7UC4-C4UO0ZTc.js → chunk-FMBD7UC4-f6iJDfdI.js} +1 -1
  51. package/packages/web/dist/assets/{chunk-ND2GUHAM-BtI37CnI.js → chunk-ND2GUHAM-Bz3TKIJk.js} +1 -1
  52. package/packages/web/dist/assets/{chunk-QZHKN3VN-C5bTaK5j.js → chunk-QZHKN3VN-buQmkafK.js} +1 -1
  53. package/packages/web/dist/assets/classDiagram-4FO5ZUOK-CrbEUUCd.js +2 -0
  54. package/packages/web/dist/assets/classDiagram-v2-Q7XG4LA2-CrbEUUCd.js +2 -0
  55. package/packages/web/dist/assets/{core-DB3cpm5N.js → core-TyFI6p0n.js} +1 -1
  56. package/packages/web/dist/assets/{cose-bilkent-S5V4N54A-q-cjTZO4.js → cose-bilkent-S5V4N54A-CIkdi0XF.js} +1 -1
  57. package/packages/web/dist/assets/{dagre-BM42HDAG-DYEV5HFo.js → dagre-BM42HDAG-BnLJCfNs.js} +1 -1
  58. package/packages/web/dist/assets/{diagram-2AECGRRQ-D16XCw78.js → diagram-2AECGRRQ-D0OqfDB9.js} +1 -1
  59. package/packages/web/dist/assets/{diagram-5GNKFQAL-CeztryYE.js → diagram-5GNKFQAL-DQ2spGrK.js} +1 -1
  60. package/packages/web/dist/assets/{diagram-KO2AKTUF-D5SLIMDS.js → diagram-KO2AKTUF-RDIVQ_S3.js} +1 -1
  61. package/packages/web/dist/assets/{diagram-LMA3HP47-Bw-sVPxM.js → diagram-LMA3HP47-DKoTfh2C.js} +1 -1
  62. package/packages/web/dist/assets/{diagram-OG6HWLK6-DsRMITgx.js → diagram-OG6HWLK6-6k0OuSAL.js} +1 -1
  63. package/packages/web/dist/assets/{erDiagram-TEJ5UH35-T8Qqc_ku.js → erDiagram-TEJ5UH35-B-oQaYAC.js} +1 -1
  64. package/packages/web/dist/assets/{flowDiagram-I6XJVG4X-Cyx47UWU.js → flowDiagram-I6XJVG4X-B7qpYe9C.js} +1 -1
  65. package/packages/web/dist/assets/{format-D2I0duZa.js → format-PHdEBNOi.js} +1 -1
  66. package/packages/web/dist/assets/{ganttDiagram-6RSMTGT7-DxYJmG9o.js → ganttDiagram-6RSMTGT7-SfBsqMmx.js} +1 -1
  67. package/packages/web/dist/assets/{gitGraphDiagram-PVQCEYII-COK5YOTD.js → gitGraphDiagram-PVQCEYII-CuM4Rl_i.js} +1 -1
  68. package/packages/web/dist/assets/{index-wBXQMkGI.js → index-D_1ogxg1.js} +2 -2
  69. package/packages/web/dist/assets/{infoDiagram-5YYISTIA-BamRN_Nn.js → infoDiagram-5YYISTIA-Dq-32Oj4.js} +1 -1
  70. package/packages/web/dist/assets/{ishikawaDiagram-YF4QCWOH-DuOHdpEH.js → ishikawaDiagram-YF4QCWOH-BLFHCj_o.js} +1 -1
  71. package/packages/web/dist/assets/{journeyDiagram-JHISSGLW-Bri7GKTW.js → journeyDiagram-JHISSGLW-CHP-Yu63.js} +1 -1
  72. package/packages/web/dist/assets/{kanban-definition-UN3LZRKU-BdkgUnzI.js → kanban-definition-UN3LZRKU-DRuehSqn.js} +1 -1
  73. package/packages/web/dist/assets/{linear-DOcNPCpB.js → linear-Bwz2vnH7.js} +1 -1
  74. package/packages/web/dist/assets/{mermaid.core-D9SbVBpN.js → mermaid.core-CeMMnCip.js} +4 -4
  75. package/packages/web/dist/assets/{mindmap-definition-RKZ34NQL-CVmLm7zn.js → mindmap-definition-RKZ34NQL-CEdqeoRW.js} +1 -1
  76. package/packages/web/dist/assets/{pieDiagram-4H26LBE5-D0N10eVU.js → pieDiagram-4H26LBE5-BdDXBx87.js} +1 -1
  77. package/packages/web/dist/assets/{quadrantDiagram-W4KKPZXB-B5gnYdTa.js → quadrantDiagram-W4KKPZXB-Bovd1Zhx.js} +1 -1
  78. package/packages/web/dist/assets/{requirementDiagram-4Y6WPE33-CwtxezNZ.js → requirementDiagram-4Y6WPE33-DiyrKnJ2.js} +1 -1
  79. package/packages/web/dist/assets/{sankeyDiagram-5OEKKPKP-D79O3cux.js → sankeyDiagram-5OEKKPKP-BuX7TRVw.js} +1 -1
  80. package/packages/web/dist/assets/{sequenceDiagram-3UESZ5HK-xhKcI6tI.js → sequenceDiagram-3UESZ5HK-BjetZWJo.js} +1 -1
  81. package/packages/web/dist/assets/{stateDiagram-AJRCARHV-DBYMAjcX.js → stateDiagram-AJRCARHV-4AUBV6dF.js} +1 -1
  82. package/packages/web/dist/assets/stateDiagram-v2-BHNVJYJU-Cq84MOtb.js +2 -0
  83. package/packages/web/dist/assets/{timeline-definition-PNZ67QCA-e-MYF4lm.js → timeline-definition-PNZ67QCA-BpQ8g8Bm.js} +1 -1
  84. package/packages/web/dist/assets/{vennDiagram-CIIHVFJN-B8UsvRDM.js → vennDiagram-CIIHVFJN-Cj99BWER.js} +1 -1
  85. package/packages/web/dist/assets/{wardley-L42UT6IY-1ucACjTl.js → wardley-L42UT6IY-S7AGTOWw.js} +1 -1
  86. package/packages/web/dist/assets/{wardleyDiagram-YWT4CUSO-DJufLd_u.js → wardleyDiagram-YWT4CUSO-LNXkUA7S.js} +1 -1
  87. package/packages/web/dist/assets/{xychartDiagram-2RQKCTM6-qqaZNlu9.js → xychartDiagram-2RQKCTM6-DGdTh4Xk.js} +1 -1
  88. package/packages/web/dist/index.html +1 -1
  89. package/packages/web/dist/sw.js +1 -1
  90. package/packages/web/dist/assets/channel-DDgTXrGP.js +0 -2
  91. package/packages/web/dist/assets/classDiagram-4FO5ZUOK-DU1kd_Vu.js +0 -2
  92. package/packages/web/dist/assets/classDiagram-v2-Q7XG4LA2-DU1kd_Vu.js +0 -2
  93. package/packages/web/dist/assets/stateDiagram-v2-BHNVJYJU-CZtr9Jvq.js +0 -2
@@ -1,26 +1,95 @@
1
1
  import type { PaddockConfig } from "./config.js";
2
2
  /**
3
- * Entries of a Claude home that are USER-LEVEL configuration rather than
4
- * per-instance state, symlinked from the user's home into paddock's own when
5
- * paddock's does not already have its own.
6
- *
7
- * Without this, relocating the home silently changes agent behaviour: the user's
8
- * `~/.claude/CLAUDE.md` is auto-loaded into every session, `settings.json`
9
- * carries permissions and hooks, and `agents/` `commands/` `plugins/` are
10
- * capability. Dropping them is not "a clean home", it is a behaviour regression
11
- * nobody asked for.
12
- *
13
- * `.credentials.json` is the one that matters most: on Linux (and in the Docker
14
- * image) it is where `claude login` puts the OAuth token, so without the bridge
15
- * every file-authenticated install would come back logged out. Symlinked rather
16
- * than copied — a copy would duplicate a live secret onto disk AND diverge the
17
- * moment Claude Code refreshed the token.
18
- *
19
- * Deliberately NOT bridged: `projects/` (that's the whole point), and everything
20
- * that is per-instance runtime state — `todos/`, `shell-snapshots/`, `statsig/`,
21
- * `sessions/`. Those are exactly what should now be per-instance.
3
+ * The user's file-based Claude Code login, bridged in only under
4
+ * `claude.credentials: host` (#691).
5
+ *
6
+ * This is what the lever means on Linux and in the Docker image, where `claude
7
+ * login` writes a file rather than using a keychain: on darwin `credentials: host`
8
+ * is the `CLAUDE_SECURESTORAGE_CONFIG_DIR` empty-string trick, here it is this
9
+ * symlink, and one config key has to mean the same thing on both.
10
+ *
11
+ * Symlinked rather than copied — a copy would duplicate a live secret onto disk
12
+ * AND diverge the moment Claude Code refreshed the token.
13
+ *
14
+ * It was bridged unconditionally before the lever existed, which is why
15
+ * `credentials` defaulting to `host` keeps every existing install working
16
+ * unchanged; `own` is the new behaviour, and it has to also REMOVE a link a
17
+ * previous boot planted, or "isolated" would be a claim that only holds for
18
+ * instances that were never anything else.
19
+ */
20
+ export declare const CREDENTIAL_ENTRY = ".credentials.json";
21
+ /**
22
+ * Entries of the user's Claude home that paddock can bridge into its own — the
23
+ * complete list, for callers that want to reason about the surface rather than
24
+ * about one lever.
25
+ *
26
+ * There is no longer an "always bridged" set: since #691 step 4, every entry here
27
+ * belongs to exactly one key of the `claude:` block, and the mapping is the whole
28
+ * point of the block.
29
+ *
30
+ * | Entry | Lever |
31
+ * |---|---|
32
+ * | `CLAUDE.md`, `agents/`, `commands/`, `plugins/` | `claude.instructions` |
33
+ * | `settings.json` (its `hooks` key) | `claude.hooks` |
34
+ * | `.credentials.json` | `claude.credentials` |
35
+ *
36
+ * `settings.json` appears under `hooks` because that is the half of it a lever
37
+ * governs; its OTHER keys — permissions, model, statusline, `enabledPlugins` —
38
+ * are inherited in every mode, which is why `hooks: own` writes a filtered file
39
+ * rather than declining to bridge one. See `claude-settings.ts`.
40
+ *
41
+ * Deliberately NOT bridged in any mode: `projects/` (that's the whole point), and
42
+ * everything that is per-instance runtime state — `todos/`, `shell-snapshots/`,
43
+ * `statsig/`, `sessions/`. Those are exactly what should be per-instance.
44
+ *
45
+ * The fifth lever, `claude.mcpServers`, has NO row here on purpose: MCP servers
46
+ * are declared in `~/.claude.json`, which is a sibling of the home rather than an
47
+ * entry inside it, so it is not bridgeable at all — paddock reads it and passes
48
+ * the servers programmatically (`claude-mcp.ts`). That asymmetry is the reason
49
+ * MCP inheritance broke separately from everything in this table.
50
+ */
51
+ export declare const BRIDGEABLE_ENTRIES: readonly string[];
52
+ /**
53
+ * What a Keychain probe concluded.
54
+ *
55
+ * `unknown` is the important one and the default: not darwin, no `security`
56
+ * binary, the lookup errored, or we simply did not find an entry under a name we
57
+ * guessed. It must never be reported to the user as "you have no login".
58
+ */
59
+ export type KeychainFinding = "found" | "unknown";
60
+ /** Probe for a macOS login paddock's own home cannot see. Injectable for tests. */
61
+ export type KeychainProbe = () => Promise<KeychainFinding>;
62
+ /**
63
+ * Ask the macOS Keychain whether a plain-name Claude Code login exists (#683).
64
+ *
65
+ * The whole value of this is turning "you appear to have no credentials" into
66
+ * "you ARE logged in; paddock cannot see it, and here is the one-liner" — a
67
+ * distinction paddock currently cannot make, and the difference between a
68
+ * message that describes a problem and one that fixes it.
69
+ *
70
+ * ## The asymmetry, which is deliberate
71
+ *
72
+ * A positive result is trustworthy: an entry under that service name is a login.
73
+ * A negative result is NOT — `security` can fail for a dozen reasons that have
74
+ * nothing to do with the user, and the service name, though now read straight out
75
+ * of the SDK bundle rather than guessed, is still Claude Code's internal detail
76
+ * and can change. So a miss returns `unknown`, and the caller falls back to the
77
+ * existing, correct, generic warning. Being wrong about the name therefore costs
78
+ * nothing beyond the improvement not happening.
79
+ *
80
+ * Never prompts and never reads a secret: `find-generic-password` WITHOUT `-w`
81
+ * reports existence only (attributes, which are discarded), so nothing sensitive
82
+ * reaches a log, a transcript, or this process's memory.
83
+ *
84
+ * One known imprecision, left in on purpose: Claude Code's own lookup also passes
85
+ * `-a` (`process.env.USER`, falling back to the OS username), and this does not.
86
+ * So an entry filed under a DIFFERENT account still reads as `found` here while
87
+ * Claude Code would miss it — a service running under a different `USER` than the
88
+ * terminal that logged in. Matching that exactly would trade a rare false
89
+ * positive for a rarer false negative, and a false negative is the one that costs
90
+ * something: it downgrades a specific instruction back to the generic warning.
22
91
  */
23
- export declare const BRIDGED_ENTRIES: readonly [".credentials.json", "settings.json", "CLAUDE.md", "agents", "commands", "plugins"];
92
+ export declare function probeMacosKeychainLogin(platform?: string): Promise<KeychainFinding>;
24
93
  /** A message for the operator, at the level it should be logged at. */
25
94
  export interface ClaudeHomeNotice {
26
95
  level: "info" | "warn";
@@ -29,21 +98,48 @@ export interface ClaudeHomeNotice {
29
98
  export interface ClaudeHomeReport {
30
99
  /** Entries symlinked in from the user's home this boot. */
31
100
  bridged: string[];
101
+ /**
102
+ * Entries whose bridge symlink was REMOVED this boot because the lever that
103
+ * governs them now says `own` (#691).
104
+ *
105
+ * The bridge is non-clobbering, so without this an instance that was ever
106
+ * `host` would keep reading the user's file forever after being reconfigured —
107
+ * "isolated" would be a claim that only holds for instances that were never
108
+ * anything else.
109
+ */
110
+ withdrawn: string[];
111
+ /**
112
+ * Entries paddock WROTE into its own home this boot rather than symlinking,
113
+ * because a lever needs part of a file and not the whole of it. Only
114
+ * `settings.json` today — see `claude-settings.ts`.
115
+ */
116
+ generated: string[];
32
117
  /** Messages for `app.ts` to log — config resolution has no logger of its own. */
33
118
  notices: ClaudeHomeNotice[];
34
119
  }
35
120
  /**
36
- * Create paddock's Claude home and bridge the user-level config into it.
121
+ * Create paddock's Claude home and put the user-level config into it that this
122
+ * instance's `claude:` levers say it should have (#691).
37
123
  *
38
- * Idempotent and non-clobbering: an entry paddock's home already has (whether a
39
- * real file the user put there or a symlink from a previous boot) is left
40
- * completely alone, so this is safe to run on every start.
124
+ * Idempotent and non-clobbering: a real file the user put in paddock's home is
125
+ * left completely alone, so this is safe to run on every start. What it DOES
126
+ * maintain is what paddock itself planted — bridge symlinks, withdrawn when a
127
+ * lever flips to `own`, and the generated `settings.json`, regenerated from the
128
+ * user's current one. Ownership of a generated file is decided by hash
129
+ * ({@link classifyOwnEntry}), never by "it is at a name we use".
41
130
  *
42
131
  * Never throws. A home that cannot be created is not a reason to refuse to boot
43
132
  * — Claude Code falls back to its own default and chat still works, which is the
44
133
  * same failure mode `ensureProjectChats` has always had.
134
+ *
135
+ * **Mutates `env`** (`process.env` by default) to carry `claude.credentials` into
136
+ * the environment Claude Code runs in — see {@link applyCredentialsMode} for why
137
+ * that is the only seam available and why it is safe process-wide. Done here
138
+ * because this is already the one call that runs before the fleet starts, and
139
+ * because the credential warning below has to describe the environment it just
140
+ * set rather than the one it found.
45
141
  */
46
- export declare function ensureClaudeHome(cfg: Pick<PaddockConfig, "claudeHome" | "legacyClaudeHome" | "ownsClaudeHome">, env?: NodeJS.ProcessEnv): Promise<ClaudeHomeReport>;
142
+ export declare function ensureClaudeHome(cfg: Pick<PaddockConfig, "claudeHome" | "legacyClaudeHome" | "claude">, env?: NodeJS.ProcessEnv, probeKeychain?: KeychainProbe): Promise<ClaudeHomeReport>;
47
143
  /** One of the user's transcript folders, made readable through paddock's home. */
48
144
  export interface LegacyMirror {
49
145
  /** Folder name inside `<claudeHome>/projects/` — `encodePathForCli(engineCwd)`. */
@@ -107,6 +203,14 @@ export declare function legacySourcePath(legacyHome: string, folderName: string)
107
203
  * mirroring them would re-offer paddock's own chats as "adoptable". That also
108
204
  * makes the leftovers from before this change inert rather than confusing.
109
205
  *
206
+ * A folder paddock's own home ALREADY links to directly is skipped for the same
207
+ * reason. That is the `claude.transcripts: host` case (#691): there the folder in
208
+ * the user's home is a real directory that paddock itself writes through, so
209
+ * mirroring it would offer every project's own live chats back as importable —
210
+ * the #658 mistake with the arrow reversed. (Adoption de-duplicates sources by
211
+ * resolved real path, so this was noise rather than breakage; it is skipped here
212
+ * because a link paddock plants and then mirrors is confusing to find on disk.)
213
+ *
110
214
  * Idempotent and never throws. Returns every mirror it maintains, not only the
111
215
  * ones planted this call, so a caller can rely on the mapping after any call.
112
216
  */
@@ -123,3 +227,38 @@ export declare function mirrorLegacyTranscriptFolders(claudeHome: string, legacy
123
227
  * there is the entire point.
124
228
  */
125
229
  export declare function countLegacyTranscriptLinks(legacyHome: string, dataDir: string): Promise<number>;
230
+ /** A `~/.claude/projects/<enc>` symlink pointing at some `.chats/` store. */
231
+ export interface PlantedChatsLink {
232
+ /** The link itself, inside the user's home — the path to tell the user about. */
233
+ link: string;
234
+ /** What it points at, resolved. Always a `.chats` directory by construction. */
235
+ target: string;
236
+ /** Does the target still exist? A dangling link is the one that breaks tooling. */
237
+ dangling: boolean;
238
+ }
239
+ /**
240
+ * Find transcript symlinks planted in the user's home that point at a `.chats/`
241
+ * store OUTSIDE `dataDir` (#682).
242
+ *
243
+ * The instance's own leftovers — links into this data dir — are already reported
244
+ * by {@link countLegacyTranscriptLinks} as harmless pre-#620 residue, and they
245
+ * are: they were planted for a project whose transcripts paddock does own.
246
+ *
247
+ * The ones this finds are the poisoned kind. Under `--here` the workspace's
248
+ * `.chats/` sits at `<dir>/.chats` while the data dir is `<dir>/.paddock`, so a
249
+ * link planted by an affected build points somewhere no `dataDir` prefix match
250
+ * will ever catch. While it exists, every `claude` session the user starts in
251
+ * that directory writes into paddock's store instead of their own history, and
252
+ * anything that expects `~/.claude/projects/<enc>` to be a real directory
253
+ * (`unzip -d ~/.claude` being the observed one) fails with an error impossible
254
+ * to trace back here.
255
+ *
256
+ * Reported, never removed. Paddock not writing to `~/.claude` is the entire
257
+ * point of #620, and that has to include cleaning up after itself — a boot that
258
+ * silently deleted something under there would be the same class of surprise in
259
+ * the opposite direction. Naming the exact path is enough: `rm` is one command
260
+ * and the user can see what they are removing first.
261
+ *
262
+ * Never throws; an unreadable home just yields no findings.
263
+ */
264
+ export declare function findPlantedChatsLinks(legacyHome: string, dataDir: string): Promise<PlantedChatsLink[]>;