@peasant-labs/fairtrade 0.0.3 → 0.0.5

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 (40) hide show
  1. package/dist/lib/ChartLine-Dlp6-CLL.js +264 -0
  2. package/dist/lib/InUseShell-DZvmRdj-.js +1532 -0
  3. package/dist/lib/analytics.css +1 -0
  4. package/dist/lib/analytics.js +1052 -0
  5. package/dist/lib/commons.css +1 -0
  6. package/dist/lib/commons.js +3275 -0
  7. package/dist/lib/components.css +1 -1
  8. package/dist/lib/graph.css +1 -0
  9. package/dist/lib/graph.js +823 -0
  10. package/dist/lib/tokens.css +1 -1
  11. package/dist/lib/tokens.json +1 -1
  12. package/dist/lib/types/Intensity.d.ts +3 -3
  13. package/dist/lib/types/MapCanvas.d.ts +37 -5
  14. package/dist/lib/types/RoleRoster.d.ts +12 -1
  15. package/dist/lib/types/analytics/ChartCard.d.ts +18 -0
  16. package/dist/lib/types/analytics/ContributorTable.d.ts +16 -0
  17. package/dist/lib/types/analytics/ProjectOverview.d.ts +40 -0
  18. package/dist/lib/types/analytics/format.d.ts +48 -0
  19. package/dist/lib/types/analytics/index.d.ts +24 -0
  20. package/dist/lib/types/analytics/metrics.d.ts +130 -0
  21. package/dist/lib/types/analytics/stats.d.ts +23 -0
  22. package/dist/lib/types/analytics/time.d.ts +32 -0
  23. package/dist/lib/types/analytics/types.d.ts +453 -0
  24. package/dist/lib/types/commons/Explore.d.ts +6 -0
  25. package/dist/lib/types/commons/Manage.d.ts +34 -0
  26. package/dist/lib/types/commons/index.d.ts +24 -0
  27. package/dist/lib/types/commons/providers.d.ts +8 -0
  28. package/dist/lib/types/commons/types.d.ts +356 -0
  29. package/dist/lib/types/graph/ChangeDetail.d.ts +28 -0
  30. package/dist/lib/types/graph/Changes.d.ts +21 -0
  31. package/dist/lib/types/graph/CodeMap.d.ts +49 -0
  32. package/dist/lib/types/graph/CodeMapComposition.d.ts +85 -0
  33. package/dist/lib/types/graph/changeGraph.d.ts +106 -0
  34. package/dist/lib/types/graph/index.d.ts +30 -0
  35. package/dist/lib/types/graph/types.d.ts +579 -0
  36. package/dist/lib/types/index.d.ts +1 -0
  37. package/dist/lib/types/inuse/InUseShell.d.ts +50 -0
  38. package/dist/lib/ui-oBFnHPFe.js +11146 -0
  39. package/dist/lib/ui.js +4 -12693
  40. package/package.json +37 -6
@@ -0,0 +1,356 @@
1
+ /**
2
+ * Transcript visibility level.
3
+ * @typedef {'public' | 'private' | 'shared'} TranscriptVisibility
4
+ */
5
+ /** Canonical TranscriptVisibility values. @type {readonly TranscriptVisibility[]} */
6
+ export const TRANSCRIPT_VISIBILITIES: readonly TranscriptVisibility[];
7
+ /**
8
+ * Collective acceptance mode: who can join.
9
+ * Grounded in backend migration 005 — CHECK (acceptance_mode IN
10
+ * ('open','verified_only','curated')).
11
+ * @typedef {'open' | 'verified_only' | 'curated'} AcceptanceMode
12
+ */
13
+ /** Canonical AcceptanceMode values. @type {readonly AcceptanceMode[]} */
14
+ export const ACCEPTANCE_MODES: readonly AcceptanceMode[];
15
+ /**
16
+ * Collective data access policy: who can read transcripts.
17
+ * Grounded in backend handler/groups.go canReadData + migration 008
18
+ * (data_access default 'members_only').
19
+ * @typedef {'members_only' | 'contributors' | 'public'} DataAccessPolicy
20
+ */
21
+ /** Canonical DataAccessPolicy values. @type {readonly DataAccessPolicy[]} */
22
+ export const DATA_ACCESS_POLICIES: readonly DataAccessPolicy[];
23
+ /**
24
+ * Transcript deletion policy for a collective.
25
+ * Grounded in backend migration 016 — CHECK (transcript_deletion_policy IN
26
+ * ('user_choice','mandatory')).
27
+ * @typedef {'user_choice' | 'mandatory'} TranscriptDeletionPolicy
28
+ */
29
+ /** Canonical TranscriptDeletionPolicy values. @type {readonly TranscriptDeletionPolicy[]} */
30
+ export const TRANSCRIPT_DELETION_POLICIES: readonly TranscriptDeletionPolicy[];
31
+ /**
32
+ * A member's role within a collective. The `members` list carries
33
+ * owner/member/contributor; the `pendingMembers` list carries `pending`
34
+ * (the backend's ListGroupPendingMembers query filters `gm.role = 'pending'`),
35
+ * so this union — shared by both lists via CollectiveMemberPayload — includes it.
36
+ * Grounded in backend handler/groups.go (Role: "owner"/"member"/"contributor")
37
+ * + sqlc ListGroupPendingMembers (WHERE gm.role = 'pending').
38
+ * @typedef {'owner' | 'member' | 'contributor' | 'pending'} CollectiveRole
39
+ */
40
+ /** Canonical CollectiveRole values. @type {readonly CollectiveRole[]} */
41
+ export const COLLECTIVE_ROLES: readonly CollectiveRole[];
42
+ /**
43
+ * Transcript visibility level.
44
+ */
45
+ export type TranscriptVisibility = "public" | "private" | "shared";
46
+ /**
47
+ * Collective acceptance mode: who can join.
48
+ * Grounded in backend migration 005 — CHECK (acceptance_mode IN
49
+ * ('open','verified_only','curated')).
50
+ */
51
+ export type AcceptanceMode = "open" | "verified_only" | "curated";
52
+ /**
53
+ * Collective data access policy: who can read transcripts.
54
+ * Grounded in backend handler/groups.go canReadData + migration 008
55
+ * (data_access default 'members_only').
56
+ */
57
+ export type DataAccessPolicy = "members_only" | "contributors" | "public";
58
+ /**
59
+ * Transcript deletion policy for a collective.
60
+ * Grounded in backend migration 016 — CHECK (transcript_deletion_policy IN
61
+ * ('user_choice','mandatory')).
62
+ */
63
+ export type TranscriptDeletionPolicy = "user_choice" | "mandatory";
64
+ /**
65
+ * A member's role within a collective. The `members` list carries
66
+ * owner/member/contributor; the `pendingMembers` list carries `pending`
67
+ * (the backend's ListGroupPendingMembers query filters `gm.role = 'pending'`),
68
+ * so this union — shared by both lists via CollectiveMemberPayload — includes it.
69
+ * Grounded in backend handler/groups.go (Role: "owner"/"member"/"contributor")
70
+ * + sqlc ListGroupPendingMembers (WHERE gm.role = 'pending').
71
+ */
72
+ export type CollectiveRole = "owner" | "member" | "contributor" | "pending";
73
+ /**
74
+ * Current Explore browse filters mirrored by the host.
75
+ */
76
+ export type ExploreFilters = {
77
+ query: string;
78
+ provider: string;
79
+ topics: string[];
80
+ order: string;
81
+ page: number;
82
+ };
83
+ /**
84
+ * Surface props for the lifted Explore component.
85
+ * The component consumes one cooked payload and owns its own browse state; hosts may also supply
86
+ * navigation slots for transcript/profile/collective exits.
87
+ */
88
+ export type ExploreSurfaceProps = {
89
+ data: ExplorePayload;
90
+ className?: string;
91
+ onFiltersChange?: (filters: ExploreFilters) => void;
92
+ onOpenTranscript?: (transcript: ExploreTranscriptPayload) => void;
93
+ onOpenProfile?: (owner: ExploreOwnerPayload) => void;
94
+ onOpenCollective?: (collective: CollectiveResultPayload) => void;
95
+ transcriptHref?: (transcript: ExploreTranscriptPayload) => string;
96
+ profileHref?: (owner: ExploreOwnerPayload) => string;
97
+ collectiveHref?: (collective: CollectiveResultPayload) => string;
98
+ };
99
+ /**
100
+ * The AUTHENTICATED VIEWER's role in a collective — a CollectiveRole, OR the
101
+ * empty string when the viewer is not a member / anonymous. The backend GetGroup
102
+ * handler defaults `your_role` to "" for non-members (handler/groups.go:
103
+ * `yourRole := ""`), so this distinct type is required wherever the viewer's own
104
+ * role is exposed (your_role + the per-viewer Group.role), as opposed to a
105
+ * concrete member row's role.
106
+ */
107
+ export type ViewerRole = CollectiveRole | "";
108
+ /**
109
+ * One tag attached to a transcript in the Explore list.
110
+ */
111
+ export type TagPayload = {
112
+ id: string;
113
+ name: string;
114
+ };
115
+ /**
116
+ * The author (owner) of a transcript as shown in the Explore list.
117
+ */
118
+ export type ExploreOwnerPayload = {
119
+ githubUsername: string;
120
+ displayName: string | null;
121
+ avatarUrl: string | null;
122
+ };
123
+ /**
124
+ * One transcript row in the Explore browse list.
125
+ * Cooked from TranscriptListItem (frontend/src/lib/types.ts): snake_case fields
126
+ * are renamed to camelCase; fields not needed by the Explore surface are omitted.
127
+ */
128
+ export type ExploreTranscriptPayload = {
129
+ id: string;
130
+ title: string | null;
131
+ visibility: TranscriptVisibility;
132
+ /**
133
+ * e.g. "claude-code", "opencode"
134
+ */
135
+ modelProvider: string;
136
+ modelName: string | null;
137
+ harnessVersion: string | null;
138
+ /**
139
+ * ISO-8601 datetime or null
140
+ */
141
+ sessionStart: string | null;
142
+ /**
143
+ * ISO-8601 datetime or null
144
+ */
145
+ sessionEnd: string | null;
146
+ turnCount: number | null;
147
+ tokenCount: number | null;
148
+ toolCallCount: number | null;
149
+ durationMs: number | null;
150
+ gitBranch: string | null;
151
+ projectName: string | null;
152
+ tags: TagPayload[];
153
+ owner: ExploreOwnerPayload;
154
+ };
155
+ /**
156
+ * Paginated list of transcripts for the Explore browse view.
157
+ * Cooked from TranscriptListResponse.
158
+ */
159
+ export type ExploreTranscriptListPayload = {
160
+ transcripts: ExploreTranscriptPayload[];
161
+ /**
162
+ * total matching transcripts (for pagination)
163
+ */
164
+ total: number;
165
+ /**
166
+ * current page (1-based)
167
+ */
168
+ page: number;
169
+ /**
170
+ * page size
171
+ */
172
+ limit: number;
173
+ };
174
+ /**
175
+ * One collective result from a collective search (useSearchCollectives).
176
+ * Cooked from CollectiveSearchResult (frontend/src/lib/types.ts).
177
+ */
178
+ export type CollectiveResultPayload = {
179
+ id: string;
180
+ name: string;
181
+ description: string | null;
182
+ linkedGithubOrg: string | null;
183
+ memberCount: number;
184
+ transcriptCount: number;
185
+ };
186
+ /**
187
+ * One popular tag with its usage count.
188
+ * Cooked from TagWithCount (frontend/src/lib/types.ts).
189
+ */
190
+ export type PopularTagPayload = {
191
+ id: string;
192
+ name: string;
193
+ usageCount: number;
194
+ };
195
+ /**
196
+ * The Explore surface prop payload. The adapter maps the three hook results
197
+ * (useTranscripts, useSearchCollectives, usePopularTags) into this single
198
+ * cooked shape; the lifted <Explore> component never calls hooks directly.
199
+ *
200
+ * Query parameters (q, sort, page, provider, tags) are not embedded in the
201
+ * payload — they live as component-level props that the host passes alongside
202
+ * the payload (the adapter is called when any of them changes).
203
+ */
204
+ export type ExplorePayload = {
205
+ /**
206
+ * browsing results (page + facet filters applied)
207
+ */
208
+ transcripts: ExploreTranscriptListPayload;
209
+ /**
210
+ * collective search results (empty when no query)
211
+ */
212
+ collectives: CollectiveResultPayload[];
213
+ /**
214
+ * top tags for the facet rail (cap set by caller)
215
+ */
216
+ popularTags: PopularTagPayload[];
217
+ };
218
+ /**
219
+ * One member of a collective.
220
+ * Cooked from GroupMember (frontend/src/lib/types.ts).
221
+ */
222
+ export type CollectiveMemberPayload = {
223
+ id: string;
224
+ githubUsername: string;
225
+ displayName: string | null;
226
+ avatarUrl: string | null;
227
+ /**
228
+ * owner/member/contributor for the members list; "pending" for the pendingMembers list
229
+ */
230
+ role: CollectiveRole;
231
+ /**
232
+ * ISO-8601 datetime
233
+ */
234
+ joinedAt: string;
235
+ };
236
+ /**
237
+ * One transcript published to the collective (lightweight row).
238
+ * Cooked from GroupTranscript (which extends Transcript with owner fields).
239
+ */
240
+ export type CollectiveTranscriptPayload = {
241
+ id: string;
242
+ title: string | null;
243
+ visibility: TranscriptVisibility;
244
+ modelProvider: string;
245
+ modelName: string | null;
246
+ /**
247
+ * ISO-8601 datetime or null
248
+ */
249
+ sessionStart: string | null;
250
+ turnCount: number | null;
251
+ tokenCount: number | null;
252
+ ownerUsername: string;
253
+ ownerAvatarUrl: string | null;
254
+ };
255
+ /**
256
+ * Aggregate statistics for a collective's transcript corpus.
257
+ * Mirrors GroupTranscriptStats from frontend/src/lib/types.ts.
258
+ */
259
+ export type CollectiveStatsPayload = {
260
+ totalTranscripts: number;
261
+ contributorCount: number;
262
+ totalTurns: number;
263
+ totalDurationMs: number;
264
+ totalTokens: number;
265
+ };
266
+ /**
267
+ * Model usage breakdown for a collective.
268
+ * Mirrors GroupModelBreakdown from frontend/src/lib/types.ts.
269
+ */
270
+ export type CollectiveModelBreakdownPayload = {
271
+ modelProvider: string;
272
+ transcriptCount: number;
273
+ };
274
+ /**
275
+ * One contributor to a collective's transcript corpus.
276
+ * Mirrors GroupContributor from frontend/src/lib/types.ts.
277
+ */
278
+ export type CollectiveContributorPayload = {
279
+ id: string;
280
+ githubUsername: string;
281
+ avatarUrl: string | null;
282
+ transcriptCount: number;
283
+ };
284
+ /**
285
+ * The collective's own metadata.
286
+ * Cooked from Group (frontend/src/lib/types.ts): snake_case → camelCase.
287
+ */
288
+ export type CollectivePayload = {
289
+ id: string;
290
+ name: string;
291
+ description: string | null;
292
+ linkedGithubOrg: string | null;
293
+ displayMembers: boolean;
294
+ transcriptDeletionPolicy: TranscriptDeletionPolicy;
295
+ /**
296
+ * user id of the creator
297
+ */
298
+ createdBy: string;
299
+ /**
300
+ * ISO-8601 datetime
301
+ */
302
+ createdAt: string;
303
+ /**
304
+ * ISO-8601 datetime
305
+ */
306
+ updatedAt: string;
307
+ acceptanceMode: AcceptanceMode;
308
+ dataAccess: DataAccessPolicy;
309
+ /**
310
+ * the authenticated viewer's role; "" when not a member / anonymous
311
+ */
312
+ role: ViewerRole;
313
+ /**
314
+ * ISO-8601 datetime when the user joined; null if not a member
315
+ */
316
+ memberSince: string | null;
317
+ };
318
+ /**
319
+ * The Manage surface prop payload. The adapter maps the useGroup hook result
320
+ * into this single cooked shape; the lifted <Manage> component never calls
321
+ * hooks directly.
322
+ *
323
+ * Mutation callbacks (onCreateGroup, onUpdateGroup, onJoinGroup,
324
+ * onPromoteMember, onRemoveMember, onAddMember, onDeleteGroup) are
325
+ * component-level props defined in the surface slice — NOT fields in this
326
+ * payload. The payload carries only the READ data model.
327
+ *
328
+ * FIXTURE GAP: pendingMembers is optional on the wire (`pending_members?`)
329
+ * and absent from the current mock fixture. The adapter normalizes it to `[]`
330
+ * when absent; the mock fixture must be filled by the surface slice worker.
331
+ */
332
+ export type ManagePayload = {
333
+ collective: CollectivePayload;
334
+ /**
335
+ * approved members
336
+ */
337
+ members: CollectiveMemberPayload[];
338
+ /**
339
+ * pending join requests (may be [] when not yet seeded)
340
+ */
341
+ pendingMembers: CollectiveMemberPayload[];
342
+ /**
343
+ * published transcripts (paginated externally)
344
+ */
345
+ transcripts: CollectiveTranscriptPayload[];
346
+ stats: CollectiveStatsPayload;
347
+ /**
348
+ * usage breakdown by model provider
349
+ */
350
+ models: CollectiveModelBreakdownPayload[];
351
+ contributors: CollectiveContributorPayload[];
352
+ /**
353
+ * authenticated viewer's role; "" when not a member / anonymous
354
+ */
355
+ yourRole: ViewerRole;
356
+ };
@@ -0,0 +1,28 @@
1
+ /**
2
+ * @param {object} props
3
+ * @param {import('./types.js').ChangeDetailPayload} props.payload the cooked change-detail payload
4
+ * @param {(file: import('./types.js').FileChangePayload) => import('./types.js').ChangeDiffPayload | null | undefined} [props.getDiff]
5
+ * resolve the lazy per-file diff (the separate ChangeDiffPayload) for an opened file; return
6
+ * null/undefined while loading, or a ChangeDiffPayload whose host-side `error` sentinel is set
7
+ * (with empty hunks) when the fetch failed — the surface then renders an error row, not a spinner
8
+ * @param {string} [props.title] editorial title; default derived from the branch name
9
+ * @param {string} [props.annotation] the saved user label (host-owned)
10
+ * @param {(value: string) => void} [props.onSaveAnnotation]
11
+ * @param {() => void} [props.onRemoveAnnotation]
12
+ * @param {() => void} [props.onOpenMap] the "see this work on the code map" exit (host owns the route)
13
+ * @param {() => void} [props.onShare] the "share … conversations" exit (host owns share UX)
14
+ * @param {() => void} [props.onCopyRecap] the "copy recap" exit (host owns the clipboard recap)
15
+ * @param {Record<string, boolean>} [props.initialOpenFiles] files open on first render (path → open?)
16
+ */
17
+ export default function ChangeDetail({ payload, getDiff, title, annotation, onSaveAnnotation, onRemoveAnnotation, onOpenMap, onShare, onCopyRecap, initialOpenFiles, }: {
18
+ payload: import("./types.js").ChangeDetailPayload;
19
+ getDiff?: (file: import("./types.js").FileChangePayload) => import("./types.js").ChangeDiffPayload | null | undefined;
20
+ title?: string;
21
+ annotation?: string;
22
+ onSaveAnnotation?: (value: string) => void;
23
+ onRemoveAnnotation?: () => void;
24
+ onOpenMap?: () => void;
25
+ onShare?: () => void;
26
+ onCopyRecap?: () => void;
27
+ initialOpenFiles?: Record<string, boolean>;
28
+ }): any;
@@ -0,0 +1,21 @@
1
+ /**
2
+ * @param {object} props
3
+ * @param {import('./types.js').ChangesPayload} props.payload the cooked changes payload (adapter output)
4
+ * @param {string} [props.projectLabel] the head label (e.g. "peasant-labs/peasant"); host-supplied (not a payload field)
5
+ * @param {string} [props.selectedId] id of the active commit/tip row (the scarce amber treatment)
6
+ * @param {(commit: import('./changeGraph.js').CommitGraphRow) => void} [props.onSelectChange] a row was chosen (open its change detail)
7
+ * @param {() => void} [props.onOpenMap] the "open the map" affordance was pressed
8
+ * @param {boolean} [props.hasMore] more history exists below the window (→ "show older")
9
+ * @param {() => void} [props.onShowOlder] "show older" was pressed
10
+ * @param {number} [props.nowMs] pins relative-time humanisation (default Date.now()); the harness fixes it for byte-stable captures
11
+ */
12
+ export default function Changes({ payload, projectLabel, selectedId, onSelectChange, onOpenMap, hasMore, onShowOlder, nowMs, }: {
13
+ payload: import("./types.js").ChangesPayload;
14
+ projectLabel?: string;
15
+ selectedId?: string;
16
+ onSelectChange?: (commit: import("./changeGraph.js").CommitGraphRow) => void;
17
+ onOpenMap?: () => void;
18
+ hasMore?: boolean;
19
+ onShowOlder?: () => void;
20
+ nowMs?: number;
21
+ }): any;
@@ -0,0 +1,49 @@
1
+ /**
2
+ * CodeMap — the lifted code-topology surface over the shared MapCanvas.
3
+ *
4
+ * The payload remains the cooked topology contract from @peasant-labs/fairtrade/graph:
5
+ * geometry stays derived here, activity edges stay in the host rail, and the host
6
+ * feeds interaction state through props so demo and app render the same behavior.
7
+ *
8
+ * @param {object} props
9
+ * @param {import('./types.js').CodeMapPayload} props.payload
10
+ * @param {{level:'project'|'package'|'file', expanded?: Iterable<string>}} [props.zoom]
11
+ * @param {(zoom:{level:'project'|'package'|'file', expanded:string[]})=>void} [props.onZoomChange]
12
+ * @param {string|null} [props.selectedId]
13
+ * @param {(id:string|null, node:import('./types.js').MapNodePayload|null)=>void} [props.onSelect]
14
+ * @param {(id:string)=>void} [props.onExpand]
15
+ * @param {Iterable<string>} [props.highlightedIds]
16
+ * @param {Record<string,'new'|'removed'>} [props.nodeDeltas]
17
+ * @param {Record<string,'new'|'removed'>} [props.structureEdgeDeltas]
18
+ * @param {number|string} [props.height]
19
+ * @param {string} [props.ariaLabel]
20
+ * @param {string} [props.className]
21
+ */
22
+ export default function CodeMap({ payload, zoom, onZoomChange, selectedId, onSelect, onExpand, highlightedIds, nodeDeltas, structureEdgeDeltas, height, ariaLabel, className, }: {
23
+ payload: import("./types.js").CodeMapPayload;
24
+ zoom?: {
25
+ level: "project" | "package" | "file";
26
+ expanded?: Iterable<string>;
27
+ };
28
+ onZoomChange?: (zoom: {
29
+ level: "project" | "package" | "file";
30
+ expanded: string[];
31
+ }) => void;
32
+ selectedId?: string | null;
33
+ onSelect?: (id: string | null, node: import("./types.js").MapNodePayload | null) => void;
34
+ onExpand?: (id: string) => void;
35
+ highlightedIds?: Iterable<string>;
36
+ nodeDeltas?: Record<string, "new" | "removed">;
37
+ structureEdgeDeltas?: Record<string, "new" | "removed">;
38
+ height?: number | string;
39
+ ariaLabel?: string;
40
+ className?: string;
41
+ }): any;
42
+ /**
43
+ * @param {import('./types.js').CodeMapPayload | undefined} payload
44
+ * @returns {{nodes: Array<object>, edges: Array<object>}}
45
+ */
46
+ export function codeMapPayloadToMapData(payload: import("./types.js").CodeMapPayload | undefined): {
47
+ nodes: Array<object>;
48
+ edges: Array<object>;
49
+ };
@@ -0,0 +1,85 @@
1
+ /**
2
+ * CodeMapComposition — the FULL map surface (full-lift): the
3
+ * RailShell frame (sticky toolbar + canvas + rail), the persistent visual-
4
+ * channel legend, and the shared <CodeMap> canvas, composed once here so the
5
+ * demo GraphMap mockup and every consuming app (peasant, village) render the
6
+ * SAME toolbar/rail-shell/legend/interaction composition — not just the same
7
+ * canvas wrapped in each host's own hand-rolled shell.
8
+ *
9
+ * Before this component, only the canvas itself (<CodeMap>) was shared; the
10
+ * surrounding toolbar, rail shell, and legend were reimplemented per host
11
+ * (review finding: "CodeMap boundary only lifts the canvas wrapper").
12
+ * Composition-level pieces that are inherently
13
+ * host-specific — the RAIL's content (real API data vs. demo mock data) and
14
+ * the canvas region's loading/empty/error states (peasant's WS/REST fetch
15
+ * lifecycle vs. the demo's static fixture) — stay host-owned via the `rail`
16
+ * and `canvasSlot` slots below; everything else (frame, legend, interaction
17
+ * wiring) is now ONE implementation.
18
+ *
19
+ * @param {object} props
20
+ * @param {import('./types.js').CodeMapPayload} [props.payload] forwarded to <CodeMap> when `canvasSlot` is omitted
21
+ * @param {{level:'project'|'package'|'file', expanded?: Iterable<string>}} [props.zoom]
22
+ * @param {(zoom:{level:'project'|'package'|'file', expanded:string[]})=>void} [props.onZoomChange]
23
+ * @param {string|null} [props.selectedId]
24
+ * @param {(id:string|null, node:import('./types.js').MapNodePayload|null)=>void} [props.onSelect]
25
+ * @param {(id:string)=>void} [props.onExpand]
26
+ * @param {Iterable<string>} [props.highlightedIds]
27
+ * @param {Record<string,'new'|'removed'>} [props.nodeDeltas]
28
+ * @param {Record<string,'new'|'removed'>} [props.structureEdgeDeltas]
29
+ * @param {number|string} [props.height=480] canvas height, forwarded to <CodeMap>
30
+ * @param {string} [props.ariaLabel='code map'] forwarded to <CodeMap>
31
+ * @param {React.ReactNode} [props.canvasSlot] override the canvas region entirely
32
+ * (e.g. a host's loading/disconnected/error states); when omitted, renders
33
+ * <CodeMap> from the props above — the demo mockup and any host without
34
+ * custom fetch-lifecycle states can rely on the default.
35
+ * @param {React.ReactNode} props.rail the rail's content (host-specific:
36
+ * real API data vs. demo mock data) — compose with the kit's <RailSection>.
37
+ * @param {React.ReactNode} [props.toolbar] optional extra sticky toolbar content
38
+ * ABOVE the canvas (e.g. a connection indicator) — the canvas's OWN shared
39
+ * grain/search toolbar (owned by <CodeMap>/<MapCanvas>) is unaffected either way.
40
+ * @param {string} [props.sheetTitle='code area'] RailShell's mobile bottom-sheet title
41
+ * @param {React.ReactNode} [props.sheetMeta]
42
+ * @param {'left'|'right'} [props.railSide='right']
43
+ * @param {React.ReactNode|false} [props.legend] override the default legend; `false` hides it
44
+ * @param {string} [props.canvasWrapperClassName] extra class on the canvas region wrapper
45
+ * @param {React.CSSProperties} [props.canvasWrapperStyle] inline style on the canvas region wrapper
46
+ * (e.g. a host's own responsive height clamp)
47
+ * @param {string} [props.className] extra class on the root
48
+ */
49
+ export default function CodeMapComposition({ payload, zoom, onZoomChange, selectedId, onSelect, onExpand, highlightedIds, nodeDeltas, structureEdgeDeltas, height, ariaLabel, canvasSlot, rail, toolbar, sheetTitle, sheetMeta, railSide, legend, canvasWrapperClassName, canvasWrapperStyle, className, }: {
50
+ payload?: import("./types.js").CodeMapPayload;
51
+ zoom?: {
52
+ level: "project" | "package" | "file";
53
+ expanded?: Iterable<string>;
54
+ };
55
+ onZoomChange?: (zoom: {
56
+ level: "project" | "package" | "file";
57
+ expanded: string[];
58
+ }) => void;
59
+ selectedId?: string | null;
60
+ onSelect?: (id: string | null, node: import("./types.js").MapNodePayload | null) => void;
61
+ onExpand?: (id: string) => void;
62
+ highlightedIds?: Iterable<string>;
63
+ nodeDeltas?: Record<string, "new" | "removed">;
64
+ structureEdgeDeltas?: Record<string, "new" | "removed">;
65
+ height?: number | string;
66
+ ariaLabel?: string;
67
+ canvasSlot?: React.ReactNode;
68
+ rail: React.ReactNode;
69
+ toolbar?: React.ReactNode;
70
+ sheetTitle?: string;
71
+ sheetMeta?: React.ReactNode;
72
+ railSide?: "left" | "right";
73
+ legend?: React.ReactNode | false;
74
+ canvasWrapperClassName?: string;
75
+ canvasWrapperStyle?: React.CSSProperties;
76
+ className?: string;
77
+ }): any;
78
+ /**
79
+ * The persistent legend explaining the canvas's four orthogonal visual channels
80
+ * (peasant spec §4/§5: WIDTH ∝ loc, monochrome FILL ∝ coverage, folder/file ICON,
81
+ * amber SELECTION, clay VIOLATION badge) — so the picture never needs decoding.
82
+ * Lifted here from the peasant app (was app-only chrome, spec-legend drift risk)
83
+ * so demo and every consuming app show the SAME legend for the SAME canvas.
84
+ */
85
+ export function DefaultMapLegend(): any;
@@ -0,0 +1,106 @@
1
+ /**
2
+ * Humanise an absolute epoch-ms time into a short relative label ("5h ago",
3
+ * "3d ago", "1wk ago"). Pure: depends only on (timeMs, nowMs). Returns '' when
4
+ * the time is missing so the kit simply omits the label.
5
+ *
6
+ * @param {number | null | undefined} timeMs
7
+ * @param {number} nowMs
8
+ * @returns {string}
9
+ */
10
+ export function humanizeAge(timeMs: number | null | undefined, nowMs: number): string;
11
+ /**
12
+ * Derive the CommitGraph dataset (+ reverted list + counts) from a ChangesPayload.
13
+ *
14
+ * Lane assignment is deterministic: open changes sort by tip time (newest first,
15
+ * branch name as a tiebreak) and take lanes 1..N in that order. Each open change
16
+ * contributes a tip row inserted just above the first recent commit at/older than
17
+ * its tip time; its `parents` point at its merge-base (baseHash) when that commit
18
+ * is in the window. Merged changes flip `merged` on their merge commit and add the
19
+ * (synthetic) branch tip as a second parent so the kit draws the join elbow.
20
+ *
21
+ * @param {ChangesPayload} payload
22
+ * @param {{ nowMs: number }} opts `nowMs` pins relative-time humanisation (determinism)
23
+ * @returns {ChangesGraph}
24
+ */
25
+ export function buildChangesGraph(payload: ChangesPayload, { nowMs }: {
26
+ nowMs: number;
27
+ }): ChangesGraph;
28
+ export type ChangesPayload = import("./types.js").ChangesPayload;
29
+ export type ChangeSummaryPayload = import("./types.js").ChangeSummaryPayload;
30
+ export type CommitRefPayload = import("./types.js").CommitRefPayload;
31
+ /**
32
+ * One row in the kit CommitGraph dataset (mirrors the `Commit` shape documented
33
+ * on src/ui/CommitGraph.jsx). Time order = array order (newest first); the graph
34
+ * is implicit in `lane` + `parents`.
35
+ */
36
+ export type CommitGraphRow = {
37
+ /**
38
+ * stable key (commit hash, or `tip:<branch>` for an open tip)
39
+ */
40
+ id: string;
41
+ /**
42
+ * 0 = the default-branch line; >0 = a branch lane
43
+ */
44
+ lane: number;
45
+ /**
46
+ * parent row ids (>1 ⇒ a merge)
47
+ */
48
+ parents?: string[];
49
+ /**
50
+ * the commit subject / branch label (USER CONTENT — case preserved)
51
+ */
52
+ message: string;
53
+ /**
54
+ * branch name chip (USER CONTENT — case preserved)
55
+ */
56
+ branch?: string;
57
+ /**
58
+ * a recorded session sits behind this commit (→ filled dot + sparkle)
59
+ */
60
+ session?: boolean;
61
+ /**
62
+ * this commit merged a branch back in (→ merged chip)
63
+ */
64
+ merged?: boolean;
65
+ /**
66
+ * this row is an open branch tip (→ tip affordance)
67
+ */
68
+ tip?: boolean;
69
+ /**
70
+ * humanised relative time (e.g. "5h ago")
71
+ */
72
+ time?: string;
73
+ };
74
+ /**
75
+ * A reverted line of work, surfaced under the graph (the demo's "reverted" chip).
76
+ */
77
+ export type RevertedChange = {
78
+ branch: string;
79
+ mergedAtMs?: number | null;
80
+ /**
81
+ * humanised relative time of the merge
82
+ */
83
+ when?: string;
84
+ };
85
+ /**
86
+ * The derived Changes view model: the CommitGraph dataset + the reverted list +
87
+ * the head counts the surface caption shows.
88
+ */
89
+ export type ChangesGraph = {
90
+ /**
91
+ * newest first; lane 0 is the default branch
92
+ */
93
+ commits: CommitGraphRow[];
94
+ /**
95
+ * merged-then-reverted changes (listed under the graph)
96
+ */
97
+ reverted: RevertedChange[];
98
+ /**
99
+ * number of open changes
100
+ */
101
+ openCount: number;
102
+ /**
103
+ * number of merged changes
104
+ */
105
+ mergedCount: number;
106
+ };
@@ -0,0 +1,30 @@
1
+ export { default as Changes } from "./Changes.jsx";
2
+ export { default as ChangeDetail } from "./ChangeDetail.jsx";
3
+ export type MapNodeKind = import("./types.js").MapNodeKind;
4
+ export type ChangeBinding = import("./types.js").ChangeBinding;
5
+ export type EdgeViolationKind = import("./types.js").EdgeViolationKind;
6
+ export type FileChangeStatus = import("./types.js").FileChangeStatus;
7
+ export type DiffLineKind = import("./types.js").DiffLineKind;
8
+ export type CommitRefPayload = import("./types.js").CommitRefPayload;
9
+ export type MapEdgePayload = import("./types.js").MapEdgePayload;
10
+ export type ActivityEdgePayload = import("./types.js").ActivityEdgePayload;
11
+ export type EdgeViolationPayload = import("./types.js").EdgeViolationPayload;
12
+ export type MapNodePayload = import("./types.js").MapNodePayload;
13
+ export type MapSlicePayload = import("./types.js").MapSlicePayload;
14
+ export type ChangeSummaryPayload = import("./types.js").ChangeSummaryPayload;
15
+ export type ChangesPayload = import("./types.js").ChangesPayload;
16
+ export type TaskSummaryPayload = import("./types.js").TaskSummaryPayload;
17
+ export type ChangeSessionPayload = import("./types.js").ChangeSessionPayload;
18
+ export type UnusualSignalPayload = import("./types.js").UnusualSignalPayload;
19
+ export type FrictionClusterPayload = import("./types.js").FrictionClusterPayload;
20
+ export type FileChangePayload = import("./types.js").FileChangePayload;
21
+ export type ChangeDetailPayload = import("./types.js").ChangeDetailPayload;
22
+ export type DiffLinePayload = import("./types.js").DiffLinePayload;
23
+ export type DiffHunkPayload = import("./types.js").DiffHunkPayload;
24
+ export type ChangeDiffPayload = import("./types.js").ChangeDiffPayload;
25
+ export type CodeMapPayload = import("./types.js").CodeMapPayload;
26
+ export { default as CodeMap, codeMapPayloadToMapData } from "./CodeMap.jsx";
27
+ export { default as CodeMapComposition, DefaultMapLegend } from "./CodeMapComposition.jsx";
28
+ export { GraphAppShell, GraphSectionNav, GRAPH_APP_SECTIONS } from "../inuse/InUseShell.jsx";
29
+ export { buildChangesGraph, humanizeAge } from "./changeGraph.js";
30
+ export { MAP_NODE_KINDS, CHANGE_BINDINGS, EDGE_VIOLATION_KINDS, FILE_CHANGE_STATUSES, DIFF_LINE_KINDS } from "./types.js";