@edspencer/paddock 0.63.0 → 0.64.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/adoptable.d.ts +18 -0
- package/packages/server/dist/adoptable.js +1 -1
- package/packages/server/dist/app.js +3 -1
- package/packages/server/dist/claude-home.js +9 -1
- package/packages/server/dist/cli/import-chats.js +1 -1
- package/packages/server/dist/git.d.ts +44 -1
- package/packages/server/dist/git.js +79 -11
- package/packages/server/dist/management-ops.js +2 -1
- package/packages/server/dist/project-paths.d.ts +72 -4
- package/packages/server/dist/project-paths.js +76 -4
- package/packages/server/dist/project-types.d.ts +109 -11
- package/packages/server/dist/projects.d.ts +161 -3
- package/packages/server/dist/projects.js +466 -64
- package/packages/server/dist/routes/git.js +6 -3
- package/packages/server/dist/routes/projects.js +16 -2
- package/packages/server/dist/self-mcp-types.d.ts +6 -4
- package/packages/server/dist/sweep.js +10 -5
- package/packages/server/package.json +1 -1
- package/packages/web/dist/assets/{InstanceConfigPage-CCk2hVT9.js → InstanceConfigPage-Blr1a-hx.js} +1 -1
- package/packages/web/dist/assets/{MarkdownRenderer-B6gST_0U.js → MarkdownRenderer-R6YzfI9Y.js} +1 -1
- package/packages/web/dist/assets/{ProjectRedirect-BCmKT4mf.js → ProjectRedirect-Cy-7Thc-.js} +1 -1
- package/packages/web/dist/assets/{ProjectView-CCN98MWu.js → ProjectView-bMX4GEau.js} +9 -9
- package/packages/web/dist/assets/{ProjectsGrid-CYzuN_yD.js → ProjectsGrid-C9XHf4eS.js} +1 -1
- package/packages/web/dist/assets/{arc-BxvtMCZQ.js → arc-B_42F7Yk.js} +1 -1
- package/packages/web/dist/assets/{architectureDiagram-3BPJPVTR-Bp6ffJ_u.js → architectureDiagram-3BPJPVTR-BAXzSOyw.js} +1 -1
- package/packages/web/dist/assets/{blockDiagram-GPEHLZMM-BIY2X8nW.js → blockDiagram-GPEHLZMM-BdYEdA-3.js} +1 -1
- package/packages/web/dist/assets/{c4Diagram-AAUBKEIU-Br9stEJS.js → c4Diagram-AAUBKEIU-Cc4o15R5.js} +1 -1
- package/packages/web/dist/assets/channel-BZnRb_8C.js +2 -0
- package/packages/web/dist/assets/{chunk-2J33WTMH-Djc7uqMV.js → chunk-2J33WTMH-CeuxHjIm.js} +1 -1
- package/packages/web/dist/assets/{chunk-4BX2VUAB-yEVMLksS.js → chunk-4BX2VUAB-DnZfrAaV.js} +1 -1
- package/packages/web/dist/assets/{chunk-55IACEB6-tJaEdPZg.js → chunk-55IACEB6-DFE6UYOT.js} +1 -1
- package/packages/web/dist/assets/{chunk-727SXJPM-bWEqh672.js → chunk-727SXJPM-YVHQ5cHc.js} +1 -1
- package/packages/web/dist/assets/{chunk-AQP2D5EJ-B8U9fB-T.js → chunk-AQP2D5EJ-5BYSbg-F.js} +1 -1
- package/packages/web/dist/assets/{chunk-FMBD7UC4-BeEITYig.js → chunk-FMBD7UC4-HBcelndR.js} +1 -1
- package/packages/web/dist/assets/{chunk-ND2GUHAM-L2rpLaoK.js → chunk-ND2GUHAM-2AwEsdxJ.js} +1 -1
- package/packages/web/dist/assets/{chunk-QZHKN3VN-qqzPMZL_.js → chunk-QZHKN3VN-BPpaZ6ct.js} +1 -1
- package/packages/web/dist/assets/classDiagram-4FO5ZUOK-BGCpL0-K.js +2 -0
- package/packages/web/dist/assets/classDiagram-v2-Q7XG4LA2-BGCpL0-K.js +2 -0
- package/packages/web/dist/assets/{core-CSaNbmLO.js → core-Cu_4vw1U.js} +1 -1
- package/packages/web/dist/assets/{cose-bilkent-S5V4N54A-BRF7Nech.js → cose-bilkent-S5V4N54A-DWkF0NrF.js} +1 -1
- package/packages/web/dist/assets/{dagre-BM42HDAG-D10rJWOR.js → dagre-BM42HDAG-DTgNmO9I.js} +1 -1
- package/packages/web/dist/assets/{diagram-2AECGRRQ-DGjT5mAO.js → diagram-2AECGRRQ-DC28b7YS.js} +1 -1
- package/packages/web/dist/assets/{diagram-5GNKFQAL-DaH3bxHh.js → diagram-5GNKFQAL-_WvuLno6.js} +1 -1
- package/packages/web/dist/assets/{diagram-KO2AKTUF-QrLW9Wn6.js → diagram-KO2AKTUF-BEYxPfWq.js} +1 -1
- package/packages/web/dist/assets/{diagram-LMA3HP47-BX15wgYN.js → diagram-LMA3HP47-Biyev7x0.js} +1 -1
- package/packages/web/dist/assets/{diagram-OG6HWLK6-DXQ_p63s.js → diagram-OG6HWLK6-u47NLW3S.js} +1 -1
- package/packages/web/dist/assets/{erDiagram-TEJ5UH35-C_ioRruE.js → erDiagram-TEJ5UH35-Bud2ISlK.js} +1 -1
- package/packages/web/dist/assets/{flowDiagram-I6XJVG4X-7d-xLXLM.js → flowDiagram-I6XJVG4X-D-18vLQ1.js} +1 -1
- package/packages/web/dist/assets/{format-BSDZezwD.js → format-CQ2BDlby.js} +1 -1
- package/packages/web/dist/assets/{ganttDiagram-6RSMTGT7-DZYx5xcj.js → ganttDiagram-6RSMTGT7-CzyRX39N.js} +1 -1
- package/packages/web/dist/assets/{gitGraphDiagram-PVQCEYII-dimo-osm.js → gitGraphDiagram-PVQCEYII-DLogfrjg.js} +1 -1
- package/packages/web/dist/assets/{index-CUnFKMga.js → index-B0gJ0qWe.js} +14 -14
- package/packages/web/dist/assets/{infoDiagram-5YYISTIA-BzApY25x.js → infoDiagram-5YYISTIA-OgNPt6RG.js} +1 -1
- package/packages/web/dist/assets/{ishikawaDiagram-YF4QCWOH-DtX47_9p.js → ishikawaDiagram-YF4QCWOH-CrM0t0_X.js} +1 -1
- package/packages/web/dist/assets/{journeyDiagram-JHISSGLW-C7fITKg1.js → journeyDiagram-JHISSGLW-xbxfHfwR.js} +1 -1
- package/packages/web/dist/assets/{kanban-definition-UN3LZRKU-BOrWLf_W.js → kanban-definition-UN3LZRKU-DpszBaZb.js} +1 -1
- package/packages/web/dist/assets/{linear-DuyAaBu6.js → linear-BLujdbjQ.js} +1 -1
- package/packages/web/dist/assets/{mermaid.core-BQlzuVvO.js → mermaid.core-DzEhy9Qq.js} +4 -4
- package/packages/web/dist/assets/{mindmap-definition-RKZ34NQL-CmP748B5.js → mindmap-definition-RKZ34NQL-DaH3Lmoo.js} +1 -1
- package/packages/web/dist/assets/{pieDiagram-4H26LBE5-CRd5Pdfq.js → pieDiagram-4H26LBE5-BxeW1kuf.js} +1 -1
- package/packages/web/dist/assets/{quadrantDiagram-W4KKPZXB-DpJm0Yw_.js → quadrantDiagram-W4KKPZXB-BKs2CT0r.js} +1 -1
- package/packages/web/dist/assets/{requirementDiagram-4Y6WPE33-B0o2PRMC.js → requirementDiagram-4Y6WPE33-CVdO-hXD.js} +1 -1
- package/packages/web/dist/assets/{sankeyDiagram-5OEKKPKP-CBi3Ek3v.js → sankeyDiagram-5OEKKPKP-yusj_kJC.js} +1 -1
- package/packages/web/dist/assets/{sequenceDiagram-3UESZ5HK-C1stxfQg.js → sequenceDiagram-3UESZ5HK-C0h-9c8Y.js} +1 -1
- package/packages/web/dist/assets/{stateDiagram-AJRCARHV-lCkiETWK.js → stateDiagram-AJRCARHV-BSBY8Psb.js} +1 -1
- package/packages/web/dist/assets/stateDiagram-v2-BHNVJYJU-4DGE0Z1g.js +2 -0
- package/packages/web/dist/assets/{timeline-definition-PNZ67QCA-D3DkWJMC.js → timeline-definition-PNZ67QCA-DEFUdNb8.js} +1 -1
- package/packages/web/dist/assets/{vennDiagram-CIIHVFJN-CO2-yC7K.js → vennDiagram-CIIHVFJN-DunhMqxK.js} +1 -1
- package/packages/web/dist/assets/{wardley-L42UT6IY-Dfjp0kqX.js → wardley-L42UT6IY-CXJsBGKl.js} +1 -1
- package/packages/web/dist/assets/{wardleyDiagram-YWT4CUSO-CIl0OPwS.js → wardleyDiagram-YWT4CUSO-DfT_-dqX.js} +1 -1
- package/packages/web/dist/assets/{xychartDiagram-2RQKCTM6-CuvlQuup.js → xychartDiagram-2RQKCTM6-BysTtULW.js} +1 -1
- package/packages/web/dist/index.html +1 -1
- package/packages/web/dist/sw.js +1 -1
- package/packages/web/dist/assets/channel-CMdgNeFH.js +0 -2
- package/packages/web/dist/assets/classDiagram-4FO5ZUOK-DU4HSESS.js +0 -2
- package/packages/web/dist/assets/classDiagram-v2-Q7XG4LA2-DU4HSESS.js +0 -2
- package/packages/web/dist/assets/stateDiagram-v2-BHNVJYJU-ZgEZRNqp.js +0 -2
|
@@ -1,12 +1,28 @@
|
|
|
1
1
|
import { IMAGE_MIME, VIDEO_MIME, DOCUMENT_MIME, fileKind, contentTypeFor } from "./project-mime.js";
|
|
2
2
|
export { IMAGE_MIME, VIDEO_MIME, DOCUMENT_MIME, fileKind, contentTypeFor };
|
|
3
|
-
import { ROOT_KEY, isRootKey, isValidRepoUrl, repoCheckoutName, workingDirFor, slugify, ProjectError } from "./project-paths.js";
|
|
4
|
-
export { ROOT_KEY, isRootKey, isValidRepoUrl, repoCheckoutName, workingDirFor, slugify, ProjectError, };
|
|
3
|
+
import { ROOT_KEY, isRootKey, isPathInside, isManaged, contentDirFor, isValidRepoUrl, repoCheckoutName, workingDirFor, slugify, ProjectError } from "./project-paths.js";
|
|
4
|
+
export { ROOT_KEY, isRootKey, isPathInside, isManaged, contentDirFor, isValidRepoUrl, repoCheckoutName, workingDirFor, slugify, ProjectError, };
|
|
5
5
|
import { type Project, type FileKind, type FileEntry, type CreateProjectInput, type UpdateProjectInput } from "./project-types.js";
|
|
6
6
|
export * from "./project-types.js";
|
|
7
7
|
export declare class ProjectStore {
|
|
8
8
|
private readonly root;
|
|
9
|
-
|
|
9
|
+
private readonly dataDir?;
|
|
10
|
+
private readonly log;
|
|
11
|
+
/**
|
|
12
|
+
* @param root The projects root (`cfg.projectsRoot`) — every project's metadata dir.
|
|
13
|
+
* @param dataDir The instance data dir (`cfg.dataDir`), used ONLY to reject a
|
|
14
|
+
* `path:` that points inside Paddock's own state (issue #206). Optional so the
|
|
15
|
+
* many tests that construct a bare store keep compiling; when omitted, `root`
|
|
16
|
+
* alone is the containment check (in the default layout `projectsRoot` is
|
|
17
|
+
* `<dataDir>/projects`, so it is the tighter of the two anyway).
|
|
18
|
+
* @param log Where non-fatal advisories go — currently only the declared-repo /
|
|
19
|
+
* actual-remote mismatch on an existing `path` (issue #206), which must be
|
|
20
|
+
* said out loud rather than silently ignored (#659) but must not fail the
|
|
21
|
+
* create. Defaults to a no-op so a bare `new ProjectStore(root)` is unchanged.
|
|
22
|
+
*/
|
|
23
|
+
constructor(root: string, dataDir?: string | undefined, log?: {
|
|
24
|
+
warn: (message: string) => void;
|
|
25
|
+
});
|
|
10
26
|
/** Ensure the projects root exists. Call once at startup. */
|
|
11
27
|
init(): Promise<void>;
|
|
12
28
|
/**
|
|
@@ -40,12 +56,130 @@ export declare class ProjectStore {
|
|
|
40
56
|
* record; the root workspace always exists, record or not.
|
|
41
57
|
*/
|
|
42
58
|
exists(slug: string): Promise<boolean>;
|
|
59
|
+
/**
|
|
60
|
+
* Recursively delete `target`, but ONLY if it is strictly inside `projectsRoot`.
|
|
61
|
+
*
|
|
62
|
+
* The single choke point for every recursive delete in this store. Before issue
|
|
63
|
+
* #206 the containment was implicit: everything a project owned — including a
|
|
64
|
+
* repo-backed project's checkout — was nested under `<projectsRoot>/<slug>/`, so
|
|
65
|
+
* `fs.rm(dir, {recursive: true})` could not reach anything that wasn't ours.
|
|
66
|
+
* A LINKED project's working directory is the user's real work repo, outside the
|
|
67
|
+
* root, and that implicit safety is gone.
|
|
68
|
+
*
|
|
69
|
+
* So the check is made explicit and centralised here rather than re-derived at
|
|
70
|
+
* each call site: an `fs.rm` that escapes throws instead of deleting. Both
|
|
71
|
+
* current callers already only pass in-root paths — this exists so that stays
|
|
72
|
+
* true when someone later adds a third one.
|
|
73
|
+
*/
|
|
74
|
+
private rmInsideRoot;
|
|
75
|
+
/**
|
|
76
|
+
* Undo a failed {@link create} by removing the directories it created — and
|
|
77
|
+
* ONLY those.
|
|
78
|
+
*
|
|
79
|
+
* This is the non-negotiable half of the acquisition rules (issue #206). The
|
|
80
|
+
* previous rollback was an unconditional `fs.rm(dir, {recursive, force})` on the
|
|
81
|
+
* slug dir, safe only because everything a project owned was nested inside it.
|
|
82
|
+
* Once `path:` lets a user nominate a clone TARGET, an unconditional recursive
|
|
83
|
+
* delete is a footgun aimed at whatever they typed — a home directory, say. So
|
|
84
|
+
* the caller records what it brought into being and this removes exactly that
|
|
85
|
+
* list; a pre-existing directory is never in it and therefore can never be
|
|
86
|
+
* deleted, no matter how the create failed.
|
|
87
|
+
*
|
|
88
|
+
* Removed deepest-first so a nested pair (slug dir + its checkout) unwinds
|
|
89
|
+
* cleanly. Failures are swallowed: the original error is the one worth
|
|
90
|
+
* reporting, and a rollback that can't finish must not mask it.
|
|
91
|
+
*/
|
|
92
|
+
private rollback;
|
|
93
|
+
/**
|
|
94
|
+
* Validate a `path:` (issue #206) and return it canonicalised, along with
|
|
95
|
+
* whether it already exists.
|
|
96
|
+
*
|
|
97
|
+
* This is the ONLY gate between a user-supplied string and a directory Paddock
|
|
98
|
+
* will hand an agent as its cwd (and may `git clone` into), so it is
|
|
99
|
+
* deliberately strict and ordered cheapest-first. It rejects:
|
|
100
|
+
*
|
|
101
|
+
* - a relative path (a cwd must be unambiguous — it is baked into every
|
|
102
|
+
* transcript path, and resolving it against the server's cwd is a footgun);
|
|
103
|
+
* - a path that exists but isn't a directory;
|
|
104
|
+
* - a path inside `projectsRoot` or the data dir — that is Paddock's own
|
|
105
|
+
* state, and pointing at it re-creates the nesting this feature exists to
|
|
106
|
+
* avoid (plus `remove()` would then really delete it);
|
|
107
|
+
* - a path that is, contains, or sits inside another project's working
|
|
108
|
+
* directory — two keepers sharing one cwd collide on transcripts (they are
|
|
109
|
+
* keyed by cwd) and on the working tree itself.
|
|
110
|
+
*
|
|
111
|
+
* It deliberately does NOT reject a directory for not being a git repository.
|
|
112
|
+
* That would be the only mandatory git check in the codebase: everywhere else
|
|
113
|
+
* paddock PROBES and degrades (`GitService.isRepo()` → false, the Changes tab
|
|
114
|
+
* removes itself, commit/push return `{error: "not a repo"}`), and the default
|
|
115
|
+
* E2E server runs on a non-git directory on purpose.
|
|
116
|
+
*
|
|
117
|
+
* A MISSING path is not an error here — it is an acquisition instruction, which
|
|
118
|
+
* {@link acquirePath} resolves. Only the existing-path branch can be
|
|
119
|
+
* canonicalised by `realpath`, so for a missing one the containment checks run
|
|
120
|
+
* against the resolved-but-not-real path plus its nearest existing ancestor —
|
|
121
|
+
* otherwise `/tmp/link -> <projectsRoot>` with a missing leaf would slip past.
|
|
122
|
+
*/
|
|
123
|
+
private validatePath;
|
|
124
|
+
/**
|
|
125
|
+
* Canonicalise a path that does not exist yet, by realpath-ing the deepest
|
|
126
|
+
* ancestor that DOES exist and re-appending the missing segments. Used only by
|
|
127
|
+
* {@link validatePath}, so a clone target under a symlinked parent still gets
|
|
128
|
+
* containment-checked against its real location.
|
|
129
|
+
*/
|
|
130
|
+
private resolveViaExistingAncestor;
|
|
131
|
+
/**
|
|
132
|
+
* Bring a project's `path` into existence, returning the directories THIS call
|
|
133
|
+
* created so a failure can roll back exactly those and nothing else.
|
|
134
|
+
*
|
|
135
|
+
* The acquisition rules (issue #206):
|
|
136
|
+
*
|
|
137
|
+
* - path exists ⇒ use it. With `repo` also set, verify the remote matches and
|
|
138
|
+
* WARN on a mismatch rather than silently ignoring `repo` — that is the #659
|
|
139
|
+
* bug class (a directory that is a clone of a *different* repo).
|
|
140
|
+
* - path missing + `repo` ⇒ clone the repo to that path.
|
|
141
|
+
* - path missing, managed ⇒ create the directory; the user is nominating where
|
|
142
|
+
* their notes should live, and an empty dir is a valid notebook.
|
|
143
|
+
* - path missing, unmanaged, no `repo` ⇒ error. There is nothing to acquire
|
|
144
|
+
* from and an empty directory is not a codebase.
|
|
145
|
+
*
|
|
146
|
+
* **Cleanup rule:** `created` only ever gains directories this call brought into
|
|
147
|
+
* being. A pre-existing directory is never appended, so no rollback can delete
|
|
148
|
+
* one — the target is user-nominated and may be a home directory.
|
|
149
|
+
*
|
|
150
|
+
* `created` is an OUT-parameter rather than a return value on purpose. Returning
|
|
151
|
+
* the list would mean the caller only learns what to clean up on the success
|
|
152
|
+
* path: an `acquirePath` that threw would never hand back the directory it had
|
|
153
|
+
* already made, so a clone that died partway through would orphan it. Recording
|
|
154
|
+
* before the risky step is what makes the rollback complete.
|
|
155
|
+
*/
|
|
156
|
+
private acquirePath;
|
|
157
|
+
/**
|
|
158
|
+
* Warn when a directory's git remotes don't include `repo`.
|
|
159
|
+
*
|
|
160
|
+
* Deliberately a warning, not a rejection: the directory the user named is the
|
|
161
|
+
* one they meant, and plenty of legitimate setups (a fork, a mirror, an
|
|
162
|
+
* ssh-vs-https spelling) won't match exactly. But silently ignoring `repo` is
|
|
163
|
+
* how #659 happened, so the mismatch has to be said out loud. A directory with
|
|
164
|
+
* no git at all is not a mismatch — it is just not a repo, which is allowed.
|
|
165
|
+
*
|
|
166
|
+
* Reuses `adoptable.ts`'s reader, which parses `.git/config` directly (no
|
|
167
|
+
* subprocess) and already follows a linked worktree's `gitdir:`/`commondir`
|
|
168
|
+
* pointers, and returns URLs already through {@link normalizeRemote}.
|
|
169
|
+
*/
|
|
170
|
+
private warnOnRemoteMismatch;
|
|
43
171
|
/**
|
|
44
172
|
* Create a project: mkdir + write project.yaml (from template) + seed
|
|
45
173
|
* CHANGELOG.md. Idempotency: throws ProjectError("exists") if the slug
|
|
46
174
|
* directory already holds a project.yaml.
|
|
47
175
|
*/
|
|
48
176
|
create(input: CreateProjectInput): Promise<Project>;
|
|
177
|
+
/**
|
|
178
|
+
* Write a new project's `project.yaml` and seed its content files. Split out of
|
|
179
|
+
* {@link create} so the whole sequence sits inside that method's single
|
|
180
|
+
* try/rollback rather than trailing off the end of it.
|
|
181
|
+
*/
|
|
182
|
+
private finishCreate;
|
|
49
183
|
/**
|
|
50
184
|
* Promote an existing NOTEBOOK project into a REPO-BACKED one IN PLACE (issue
|
|
51
185
|
* #213), preserving its chats + sidecar metadata. This relaxes #187's create-time
|
|
@@ -87,6 +221,21 @@ export declare class ProjectStore {
|
|
|
87
221
|
readChangelog(slug: string): Promise<string>;
|
|
88
222
|
/** Whether OVERVIEW.md exists for this project. */
|
|
89
223
|
overviewExists(slug: string): Promise<boolean>;
|
|
224
|
+
/**
|
|
225
|
+
* {@link overviewExists} for a content dir already in hand.
|
|
226
|
+
*
|
|
227
|
+
* `readSafe` needs this: it has just parsed the yaml, so it can derive the
|
|
228
|
+
* content dir for free, whereas going through the slug would re-read
|
|
229
|
+
* `project.yaml` on every project of every `list()`.
|
|
230
|
+
*/
|
|
231
|
+
private overviewExistsIn;
|
|
232
|
+
/**
|
|
233
|
+
* Where this project's curated trio lives (issue #206) — see
|
|
234
|
+
* {@link contentDirFor}. Falls back to the metadata dir for a slug that names
|
|
235
|
+
* no project, so a caller reading a missing project still gets "" rather than
|
|
236
|
+
* throwing.
|
|
237
|
+
*/
|
|
238
|
+
private contentDirOf;
|
|
90
239
|
/** Read CLAUDE.md, or "" if it doesn't exist yet (issue #177). */
|
|
91
240
|
readClaudeMd(slug: string): Promise<string>;
|
|
92
241
|
/**
|
|
@@ -198,5 +347,14 @@ export declare class ProjectStore {
|
|
|
198
347
|
private ensureSidecarGitignore;
|
|
199
348
|
private writeYaml;
|
|
200
349
|
private toDto;
|
|
350
|
+
/**
|
|
351
|
+
* Drop the derived DTO-only fields, leaving the on-disk shape.
|
|
352
|
+
*
|
|
353
|
+
* `managed` deliberately SURVIVES: it is a real `project.yaml` key, and because
|
|
354
|
+
* the DTO's value is always concrete, the first `update()` of a legacy project
|
|
355
|
+
* pins its derived value explicitly on disk. That is the desired direction —
|
|
356
|
+
* the file stops depending on a default — and it is safe precisely because the
|
|
357
|
+
* value written is the one the derivation already produced.
|
|
358
|
+
*/
|
|
201
359
|
private stripDto;
|
|
202
360
|
}
|