@edspencer/paddock 0.71.1 → 0.72.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 (113) hide show
  1. package/package.json +1 -1
  2. package/packages/server/dist/app.js +27 -0
  3. package/packages/server/dist/cli/args.d.ts +67 -8
  4. package/packages/server/dist/cli/args.js +213 -33
  5. package/packages/server/dist/cli/config.d.ts +157 -0
  6. package/packages/server/dist/cli/config.js +462 -0
  7. package/packages/server/dist/cli/paddock.js +53 -3
  8. package/packages/server/dist/cli/service/backend.d.ts +33 -0
  9. package/packages/server/dist/cli/service/index.d.ts +3 -3
  10. package/packages/server/dist/cli/service/index.js +124 -2
  11. package/packages/server/dist/cli/service/launchd.d.ts +27 -4
  12. package/packages/server/dist/cli/service/launchd.js +88 -14
  13. package/packages/server/dist/cli/service/systemd.d.ts +21 -2
  14. package/packages/server/dist/cli/service/systemd.js +58 -5
  15. package/packages/server/dist/config.d.ts +36 -1
  16. package/packages/server/dist/config.js +59 -44
  17. package/packages/server/dist/herdctl.d.ts +45 -0
  18. package/packages/server/dist/herdctl.js +58 -4
  19. package/packages/server/dist/instance-config.d.ts +149 -21
  20. package/packages/server/dist/instance-config.js +228 -5
  21. package/packages/server/dist/last-activity.d.ts +21 -0
  22. package/packages/server/dist/last-activity.js +7 -2
  23. package/packages/server/dist/profiles.d.ts +154 -0
  24. package/packages/server/dist/profiles.js +214 -0
  25. package/packages/server/dist/routes/transcripts.d.ts +61 -0
  26. package/packages/server/dist/routes/transcripts.js +676 -0
  27. package/packages/server/dist/routes.d.ts +3 -0
  28. package/packages/server/dist/routes.js +2 -0
  29. package/packages/server/dist/transcript-move.d.ts +62 -0
  30. package/packages/server/dist/transcript-move.js +179 -0
  31. package/packages/server/dist/transcripts-migration-execute.d.ts +144 -0
  32. package/packages/server/dist/transcripts-migration-execute.js +630 -0
  33. package/packages/server/dist/transcripts-migration.d.ts +336 -0
  34. package/packages/server/dist/transcripts-migration.js +917 -0
  35. package/packages/server/dist/transcripts.d.ts +46 -2
  36. package/packages/server/dist/transcripts.js +126 -3
  37. package/packages/server/package.json +1 -1
  38. package/packages/web/dist/assets/DiscoverPage-DXI9FjmJ.js +2 -0
  39. package/packages/web/dist/assets/DiscoverView-D9oqVkT4.js +2 -0
  40. package/packages/web/dist/assets/InstanceConfigPage-DyH1j5oR.js +2 -0
  41. package/packages/web/dist/assets/{MarkdownRenderer-DdoNl0Ao.js → MarkdownRenderer-D95ofnQ8.js} +1 -1
  42. package/packages/web/dist/assets/ProjectMenu-BO70tGwy.js +2 -0
  43. package/packages/web/dist/assets/{ProjectRedirect-QuGeN-qx.js → ProjectRedirect-BxX_aADU.js} +1 -1
  44. package/packages/web/dist/assets/ProjectView-BbCyKoh5.js +13 -0
  45. package/packages/web/dist/assets/{ProjectsGrid-CUFNVTif.js → ProjectsGrid-BafOHL43.js} +1 -1
  46. package/packages/web/dist/assets/RootHome-BGkMypUJ.js +2 -0
  47. package/packages/web/dist/assets/Surfaces-B8SyV4r3.js +2 -0
  48. package/packages/web/dist/assets/{arc-C0DRwCCT.js → arc-DGyr--oL.js} +1 -1
  49. package/packages/web/dist/assets/architectureDiagram-3BPJPVTR-BNczNNmx.js +37 -0
  50. package/packages/web/dist/assets/{blockDiagram-GPEHLZMM-DKmCbgWk.js → blockDiagram-GPEHLZMM-DiTvGSrV.js} +1 -1
  51. package/packages/web/dist/assets/{c4Diagram-AAUBKEIU-CJ8LiLsj.js → c4Diagram-AAUBKEIU-CKZ_jy81.js} +1 -1
  52. package/packages/web/dist/assets/channel-CjwDi1A9.js +2 -0
  53. package/packages/web/dist/assets/{chunk-2J33WTMH-C3P-O4C3.js → chunk-2J33WTMH-5o96lthu.js} +1 -1
  54. package/packages/web/dist/assets/{chunk-4BX2VUAB-Cs9u7x61.js → chunk-4BX2VUAB-38_pZfd8.js} +1 -1
  55. package/packages/web/dist/assets/{chunk-55IACEB6-C1st284U.js → chunk-55IACEB6-Db73LvlE.js} +1 -1
  56. package/packages/web/dist/assets/{chunk-727SXJPM-BjCAWo7B.js → chunk-727SXJPM-C-Q1-wUu.js} +1 -1
  57. package/packages/web/dist/assets/{chunk-AQP2D5EJ-BP6S9w2Q.js → chunk-AQP2D5EJ-ClJigITk.js} +1 -1
  58. package/packages/web/dist/assets/{chunk-FMBD7UC4-C3ySTaPs.js → chunk-FMBD7UC4-BVzSX2hw.js} +1 -1
  59. package/packages/web/dist/assets/{chunk-ND2GUHAM-eNPD4vzc.js → chunk-ND2GUHAM-DJlL-ELa.js} +1 -1
  60. package/packages/web/dist/assets/{chunk-QZHKN3VN-BbBpgHkO.js → chunk-QZHKN3VN-BC0QEk6w.js} +1 -1
  61. package/packages/web/dist/assets/classDiagram-4FO5ZUOK-CxiNtY3i.js +2 -0
  62. package/packages/web/dist/assets/classDiagram-v2-Q7XG4LA2-CxiNtY3i.js +2 -0
  63. package/packages/web/dist/assets/{core-ZwDDec0y.js → core-VUdoTe9w.js} +1 -1
  64. package/packages/web/dist/assets/cose-bilkent-S5V4N54A-DVqArcBy.js +2 -0
  65. package/packages/web/dist/assets/{dagre-BM42HDAG-DKIEUM4M.js → dagre-BM42HDAG-BgFGyUdv.js} +1 -1
  66. package/packages/web/dist/assets/{diagram-2AECGRRQ-CqlX7j8t.js → diagram-2AECGRRQ-BqdZmJt3.js} +1 -1
  67. package/packages/web/dist/assets/{diagram-5GNKFQAL-Dph5apqo.js → diagram-5GNKFQAL-DeLPu8jT.js} +1 -1
  68. package/packages/web/dist/assets/{diagram-KO2AKTUF-TW6LyHGt.js → diagram-KO2AKTUF-BqTiTGay.js} +1 -1
  69. package/packages/web/dist/assets/{diagram-LMA3HP47-BxxIIv5a.js → diagram-LMA3HP47-CbpAvCgl.js} +1 -1
  70. package/packages/web/dist/assets/{diagram-OG6HWLK6-B8M0DeV7.js → diagram-OG6HWLK6-C4h0V97s.js} +1 -1
  71. package/packages/web/dist/assets/{erDiagram-TEJ5UH35-Bfpy6UQa.js → erDiagram-TEJ5UH35-Dwz77uRx.js} +1 -1
  72. package/packages/web/dist/assets/{flowDiagram-I6XJVG4X-DstRzxek.js → flowDiagram-I6XJVG4X-DSikJnZR.js} +1 -1
  73. package/packages/web/dist/assets/ganttDiagram-6RSMTGT7-DkAGNZb3.js +293 -0
  74. package/packages/web/dist/assets/{gitGraphDiagram-PVQCEYII-CX4IozE-.js → gitGraphDiagram-PVQCEYII-BQtzt9hP.js} +1 -1
  75. package/packages/web/dist/assets/index-BN3rLMpD.js +71 -0
  76. package/packages/web/dist/assets/index-Dfzb1DvL.css +1 -0
  77. package/packages/web/dist/assets/{infoDiagram-5YYISTIA-CG2qCk6u.js → infoDiagram-5YYISTIA-YcaBUjeC.js} +1 -1
  78. package/packages/web/dist/assets/{ishikawaDiagram-YF4QCWOH-CPErvl3a.js → ishikawaDiagram-YF4QCWOH-BfLZB88u.js} +1 -1
  79. package/packages/web/dist/assets/{journeyDiagram-JHISSGLW-Bm6krUsf.js → journeyDiagram-JHISSGLW-DwaFhd6C.js} +1 -1
  80. package/packages/web/dist/assets/{kanban-definition-UN3LZRKU-B4CC8CAx.js → kanban-definition-UN3LZRKU-e9P3WxsD.js} +1 -1
  81. package/packages/web/dist/assets/{linear-CJ1DbrOX.js → linear-CsXS5LTz.js} +1 -1
  82. package/packages/web/dist/assets/{mermaid.core-Dk2kkhf9.js → mermaid.core-DsA72Qyi.js} +4 -4
  83. package/packages/web/dist/assets/{mindmap-definition-RKZ34NQL-CThvf_YD.js → mindmap-definition-RKZ34NQL-DyLOITDI.js} +1 -1
  84. package/packages/web/dist/assets/{pieDiagram-4H26LBE5-DvkHcng6.js → pieDiagram-4H26LBE5-C36aM3D-.js} +1 -1
  85. package/packages/web/dist/assets/{quadrantDiagram-W4KKPZXB-CqhrTh9q.js → quadrantDiagram-W4KKPZXB-Cq1zTk6a.js} +1 -1
  86. package/packages/web/dist/assets/{requirementDiagram-4Y6WPE33-CZykiLym.js → requirementDiagram-4Y6WPE33-B6MctUk7.js} +1 -1
  87. package/packages/web/dist/assets/{sankeyDiagram-5OEKKPKP-D-TzCKMx.js → sankeyDiagram-5OEKKPKP-CaNRUoPR.js} +1 -1
  88. package/packages/web/dist/assets/{sequenceDiagram-3UESZ5HK-C5pIItVu.js → sequenceDiagram-3UESZ5HK-DDj_tZiQ.js} +1 -1
  89. package/packages/web/dist/assets/{stateDiagram-AJRCARHV-DE6G2JfB.js → stateDiagram-AJRCARHV-DDaMlLyK.js} +1 -1
  90. package/packages/web/dist/assets/stateDiagram-v2-BHNVJYJU-Bu6Swk2T.js +2 -0
  91. package/packages/web/dist/assets/{timeline-definition-PNZ67QCA-C1VK2OfU.js → timeline-definition-PNZ67QCA-bMP-7Wam.js} +1 -1
  92. package/packages/web/dist/assets/{vennDiagram-CIIHVFJN-CtOozEwa.js → vennDiagram-CIIHVFJN-9nzKgc0Y.js} +1 -1
  93. package/packages/web/dist/assets/{wardley-L42UT6IY-DvHGK-lb.js → wardley-L42UT6IY-DIWbAFW5.js} +1 -1
  94. package/packages/web/dist/assets/{wardleyDiagram-YWT4CUSO-DxKwZ3-G.js → wardleyDiagram-YWT4CUSO-CVL3skbs.js} +1 -1
  95. package/packages/web/dist/assets/{xychartDiagram-2RQKCTM6-HM4j3l6y.js → xychartDiagram-2RQKCTM6-DHoVPvll.js} +1 -1
  96. package/packages/web/dist/index.html +2 -2
  97. package/packages/web/dist/sw.js +1 -1
  98. package/packages/web/dist/assets/Chip-Db--PJFH.js +0 -2
  99. package/packages/web/dist/assets/DiscoverPage-BFo4FTzZ.js +0 -2
  100. package/packages/web/dist/assets/DiscoverView-C4hOB3nr.js +0 -2
  101. package/packages/web/dist/assets/InstanceConfigPage-U78M95nW.js +0 -2
  102. package/packages/web/dist/assets/ProjectMenu-BxQu14ze.js +0 -2
  103. package/packages/web/dist/assets/ProjectView-FUcyJMUf.js +0 -13
  104. package/packages/web/dist/assets/RootHome-SIxo-xX9.js +0 -2
  105. package/packages/web/dist/assets/architectureDiagram-3BPJPVTR-Wwpf4cvW.js +0 -37
  106. package/packages/web/dist/assets/channel-DEmtNKeB.js +0 -2
  107. package/packages/web/dist/assets/classDiagram-4FO5ZUOK-dAGAuccL.js +0 -2
  108. package/packages/web/dist/assets/classDiagram-v2-Q7XG4LA2-dAGAuccL.js +0 -2
  109. package/packages/web/dist/assets/cose-bilkent-S5V4N54A-DiM4eeF5.js +0 -2
  110. package/packages/web/dist/assets/ganttDiagram-6RSMTGT7-Bg0oFbAl.js +0 -293
  111. package/packages/web/dist/assets/index-ASW1Jl0Y.js +0 -71
  112. package/packages/web/dist/assets/index-bC5uCujx.css +0 -1
  113. package/packages/web/dist/assets/stateDiagram-v2-BHNVJYJU-BP6oowh1.js +0 -2
@@ -0,0 +1,214 @@
1
+ /**
2
+ * Named config profiles (#878) — `paranoid` / `balanced` / `yolo`.
3
+ *
4
+ * Paddock has a dozen independent security/capability levers, each with its own
5
+ * code default. A profile is the single place to express *posture* — "locked
6
+ * down" / "full capability" — instead of hand-setting twelve `PADDOCK_*` vars.
7
+ *
8
+ * ## Why this is a resolved key, not something an installer writes
9
+ *
10
+ * Config resolves as code default < YAML file < `PADDOCK_*` env. A profile
11
+ * implemented as "the installer materialises concrete values into
12
+ * `paddock.config.yaml`" only ever touches the FILE layer — so it only works on
13
+ * the one distribution that runs an installer. Docker and bare `node dist` would
14
+ * keep falling through to code defaults and the distributions would stay
15
+ * divergent, which is the actual complaint #878 opens with. Resolving `profile`
16
+ * at every layer — file, env, and a code default underneath both — is what makes
17
+ * every distribution converge on the same posture.
18
+ *
19
+ * ## Where a profile sits in the precedence chain
20
+ *
21
+ * A profile supplies the DEFAULT that each lever's loader falls back to. It does
22
+ * not become a config layer of its own. So the full chain is:
23
+ *
24
+ * code-default profile < resolved profile < individual file key < individual env var
25
+ *
26
+ * The consequence worth stating out loud, because it inverts this codebase's
27
+ * otherwise universal env-beats-file rule: **an individual key in the YAML file
28
+ * beats `PADDOCK_PROFILE` in the env.** `PADDOCK_PROFILE=paranoid` with
29
+ * `claude: {hooks: host}` in a mounted file resolves hooks to `host`.
30
+ *
31
+ * That is deliberate — specific beats general. `PADDOCK_PROFILE` is a statement
32
+ * about the dozen levers you did NOT mention; a key you wrote by hand is a
33
+ * statement about the one you did. The alternative makes the env var a blunt
34
+ * instrument that silently discards deliberate per-key config, which is a worse
35
+ * failure than the surprise of a file winning. (Env still beats file for the same
36
+ * key, exactly as everywhere else: `PADDOCK_CLAUDE_HOOKS` beats
37
+ * `claude.hooks`.)
38
+ *
39
+ * ## Posture keys only
40
+ *
41
+ * Profiles govern the `claude:` inheritance modes, `maxSpawnDepth`, and the
42
+ * capability toggles — and define ALL of them (see `POSTURE_KEYS`, pinned by a
43
+ * test). They are silent on operational keys (port, data dir, bind host, auth,
44
+ * models, drive mode, curation/recovery/attachments, git author). Switching
45
+ * profile must never change your port or clobber your auth config.
46
+ *
47
+ * ## Two guardrails
48
+ *
49
+ * - Profiles stay orthogonal to bind address and auth. `yolo` must NOT open the
50
+ * bind or relax auth — network exposure remains its own explicit decision,
51
+ * already gated by the dangerous-allow-open opt-in. Otherwise "yolo" quietly
52
+ * becomes "yolo, reachable from the whole network".
53
+ * - `host` resolves against whatever `~/.claude` actually exists: rich on a
54
+ * workstation, typically empty in a container. **The profile sets the levers,
55
+ * the environment sets the blast radius** — which is why the permissive
56
+ * profiles are far more reasonable in a disposable container than on a primary
57
+ * machine.
58
+ */
59
+ import { DEFAULT_MAX_SPAWN_DEPTH } from "./spawn-capability.js";
60
+ /** The three built-in profiles, in ascending order of capability. */
61
+ export const PROFILE_NAMES = ["paranoid", "balanced", "yolo"];
62
+ /**
63
+ * The code-default profile (#878).
64
+ *
65
+ * `balanced` rather than `paranoid` because of the **superset principle**:
66
+ * paddock is a presentation layer over the Claude Code CLI, so its capability
67
+ * surface should be a superset of what the plain CLI already gives you. A user
68
+ * whose CLI has MCP servers configured (and plugin-provided MCP servers, which
69
+ * additionally need `instructions: host`) reasonably expects those to work here;
70
+ * defaulting them off is experienced as a capability regression versus the tool
71
+ * paddock wraps.
72
+ */
73
+ export const DEFAULT_PROFILE = "balanced";
74
+ /**
75
+ * Every posture key, as data — so a test can assert that all three profiles
76
+ * cover exactly this set. Kept in sync with `Posture` by that same test: a key
77
+ * added to the interface but not here fails to typecheck against
78
+ * `Record<keyof Posture, …>` at the `PROFILES` declaration below.
79
+ */
80
+ export const POSTURE_KEYS = [
81
+ "transcripts",
82
+ "credentials",
83
+ "instructions",
84
+ "hooks",
85
+ "mcpServers",
86
+ "maxSpawnDepth",
87
+ "selfMcpEnabled",
88
+ "selfMcpWriteEnabled",
89
+ "selfMcpProjectsEnabled",
90
+ "scheduleMutationEnabled",
91
+ "hooksMcpEnabled",
92
+ "browserMcp",
93
+ ];
94
+ /**
95
+ * The three postures. All three define the same key set, differing only in
96
+ * values — so a diff between two columns is a diff in posture, never in
97
+ * coverage.
98
+ *
99
+ * Two choices here are argued rather than assumed:
100
+ *
101
+ * - **`hooks: own` in `balanced`.** Host hooks are shell commands that fire
102
+ * AUTOMATICALLY on every matching tool call — inherited arbitrary code
103
+ * execution. That is a different risk class from MCP servers, which are tools
104
+ * an agent deliberately chooses to call. So `hooks` does not ride along with
105
+ * the other `host` modes; it is `host` only under `yolo`.
106
+ * - **`browserMcp: false` in `balanced`.** It needs a browser installed on the
107
+ * box. Enabling it by default on a host without one leads agents to fall back
108
+ * to scripting a system browser instead, which is worse than not having it.
109
+ */
110
+ export const PROFILES = {
111
+ /**
112
+ * Everything isolated, every capability off. This is paddock's historical code
113
+ * default, unchanged — `profiles.test.ts` pins it against the legacy
114
+ * `DEFAULT_*` constants, so selecting it is a no-op for anyone who was relying
115
+ * on those. `credentials` is the one lever that was never `own` by default:
116
+ * reading a login risks no file of the user's, and an instance that boots
117
+ * clean then fails every turn (#683) is the worse failure.
118
+ */
119
+ paranoid: {
120
+ transcripts: "own",
121
+ credentials: "host",
122
+ instructions: "own",
123
+ hooks: "own",
124
+ mcpServers: "own",
125
+ maxSpawnDepth: DEFAULT_MAX_SPAWN_DEPTH,
126
+ selfMcpEnabled: false,
127
+ selfMcpWriteEnabled: false,
128
+ selfMcpProjectsEnabled: false,
129
+ scheduleMutationEnabled: false,
130
+ hooksMcpEnabled: false,
131
+ browserMcp: false,
132
+ },
133
+ /**
134
+ * The default. Inherits the CAPABILITIES the host CLI already gives the user —
135
+ * `instructions`, `mcpServers`, and the plugins that ride on the former — and
136
+ * turns on read-only self-MCP, while leaving the genuinely additive/riskier
137
+ * ones off: write-side self-MCP, project creation, schedule mutation, hooks
138
+ * MCP, host hooks, deeper spawning.
139
+ *
140
+ * **`transcripts` stays `own`, against #878's original table.** The superset
141
+ * principle is an argument about capability: withholding the MCP servers and
142
+ * instructions a user has already configured reads as a regression against the
143
+ * tool paddock wraps. Transcripts are not a capability — they are where chat
144
+ * history physically lives. Sharing them makes paddock no more capable, and it
145
+ * changes what an existing verb MEANS: under `host` a delete *releases* a
146
+ * transcript rather than removing it (#689), because it is the user's history
147
+ * rather than paddock's copy. Defaulting that on would silently stop chat
148
+ * deletion from deleting, and would couple a brand-new instance to
149
+ * `~/.claude/projects` on first boot.
150
+ *
151
+ * It is also the status quo, so this half of the profile change is a no-op on
152
+ * upgrade. The cost — that flipping to `host` later is currently broken (#708)
153
+ * — is repaid by the guided migration specified in #882, which is what makes
154
+ * `own` a starting posture rather than a permanent one.
155
+ */
156
+ balanced: {
157
+ transcripts: "own",
158
+ credentials: "host",
159
+ instructions: "host",
160
+ hooks: "own",
161
+ mcpServers: "host",
162
+ maxSpawnDepth: DEFAULT_MAX_SPAWN_DEPTH,
163
+ selfMcpEnabled: true,
164
+ selfMcpWriteEnabled: false,
165
+ selfMcpProjectsEnabled: false,
166
+ scheduleMutationEnabled: false,
167
+ hooksMcpEnabled: false,
168
+ browserMcp: false,
169
+ },
170
+ /**
171
+ * Full capability. Note what it still does NOT do: it does not touch the bind
172
+ * address or auth (see the guardrail in this file's header).
173
+ */
174
+ yolo: {
175
+ transcripts: "host",
176
+ credentials: "host",
177
+ instructions: "host",
178
+ hooks: "host",
179
+ mcpServers: "host",
180
+ maxSpawnDepth: 2,
181
+ selfMcpEnabled: true,
182
+ selfMcpWriteEnabled: true,
183
+ selfMcpProjectsEnabled: true,
184
+ scheduleMutationEnabled: true,
185
+ hooksMcpEnabled: true,
186
+ browserMcp: true,
187
+ },
188
+ };
189
+ /** Whether `v` names a built-in profile. */
190
+ export function isKnownProfile(v) {
191
+ return PROFILE_NAMES.includes(v);
192
+ }
193
+ /**
194
+ * Resolve the profile NAME from env > file > {@link DEFAULT_PROFILE}.
195
+ *
196
+ * An unrecognised name falls back to the default rather than failing the boot —
197
+ * the rule every other enum in `config.ts` follows (`driveMode`, the `claude:`
198
+ * modes, whisper `mode`). The direction is defensible here in a way it is not
199
+ * for a single lever: the fallback is `balanced`, so a typo can only ever land
200
+ * you on the same posture a config-less instance already has, never on `yolo`.
201
+ *
202
+ * Deliberately NOT tsconfig-style `extends`: a closed set of names, one level,
203
+ * no chains, no path resolution. The inheritance is fine; arbitrary-file
204
+ * inheritance graphs are what make `extends` unpleasant.
205
+ */
206
+ export function resolveProfileName(fileVal, env = process.env) {
207
+ const raw = env.PADDOCK_PROFILE?.trim() || (fileVal === undefined || fileVal === null ? "" : String(fileVal).trim());
208
+ const name = raw.toLowerCase();
209
+ return name && isKnownProfile(name) ? name : DEFAULT_PROFILE;
210
+ }
211
+ /** The posture a profile name expands to. */
212
+ export function posture(name) {
213
+ return PROFILES[name];
214
+ }
@@ -0,0 +1,61 @@
1
+ /**
2
+ * Instance-level transcript-migration routes (#882).
3
+ *
4
+ * GET /api/transcripts/migration → the banner's probe. Cheap.
5
+ * GET /api/transcripts/migration/chats → the modal's per-chat plan.
6
+ * POST /api/transcripts/migration → execute: quiesce, move, commit.
7
+ *
8
+ * ## Steps 1–3 of §4.1 are here, and that is deliberate
9
+ *
10
+ * The execute ordering is
11
+ * `single-flight → expectedVersion → quiesce → re-enumerate → move → write
12
+ * config`, and the first three are refusals: when any of them fires, NOTHING
13
+ * may have moved. The cleanest way to guarantee that is for them to run in the
14
+ * route, before `executeMigration` — which owns the mover — is entered at all.
15
+ * The config write is handed to it as a callback for the mirror-image reason:
16
+ * it is the COMMIT POINT and must be last, so the module that decides whether
17
+ * every project reached the postcondition is the module that gets to call it.
18
+ *
19
+ * The reverse order (config first) was rejected in the design: a crash between
20
+ * a config saying `host` and files still in `.chats/` is a genuine #708 split,
21
+ * where a crash the other way is the transient blank list #882 already tells
22
+ * the user to expect, and which re-running reconciles.
23
+ *
24
+ * ## Why two paths rather than one with `?summary=`
25
+ *
26
+ * The same reason `routes/discover.ts:9-18` gives for its own pair: paddock
27
+ * publishes an OpenAPI 3 document generated from these Fastify route schemas,
28
+ * and one path cannot describe two different 200 bodies there — it would have
29
+ * to be `additionalProperties: true` with no shape at all, which is the defect
30
+ * #822 was filed about. Cost confirms it independently: the probe is a readdir
31
+ * per project, the plan can be a second of scanning, and they have different
32
+ * call sites (every page load vs. when the modal opens).
33
+ *
34
+ * ## These schemas are deliberately NOT the house style
35
+ *
36
+ * Every other `response.200` in `packages/server/src/routes/` is
37
+ * `additionalProperties: true` with the real shape in English in the
38
+ * `description`. #822's stated preference is that shapes belong in the route
39
+ * schemas so the published spec describes them, so these two are written out in
40
+ * full: named fields, `required`, closed enums, `additionalProperties: false`.
41
+ *
42
+ * Treat the Fastify consequence as a feature: response serialization STRIPS
43
+ * undeclared keys, so a field added to the DTO and forgotten here disappears at
44
+ * runtime and the integration test catches it, rather than shipping
45
+ * undocumented.
46
+ *
47
+ * ## This reads `~/.claude`, and that is a posture change
48
+ *
49
+ * Under `transcripts: own` nothing in the user's own Claude home was read at
50
+ * all — `transcripts.ts` and `guides/what-paddock-touches.md` both promised
51
+ * exactly that. Telling `new` from `fast-forward` is impossible without reading
52
+ * it, so the plan endpoint does. It is behind its own route precisely so it is
53
+ * something the SPA asks for rather than something a fleet poll does silently,
54
+ * and both of those promises have been narrowed to match (design §8).
55
+ */
56
+ import type { FastifyInstance } from "fastify";
57
+ import type { RouteCtx } from "../route-context.js";
58
+ /** Drop the single-flight latch. For tests, and for a process that somehow
59
+ * leaked one — a stuck latch would refuse every future migration. */
60
+ export declare function resetMigrationSingleFlight(): void;
61
+ export declare function registerTranscriptsRoutes(app: FastifyInstance, ctx: RouteCtx): void;