@edspencer/paddock 0.71.2 → 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.
- package/package.json +1 -1
- package/packages/server/dist/app.js +27 -0
- package/packages/server/dist/cli/args.d.ts +56 -5
- package/packages/server/dist/cli/args.js +193 -31
- package/packages/server/dist/cli/config.d.ts +157 -0
- package/packages/server/dist/cli/config.js +462 -0
- package/packages/server/dist/cli/paddock.js +53 -3
- package/packages/server/dist/config.d.ts +36 -1
- package/packages/server/dist/config.js +59 -44
- package/packages/server/dist/herdctl.d.ts +45 -0
- package/packages/server/dist/herdctl.js +58 -4
- package/packages/server/dist/instance-config.d.ts +149 -21
- package/packages/server/dist/instance-config.js +228 -5
- package/packages/server/dist/last-activity.d.ts +21 -0
- package/packages/server/dist/last-activity.js +7 -2
- package/packages/server/dist/profiles.d.ts +154 -0
- package/packages/server/dist/profiles.js +214 -0
- package/packages/server/dist/routes/transcripts.d.ts +61 -0
- package/packages/server/dist/routes/transcripts.js +676 -0
- package/packages/server/dist/routes.d.ts +3 -0
- package/packages/server/dist/routes.js +2 -0
- package/packages/server/dist/transcript-move.d.ts +62 -0
- package/packages/server/dist/transcript-move.js +179 -0
- package/packages/server/dist/transcripts-migration-execute.d.ts +144 -0
- package/packages/server/dist/transcripts-migration-execute.js +630 -0
- package/packages/server/dist/transcripts-migration.d.ts +336 -0
- package/packages/server/dist/transcripts-migration.js +917 -0
- package/packages/server/dist/transcripts.d.ts +46 -2
- package/packages/server/dist/transcripts.js +126 -3
- package/packages/server/package.json +1 -1
- package/packages/web/dist/assets/DiscoverPage-DXI9FjmJ.js +2 -0
- package/packages/web/dist/assets/DiscoverView-D9oqVkT4.js +2 -0
- package/packages/web/dist/assets/InstanceConfigPage-DyH1j5oR.js +2 -0
- package/packages/web/dist/assets/{MarkdownRenderer-DA5CpdGI.js → MarkdownRenderer-D95ofnQ8.js} +1 -1
- package/packages/web/dist/assets/ProjectMenu-BO70tGwy.js +2 -0
- package/packages/web/dist/assets/{ProjectRedirect-k10uM_63.js → ProjectRedirect-BxX_aADU.js} +1 -1
- package/packages/web/dist/assets/ProjectView-BbCyKoh5.js +13 -0
- package/packages/web/dist/assets/{ProjectsGrid-DrzZ7R8M.js → ProjectsGrid-BafOHL43.js} +1 -1
- package/packages/web/dist/assets/RootHome-BGkMypUJ.js +2 -0
- package/packages/web/dist/assets/Surfaces-B8SyV4r3.js +2 -0
- package/packages/web/dist/assets/{arc-BKAVFR26.js → arc-DGyr--oL.js} +1 -1
- package/packages/web/dist/assets/architectureDiagram-3BPJPVTR-BNczNNmx.js +37 -0
- package/packages/web/dist/assets/{blockDiagram-GPEHLZMM-Eu4BV7Ea.js → blockDiagram-GPEHLZMM-DiTvGSrV.js} +1 -1
- package/packages/web/dist/assets/{c4Diagram-AAUBKEIU-DR8PZaoa.js → c4Diagram-AAUBKEIU-CKZ_jy81.js} +1 -1
- package/packages/web/dist/assets/channel-CjwDi1A9.js +2 -0
- package/packages/web/dist/assets/{chunk-2J33WTMH-CgvIIrI1.js → chunk-2J33WTMH-5o96lthu.js} +1 -1
- package/packages/web/dist/assets/{chunk-4BX2VUAB-CyJWrZqN.js → chunk-4BX2VUAB-38_pZfd8.js} +1 -1
- package/packages/web/dist/assets/{chunk-55IACEB6-DXEnZN1d.js → chunk-55IACEB6-Db73LvlE.js} +1 -1
- package/packages/web/dist/assets/{chunk-727SXJPM-Co89QTmp.js → chunk-727SXJPM-C-Q1-wUu.js} +1 -1
- package/packages/web/dist/assets/{chunk-AQP2D5EJ-BRxTzfev.js → chunk-AQP2D5EJ-ClJigITk.js} +1 -1
- package/packages/web/dist/assets/{chunk-FMBD7UC4-DUj18CvF.js → chunk-FMBD7UC4-BVzSX2hw.js} +1 -1
- package/packages/web/dist/assets/{chunk-ND2GUHAM-BQMMJobN.js → chunk-ND2GUHAM-DJlL-ELa.js} +1 -1
- package/packages/web/dist/assets/{chunk-QZHKN3VN-COx8LZCe.js → chunk-QZHKN3VN-BC0QEk6w.js} +1 -1
- package/packages/web/dist/assets/classDiagram-4FO5ZUOK-CxiNtY3i.js +2 -0
- package/packages/web/dist/assets/classDiagram-v2-Q7XG4LA2-CxiNtY3i.js +2 -0
- package/packages/web/dist/assets/{core-DnpcT0s6.js → core-VUdoTe9w.js} +1 -1
- package/packages/web/dist/assets/cose-bilkent-S5V4N54A-DVqArcBy.js +2 -0
- package/packages/web/dist/assets/{dagre-BM42HDAG-CuaYJexd.js → dagre-BM42HDAG-BgFGyUdv.js} +1 -1
- package/packages/web/dist/assets/{diagram-2AECGRRQ-C9_anxrA.js → diagram-2AECGRRQ-BqdZmJt3.js} +1 -1
- package/packages/web/dist/assets/{diagram-5GNKFQAL-Ckf3kFlY.js → diagram-5GNKFQAL-DeLPu8jT.js} +1 -1
- package/packages/web/dist/assets/{diagram-KO2AKTUF-BrpUuY5x.js → diagram-KO2AKTUF-BqTiTGay.js} +1 -1
- package/packages/web/dist/assets/{diagram-LMA3HP47-B9lyXZXW.js → diagram-LMA3HP47-CbpAvCgl.js} +1 -1
- package/packages/web/dist/assets/{diagram-OG6HWLK6-DT7ro32m.js → diagram-OG6HWLK6-C4h0V97s.js} +1 -1
- package/packages/web/dist/assets/{erDiagram-TEJ5UH35-ZZn9bHQh.js → erDiagram-TEJ5UH35-Dwz77uRx.js} +1 -1
- package/packages/web/dist/assets/{flowDiagram-I6XJVG4X-BxQ82PY_.js → flowDiagram-I6XJVG4X-DSikJnZR.js} +1 -1
- package/packages/web/dist/assets/ganttDiagram-6RSMTGT7-DkAGNZb3.js +293 -0
- package/packages/web/dist/assets/{gitGraphDiagram-PVQCEYII-BlwODdH9.js → gitGraphDiagram-PVQCEYII-BQtzt9hP.js} +1 -1
- package/packages/web/dist/assets/index-BN3rLMpD.js +71 -0
- package/packages/web/dist/assets/index-Dfzb1DvL.css +1 -0
- package/packages/web/dist/assets/{infoDiagram-5YYISTIA-nanSBFyG.js → infoDiagram-5YYISTIA-YcaBUjeC.js} +1 -1
- package/packages/web/dist/assets/{ishikawaDiagram-YF4QCWOH-yZHr_s28.js → ishikawaDiagram-YF4QCWOH-BfLZB88u.js} +1 -1
- package/packages/web/dist/assets/{journeyDiagram-JHISSGLW-BKjDqQEQ.js → journeyDiagram-JHISSGLW-DwaFhd6C.js} +1 -1
- package/packages/web/dist/assets/{kanban-definition-UN3LZRKU-QusvHqc6.js → kanban-definition-UN3LZRKU-e9P3WxsD.js} +1 -1
- package/packages/web/dist/assets/{linear-4xRoD38Z.js → linear-CsXS5LTz.js} +1 -1
- package/packages/web/dist/assets/{mermaid.core-CeulYvDv.js → mermaid.core-DsA72Qyi.js} +4 -4
- package/packages/web/dist/assets/{mindmap-definition-RKZ34NQL-DSjYt2Kp.js → mindmap-definition-RKZ34NQL-DyLOITDI.js} +1 -1
- package/packages/web/dist/assets/{pieDiagram-4H26LBE5-Ci0gO3CA.js → pieDiagram-4H26LBE5-C36aM3D-.js} +1 -1
- package/packages/web/dist/assets/{quadrantDiagram-W4KKPZXB-y2qHkaHP.js → quadrantDiagram-W4KKPZXB-Cq1zTk6a.js} +1 -1
- package/packages/web/dist/assets/{requirementDiagram-4Y6WPE33-D9hiWbad.js → requirementDiagram-4Y6WPE33-B6MctUk7.js} +1 -1
- package/packages/web/dist/assets/{sankeyDiagram-5OEKKPKP-DA3Mvoze.js → sankeyDiagram-5OEKKPKP-CaNRUoPR.js} +1 -1
- package/packages/web/dist/assets/{sequenceDiagram-3UESZ5HK-DWACrljw.js → sequenceDiagram-3UESZ5HK-DDj_tZiQ.js} +1 -1
- package/packages/web/dist/assets/{stateDiagram-AJRCARHV-CFGEhoTb.js → stateDiagram-AJRCARHV-DDaMlLyK.js} +1 -1
- package/packages/web/dist/assets/stateDiagram-v2-BHNVJYJU-Bu6Swk2T.js +2 -0
- package/packages/web/dist/assets/{timeline-definition-PNZ67QCA-Cjygpd9e.js → timeline-definition-PNZ67QCA-bMP-7Wam.js} +1 -1
- package/packages/web/dist/assets/{vennDiagram-CIIHVFJN-zQnLaxgv.js → vennDiagram-CIIHVFJN-9nzKgc0Y.js} +1 -1
- package/packages/web/dist/assets/{wardley-L42UT6IY-DGmt-Lo2.js → wardley-L42UT6IY-DIWbAFW5.js} +1 -1
- package/packages/web/dist/assets/{wardleyDiagram-YWT4CUSO-Dj3vDukN.js → wardleyDiagram-YWT4CUSO-CVL3skbs.js} +1 -1
- package/packages/web/dist/assets/{xychartDiagram-2RQKCTM6-C0bGbwbL.js → xychartDiagram-2RQKCTM6-DHoVPvll.js} +1 -1
- package/packages/web/dist/index.html +2 -2
- package/packages/web/dist/sw.js +1 -1
- package/packages/web/dist/assets/Chip-Cp32dDmz.js +0 -2
- package/packages/web/dist/assets/DiscoverPage-Cs439wTf.js +0 -2
- package/packages/web/dist/assets/DiscoverView-DoGAlUXT.js +0 -2
- package/packages/web/dist/assets/InstanceConfigPage-BDypeo_r.js +0 -2
- package/packages/web/dist/assets/ProjectMenu-DXXXtXeh.js +0 -2
- package/packages/web/dist/assets/ProjectView-BxjcMlSO.js +0 -13
- package/packages/web/dist/assets/RootHome-rWodzOC8.js +0 -2
- package/packages/web/dist/assets/architectureDiagram-3BPJPVTR-UzIlxaCQ.js +0 -37
- package/packages/web/dist/assets/channel-C-sodtn7.js +0 -2
- package/packages/web/dist/assets/classDiagram-4FO5ZUOK-D2eBPVdq.js +0 -2
- package/packages/web/dist/assets/classDiagram-v2-Q7XG4LA2-D2eBPVdq.js +0 -2
- package/packages/web/dist/assets/cose-bilkent-S5V4N54A-B-4NadKI.js +0 -2
- package/packages/web/dist/assets/ganttDiagram-6RSMTGT7-BxliloOH.js +0 -293
- package/packages/web/dist/assets/index-Cx9y6c3f.js +0 -71
- package/packages/web/dist/assets/index-bC5uCujx.css +0 -1
- package/packages/web/dist/assets/stateDiagram-v2-BHNVJYJU-CLfbDXLX.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;
|