Repository navigation
Expand file tree
/
Copy pathtypes.ts
More file actions
216 lines (181 loc) · 8.64 KB
/
Copy pathtypes.ts
File metadata and controls
216 lines (181 loc) · 8.64 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
// pridm: data model.
//
// The root type is BulkDelta: a set of changes on a branch compared with its base.
// It may exist only locally (a worktree with commits or edits), only as a PR
// (not checked out), or as both. A delta keeps the same id after a PR is
// opened for it, so its focus setting carries over.
// ─── Root ────────────────────────────────────────────────────
interface BulkDelta {
id: DeltaId;
repo: RepoKey;
branch: string | null; // null = detached HEAD (local only)
base: { ref: string; sha: string }; // PR base if there's a PR, else merge-base with origin/<default>
title: string; // PR title, else the last commit subject, else the branch name
local: LocalCheckout | null;
pr: PullRequest | null;
surfaces: SurfaceRef[]; // live data, rebuilt on every refresh, never saved
source: 'local' | 'pr'; // where the diff comes from: local if checked out, else the PR head
}
// "<repoKey>:<branch>", e.g. "github.com/diffplug/spotless:feat/x".
// Detached HEAD uses "<repoKey>@<worktree path>".
// Known gap: PRs from two forks with the same branch name collide. Fine for "my PRs".
type DeltaId = string;
// The normalized origin remote: host + path, no scheme, user, or ".git".
// git@github.com:diffplug/spotless.git -> "github.com/diffplug/spotless"
// https://github.com/diffplug/spotless.git -> "github.com/diffplug/spotless"
// A clone with no origin uses "file:<absolute path of the main clone>".
type RepoKey = string;
// ─── Local ───────────────────────────────────────────────────
interface LocalCheckout {
path: string; // the worktree root
headSha: string;
uncommitted: { staged: number; unstaged: number; untracked: number };
upstream: { ref: string; ahead: number; behind: number } | null; // null = never pushed
updatedAt: string; // ISO time of the last commit
}
// ─── GitHub ──────────────────────────────────────────────────
interface PullRequest {
number: number;
url: string;
author: string;
state: 'open' | 'draft' | 'merged' | 'closed';
headSha: string;
updatedAt: string;
}
// ─── Dormouse ────────────────────────────────────────────────
// A trimmed-down row from `dor list --json --all`
interface SurfaceRef {
id: string; // "surface:713"
kind: 'terminal' | 'browser' | 'tool';
title: string;
command: string | null; // "claude", "npm run dev", ...
cwd: string | null;
url: string | null;
workspaceId: string;
activity: string;
needsAttention: boolean; // ringing || todo
matchedBy: 'cwd' | 'url'; // cwd inside local.path (longest match wins), or url starts with pr.url
}
// ─── What the UI loads ───────────────────────────────────────
//
// Three levels, each loaded only when needed:
// 1. DeltaSummary[] the dashboard: per-category +/- for every delta
// 2. DeltaOverview one delta: every category collapsed, showing +/- and its file list
// 3. CategoryDiff loaded when you expand a category. This is the expensive
// part: both full versions of every file.
// Line counts come from `git diff --numstat`. Markdown files are also counted
// in words (FileStat.words), which the UI shows instead of lines.
// Category names are defined in categories.json. OTHER is the only built-in one.
type Category = string;
const OTHER: Category = 'other';
type Focus = 'pinned' | 'normal' | 'muted';
// Lists of these are in section order: the origin's order in categories.json,
// with OTHER last. Categories with no changed files are left out.
interface CategoryStat {
category: Category;
fileCount: number;
additions: number;
deletions: number;
words?: WordCounts; // set when every file in the category is markdown
}
// Markdown files are counted in words as well as lines; the UI shows words.
interface WordCounts {
added: number;
removed: number;
}
interface DeltaSummary {
delta: BulkDelta;
focus: Focus;
categories: CategoryStat[];
unavailable?: string; // why this delta can't be opened, e.g. its repo isn't cloned
}
// GET /api/deltas. Warnings are problems that didn't stop the listing,
// e.g. `gh` isn't logged in, so only local checkouts are shown.
interface DeltaList {
deltas: DeltaSummary[];
warnings: string[];
}
interface DeltaOverview {
delta: BulkDelta;
focus?: Focus; // set by the server; fixtures can leave it out
categories: (CategoryStat & { files: FileStat[] })[]; // shown in each collapsed header
}
interface CategoryDiff {
deltaId: DeltaId;
category: Category;
files: FileChange[];
}
// ─── File changes ────────────────────────────────────────────
type FileStatus = 'added' | 'modified' | 'deleted' | 'renamed';
interface FileStat {
path: string;
oldPath?: string; // set when the file was renamed
status: FileStatus;
category: Category;
additions: number;
deletions: number;
isBinary: boolean;
committed: boolean; // false = only in the working tree (local source only)
words?: WordCounts; // markdown files only
}
interface FileChange extends FileStat {
diff: CodeDiff | MarkdownDiff;
}
// Monaco's DiffEditor computes the diff itself and wants both full versions.
// Shown inline (renderSideBySide: false), with unchanged regions folded.
interface CodeDiff {
kind: 'code';
language: string; // Monaco language id, from the file extension
original: string; // '' for an added file
modified: string; // '' for a deleted file
}
// Shown in a read-only MDXEditor in rich-text mode. `merged` is one markdown
// document with deletions as ~~strikethrough~~ and insertions as ==highlight==,
// which MDXEditor's core plugin already renders. CSS colors them red and green.
// It is built on the server: blocks are diffed first, then words inside blocks
// that changed. A changed code block or table can't hold inline marks, so it
// appears twice, old then new.
interface MarkdownDiff {
kind: 'markdown';
original: string;
modified: string;
merged: string;
pieces: MarkdownPiece[]; // `merged`, block by block, so unchanged runs can be hidden
}
// One block of the merged markdown. See src/shared/mdmerge.ts.
interface MarkdownPiece {
text: string;
listItem: boolean; // list items keep their own separators so lists stay tight
sep: string; // the text before this block in its own version
changed: boolean;
}
// ─── Classification ──────────────────────────────────────────
// Category globs for one origin, matched against the file's path (the old path
// for deleted files). Keys are any category names you like, checked in the order
// they are written; the first category with a matching glob wins. A file that
// matches nothing is OTHER. OTHER may also be listed, to claim files before a
// later, broader category does.
type CategoryGlobs = Record<Category, string[]>;
// Keyed by origin. An origin's entry replaces "*" entirely; the two are not merged.
// Saved in ~/.pridm/categories.json, which is meant to be edited by hand.
type CategoryConfig = { '*': CategoryGlobs } & Record<RepoKey, CategoryGlobs>;
const DEFAULT_CATEGORIES: CategoryConfig = {
'*': {
spec: ['**/spec/**', '**/specs/**', 'docs/**', 'rfcs/**', '**/*.md', '**/*.mdx'],
test: ['**/test/**', '**/tests/**', '**/__tests__/**', '**/*.test.*', '**/*.spec.{ts,tsx,js,jsx}', '**/*_test.go', '**/test_*.py'],
prod: ['**/*.{ts,tsx,js,jsx,go,py,java,kt,rs,rb,swift,c,cpp,h}'],
},
};
// ─── Saved state (~/.pridm/state.json), written by pridm ──
interface PridmState {
focus: Record<DeltaId, Focus>;
scanRoots: string[]; // e.g. ['~/projects']
}
export {
DEFAULT_CATEGORIES,
OTHER,
type BulkDelta, type DeltaId, type RepoKey, type LocalCheckout, type PullRequest,
type SurfaceRef, type Category, type Focus, type CategoryStat, type WordCounts, type DeltaSummary, type DeltaList,
type DeltaOverview, type CategoryDiff, type FileStatus, type FileStat, type FileChange,
type CodeDiff, type MarkdownDiff, type MarkdownPiece, type CategoryGlobs, type CategoryConfig, type PridmState,
};