@peasant-labs/fairtrade 0.0.2 → 0.0.4

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 (67) 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/base.css +7 -1
  6. package/dist/lib/commons.css +1 -0
  7. package/dist/lib/commons.js +3275 -0
  8. package/dist/lib/components.css +1 -1
  9. package/dist/lib/graph.css +1 -0
  10. package/dist/lib/graph.js +823 -0
  11. package/dist/lib/types/Intensity.d.ts +3 -3
  12. package/dist/lib/types/MapCanvas.d.ts +37 -5
  13. package/dist/lib/types/RoleRoster.d.ts +12 -1
  14. package/dist/lib/types/analytics/ChartCard.d.ts +18 -0
  15. package/dist/lib/types/analytics/ContributorTable.d.ts +16 -0
  16. package/dist/lib/types/analytics/ProjectOverview.d.ts +40 -0
  17. package/dist/lib/types/analytics/format.d.ts +48 -0
  18. package/dist/lib/types/analytics/index.d.ts +24 -0
  19. package/dist/lib/types/analytics/metrics.d.ts +130 -0
  20. package/dist/lib/types/analytics/stats.d.ts +23 -0
  21. package/dist/lib/types/analytics/time.d.ts +32 -0
  22. package/dist/lib/types/analytics/types.d.ts +453 -0
  23. package/dist/lib/types/commons/Explore.d.ts +6 -0
  24. package/dist/lib/types/commons/Manage.d.ts +34 -0
  25. package/dist/lib/types/commons/index.d.ts +24 -0
  26. package/dist/lib/types/commons/providers.d.ts +8 -0
  27. package/dist/lib/types/commons/types.d.ts +356 -0
  28. package/dist/lib/types/graph/ChangeDetail.d.ts +28 -0
  29. package/dist/lib/types/graph/Changes.d.ts +21 -0
  30. package/dist/lib/types/graph/CodeMap.d.ts +49 -0
  31. package/dist/lib/types/graph/CodeMapComposition.d.ts +85 -0
  32. package/dist/lib/types/graph/changeGraph.d.ts +106 -0
  33. package/dist/lib/types/graph/index.d.ts +30 -0
  34. package/dist/lib/types/graph/types.d.ts +579 -0
  35. package/dist/lib/types/index.d.ts +3 -0
  36. package/dist/lib/types/inuse/InUseShell.d.ts +50 -0
  37. package/dist/lib/types/transcript/CheckRow.d.ts +15 -0
  38. package/dist/lib/types/transcript/DiffEntryCard.d.ts +27 -0
  39. package/dist/lib/types/transcript/FilterSection.d.ts +11 -0
  40. package/dist/lib/types/transcript/FiltersRail.d.ts +41 -0
  41. package/dist/lib/types/transcript/LabelPopover.d.ts +14 -0
  42. package/dist/lib/types/transcript/Markdown.d.ts +7 -0
  43. package/dist/lib/types/transcript/OutlineRail.d.ts +13 -0
  44. package/dist/lib/types/transcript/Scorecard.d.ts +8 -0
  45. package/dist/lib/types/transcript/Scrubber.d.ts +17 -0
  46. package/dist/lib/types/transcript/TaskBody.d.ts +8 -0
  47. package/dist/lib/types/transcript/Thinking.d.ts +9 -0
  48. package/dist/lib/types/transcript/ToolBody.d.ts +8 -0
  49. package/dist/lib/types/transcript/ToolCall.d.ts +12 -0
  50. package/dist/lib/types/transcript/TranscriptViewer.d.ts +6 -0
  51. package/dist/lib/types/transcript/TurnCard.d.ts +31 -0
  52. package/dist/lib/types/transcript/ViewSwitch.d.ts +11 -0
  53. package/dist/lib/types/transcript/adapter.d.ts +90 -0
  54. package/dist/lib/types/transcript/adapter.parse.d.ts +75 -0
  55. package/dist/lib/types/transcript/analytics.d.ts +216 -0
  56. package/dist/lib/types/transcript/graph/GraphLegend.d.ts +49 -0
  57. package/dist/lib/types/transcript/graph/GraphSubagentBranch.d.ts +24 -0
  58. package/dist/lib/types/transcript/graph/GraphToolNode.d.ts +56 -0
  59. package/dist/lib/types/transcript/graph/GraphTurnNode.d.ts +76 -0
  60. package/dist/lib/types/transcript/graph/index.d.ts +10 -0
  61. package/dist/lib/types/transcript/index.d.ts +69 -0
  62. package/dist/lib/types/transcript/state-capabilities.d.ts +161 -0
  63. package/dist/lib/types/transcript/view-model.d.ts +563 -0
  64. package/dist/lib/types/transcript/wire-types.d.ts +325 -0
  65. package/dist/lib/ui-oBFnHPFe.js +11146 -0
  66. package/dist/lib/ui.js +4 -8736
  67. package/package.json +42 -6
@@ -4,11 +4,11 @@ export function clampLevel(level: any): number;
4
4
  * coverage ratio (recorded / total) → ramp level. 0 / unknown = none; ≥ 0.9
5
5
  * reads as fully covered. mirrors peasant's traceabilityLevel quantiles.
6
6
  */
7
- export function coverageLevel(recorded: any, total: any): 0 | 4 | 1 | 2 | 3;
7
+ export function coverageLevel(recorded: any, total: any): 0 | 1 | 2 | 4 | 3;
8
8
  /** density (0..1) → ramp level for the bottom-edge effort bar. */
9
- export function effortLevel(density: any): 0 | 4 | 1 | 2 | 3;
9
+ export function effortLevel(density: any): 0 | 1 | 2 | 4 | 3;
10
10
  /** generic value-vs-max quantization (heatmap cells, sparklines). */
11
- export function quantize(value: any, max: any): 0 | 4 | 1 | 2 | 3;
11
+ export function quantize(value: any, max: any): 0 | 1 | 2 | 4 | 3;
12
12
  /** loc → node size class. small files are compact; large ones get real estate. */
13
13
  export function locSize(loc: any): "sm" | "md" | "lg" | "xs" | "xl";
14
14
  export function IntensitySwatch({ level, accent, size, label, className, ...rest }: {
@@ -7,6 +7,12 @@
7
7
  * @property {number} [coverage=0] 0..4 monochrome coverage ramp (the FILL)
8
8
  * @property {string} [parent] parent id (forms the tree)
9
9
  * @property {number} [violations=0] violation count — a clay badge
10
+ * @property {number} [layer] server-assigned row (0 = top row); when
11
+ * present, positions this node's ROW instead of tree depth (peasant/codegraph's
12
+ * deterministic layer/order contract). Falls back to tree depth when absent.
13
+ * @property {number} [order] server-assigned stable sort key within a
14
+ * layer; when present, orders siblings/row-mates instead of input-array position.
15
+ * Falls back to input order when absent.
10
16
  */
11
17
  /**
12
18
  * @typedef {Object} MapEdge
@@ -27,21 +33,35 @@
27
33
  * @param {Object} props
28
34
  * @param {{nodes: MapNode[], edges?: MapEdge[]}} [props.data] the graph
29
35
  * @param {'overview'|'folders'|'files'} [props.grain='folders'] initial semantic zoom
30
- * @param {string} [props.selectedId] initial selection
36
+ * @param {Iterable<string>} [props.expandedIds] expanded node ids
37
+ * @param {string|null} [props.selectedId] selected node id
38
+ * @param {Iterable<string>} [props.highlightedIds] host hover/relay ids
39
+ * @param {Record<string,'new'|'removed'>} [props.nodeDeltas] per-node review deltas
40
+ * @param {Record<string,'new'|'removed'>} [props.edgeDeltas] per-edge review deltas
31
41
  * @param {(id:string|null, node:MapNode|null)=>void} [props.onSelect] selection cb
32
- * @param {number} [props.height=520] canvas height (px)
42
+ * @param {(grain:'overview'|'folders'|'files')=>void} [props.onGrainChange]
43
+ * @param {(ids:string[])=>void} [props.onExpandedIdsChange]
44
+ * @param {(id:string)=>void} [props.onExpand]
45
+ * @param {number|string} [props.height=520] canvas height
33
46
  * @param {string} [props.ariaLabel='code map'] application label
34
47
  * @param {string} [props.className] extra container class
35
48
  */
36
- export default function MapCanvas({ data, grain: initialGrain, selectedId: initialSelected, onSelect, height, ariaLabel, className, }: {
49
+ export default function MapCanvas({ data, grain: grainProp, expandedIds, selectedId: selectedIdProp, highlightedIds, nodeDeltas, edgeDeltas, onSelect, onGrainChange, onExpandedIdsChange, onExpand, height, ariaLabel, className, }: {
37
50
  data?: {
38
51
  nodes: MapNode[];
39
52
  edges?: MapEdge[];
40
53
  };
41
54
  grain?: "overview" | "folders" | "files";
42
- selectedId?: string;
55
+ expandedIds?: Iterable<string>;
56
+ selectedId?: string | null;
57
+ highlightedIds?: Iterable<string>;
58
+ nodeDeltas?: Record<string, "new" | "removed">;
59
+ edgeDeltas?: Record<string, "new" | "removed">;
43
60
  onSelect?: (id: string | null, node: MapNode | null) => void;
44
- height?: number;
61
+ onGrainChange?: (grain: "overview" | "folders" | "files") => void;
62
+ onExpandedIdsChange?: (ids: string[]) => void;
63
+ onExpand?: (id: string) => void;
64
+ height?: number | string;
45
65
  ariaLabel?: string;
46
66
  className?: string;
47
67
  }): any;
@@ -74,6 +94,18 @@ export type MapNode = {
74
94
  * violation count — a clay badge
75
95
  */
76
96
  violations?: number;
97
+ /**
98
+ * server-assigned row (0 = top row); when
99
+ * present, positions this node's ROW instead of tree depth (peasant/codegraph's
100
+ * deterministic layer/order contract). Falls back to tree depth when absent.
101
+ */
102
+ layer?: number;
103
+ /**
104
+ * server-assigned stable sort key within a
105
+ * layer; when present, orders siblings/row-mates instead of input-array position.
106
+ * Falls back to input order when absent.
107
+ */
108
+ order?: number;
77
109
  };
78
110
  export type MapEdge = {
79
111
  from: string;
@@ -43,13 +43,24 @@ export function ConfirmInline({ label, confirmLabel, icon, onConfirm, busy, disa
43
43
  * @param {(member: RosterMember) => (void | Promise<void>)} [props.onRemove] fired when a row's remove is confirmed
44
44
  * @param {string} [props.title='members'] section header label (lowercase chrome)
45
45
  * @param {string[]} [props.roles] selectable roles (default member/contributor/guest; owner is never offered)
46
+ * @param {boolean} [props.canManage=true] whether the CURRENT VIEWER may edit roles / remove members at
47
+ * all (distinct from `member.owner`, which locks one specific ROW regardless of viewer). When `false`, every
48
+ * non-owner row's role renders as plain read-only text (no select) and its remove action is hidden entirely
49
+ * -- e.g. a non-owner viewing a roster they can't manage. Defaults to `true` (the prior, only behaviour) so
50
+ * existing callers are unaffected.
51
+ * @param {React.ReactNode} [props.filterSlot] an optional row rendered INSIDE the roster's own bordered
52
+ * box, directly under the header and before the member list (e.g. a "show: [org ▾]" list filter) -- lets a
53
+ * consumer add a filter/toolbar control that reads as part of THIS box, not a separate section floating
54
+ * above it. Undefined by default, so existing callers render exactly as before.
46
55
  */
47
- export default function RoleRoster({ members, onRole, onRemove, title, roles, }: {
56
+ export default function RoleRoster({ members, onRole, onRemove, title, roles, canManage, filterSlot, }: {
48
57
  members: RosterMember[];
49
58
  onRole?: (member: RosterMember, role: string) => void;
50
59
  onRemove?: (member: RosterMember) => (void | Promise<void>);
51
60
  title?: string;
52
61
  roles?: string[];
62
+ canManage?: boolean;
63
+ filterSlot?: React.ReactNode;
53
64
  }): any;
54
65
  /**
55
66
  * A clay-bordered section wrapping destructive actions (e.g. "delete collective"). Fronted by a
@@ -0,0 +1,18 @@
1
+ /**
2
+ * @param {Object} props
3
+ * @param {string} props.title Card heading (lowercase chrome by convention).
4
+ * @param {import('react').ComponentType<{ className?: string, 'aria-hidden'?: boolean | 'true' | 'false' }>} [props.icon]
5
+ * Lucide icon component rendered inline before the title.
6
+ * @param {import('react').ReactNode} [props.subtitle] One-line description under the title.
7
+ * @param {import('react').ReactNode} [props.aside] Right-aligned head slot (summary figure or control).
8
+ * @param {import('react').ReactNode} props.children Card body (the chart).
9
+ * @param {string} [props.className]
10
+ */
11
+ export default function ChartCard({ title, icon: Icon, subtitle, aside, children, className }: {
12
+ title: string;
13
+ icon?: any;
14
+ subtitle?: any;
15
+ aside?: any;
16
+ children: any;
17
+ className?: string;
18
+ }): any;
@@ -0,0 +1,16 @@
1
+ /**
2
+ * @param {Object} props
3
+ * @param {ContributorBreakdown[]} props.rows Pre-sorted rollup rows (sessions desc).
4
+ * @param {(row: ContributorBreakdown) => import('react').ReactNode} [props.renderContributor]
5
+ * Host-owned renderer for the contributor cell. Defaults to an
6
+ * initial-letter avatar + the raw id.
7
+ * @param {number} [props.limit] Cap the number of rows shown; omit for all.
8
+ * @param {string} [props.className]
9
+ */
10
+ export default function ContributorTable({ rows, renderContributor, limit, className }: {
11
+ rows: ContributorBreakdown[];
12
+ renderContributor?: (row: ContributorBreakdown) => any;
13
+ limit?: number;
14
+ className?: string;
15
+ }): any;
16
+ export type ContributorBreakdown = import("./types.js").ContributorBreakdown;
@@ -0,0 +1,40 @@
1
+ /**
2
+ * @param {Object} props
3
+ * @param {AnalyticsOverviewPayload} props.payload Cooked data payload — raw
4
+ * `sessions` (the surface computes the metrics) or a pre-computed
5
+ * `analytics` bundle; `analytics` wins if both are given.
6
+ * @param {string} [props.title] Heading above the grid. Omit for a chrome-less embed.
7
+ * @param {import('react').ReactNode} [props.subtitle] Sub-heading under the
8
+ * title; defaults to an auto-generated project/contributor/session summary.
9
+ * @param {ProjectOverviewSections} [props.sections] Host-level show/hide per
10
+ * section. Unset keys default to ON; a host-hidden section cannot be
11
+ * re-enabled by the built-in toggle.
12
+ * @param {boolean} [props.showSectionToggle] Show the built-in visible-section
13
+ * chip row. Default true.
14
+ * @param {number} [props.contributorLimit] Cap rows in the contributor table.
15
+ * @param {(row: ContributorBreakdown) => import('react').ReactNode} [props.renderContributor]
16
+ * Host-owned renderer for the contributor cell (name/avatar/link).
17
+ * @param {number} [props.chartHeight] Height (px) of each chart's plotting
18
+ * area. Default 200.
19
+ * @param {import('react').ReactNode} [props.footnote] Optional prose rendered
20
+ * at the end of the scroll region (`.gan-foot`) — page-level commentary the
21
+ * host wants to travel with the dashboard.
22
+ * @param {string} [props.className]
23
+ */
24
+ export default function ProjectOverview({ payload, title, subtitle, sections, showSectionToggle, contributorLimit, renderContributor, chartHeight, footnote, className, }: {
25
+ payload: AnalyticsOverviewPayload;
26
+ title?: string;
27
+ subtitle?: any;
28
+ sections?: ProjectOverviewSections;
29
+ showSectionToggle?: boolean;
30
+ contributorLimit?: number;
31
+ renderContributor?: (row: ContributorBreakdown) => any;
32
+ chartHeight?: number;
33
+ footnote?: any;
34
+ className?: string;
35
+ }): any;
36
+ export type AnalyticsOverviewPayload = import("./types.js").AnalyticsOverviewPayload;
37
+ export type ProjectOverviewSectionKey = import("./types.js").ProjectOverviewSectionKey;
38
+ export type ProjectOverviewSections = import("./types.js").ProjectOverviewSections;
39
+ export type ContributorBreakdown = import("./types.js").ContributorBreakdown;
40
+ export type ProjectAnalytics = import("./types.js").ProjectAnalytics;
@@ -0,0 +1,48 @@
1
+ /**
2
+ * Compact token count: 1234 → "1.2k", 62_000 → "62k", 1_234_567 → "1.23M".
3
+ * @param {number | null | undefined} n
4
+ * @returns {string}
5
+ */
6
+ export function formatTokens(n: number | null | undefined): string;
7
+ /**
8
+ * Round a number to at most 1 decimal place, dropping a trailing ".0".
9
+ * @param {number | null | undefined} n
10
+ * @returns {string}
11
+ */
12
+ export function formatNumber(n: number | null | undefined): string;
13
+ /**
14
+ * Percentage from a [0,1] rate: 0.4231 → "42%".
15
+ * @param {number | null | undefined} rate
16
+ * @returns {string}
17
+ */
18
+ export function formatRate(rate: number | null | undefined): string;
19
+ /**
20
+ * Minutes → human duration: 90 → "1h 30m", 45 → "45m".
21
+ * @param {number | null | undefined} mins
22
+ * @returns {string}
23
+ */
24
+ export function formatDuration(mins: number | null | undefined): string;
25
+ /**
26
+ * Shorten a `YYYY-MM-DD` week key to `MM-DD` for compact axis ticks.
27
+ * @param {string} week
28
+ * @returns {string}
29
+ */
30
+ export function shortWeek(week: string): string;
31
+ /**
32
+ * Format a median·p90 pair of plain numbers with MATCHED precision (the
33
+ * identical-precision rule: "8.0 · 19.2", never "8 · 19.2"; two integers stay
34
+ * "12 · 27"). Nulls render "—" individually.
35
+ * @param {number | null | undefined} a
36
+ * @param {number | null | undefined} b
37
+ * @returns {[string, string]}
38
+ */
39
+ export function formatNumberPair(a: number | null | undefined, b: number | null | undefined): [string, string];
40
+ /**
41
+ * Format a median·p90 pair of token counts with a SHARED unit and matched
42
+ * precision ("10.5k · 23.0k", "62k · 106k"). Unit is picked from the larger
43
+ * value; nulls render "—" individually.
44
+ * @param {number | null | undefined} a
45
+ * @param {number | null | undefined} b
46
+ * @returns {[string, string]}
47
+ */
48
+ export function formatTokenPair(a: number | null | undefined, b: number | null | undefined): [string, string];
@@ -0,0 +1,24 @@
1
+ export { default as ProjectOverview } from "./ProjectOverview.jsx";
2
+ export { default as ChartCard } from "./ChartCard.jsx";
3
+ export { default as ContributorTable } from "./ContributorTable.jsx";
4
+ export type AnalyticsSessionOutcome = import("./types.js").AnalyticsSessionOutcome;
5
+ export type ProjectOverviewSectionKey = import("./types.js").ProjectOverviewSectionKey;
6
+ export type AnalyticsSessionRecord = import("./types.js").AnalyticsSessionRecord;
7
+ export type AnalyticsOverviewPayload = import("./types.js").AnalyticsOverviewPayload;
8
+ export type ProjectOverviewSections = import("./types.js").ProjectOverviewSections;
9
+ export type WeekCount = import("./types.js").WeekCount;
10
+ export type WeekContributors = import("./types.js").WeekContributors;
11
+ export type ReturningContributorRate = import("./types.js").ReturningContributorRate;
12
+ export type LongestStreak = import("./types.js").LongestStreak;
13
+ export type WeekNewContributors = import("./types.js").WeekNewContributors;
14
+ export type SessionToCommitRate = import("./types.js").SessionToCommitRate;
15
+ export type WeekAvgDuration = import("./types.js").WeekAvgDuration;
16
+ export type OutcomeDistribution = import("./types.js").OutcomeDistribution;
17
+ export type MedianP90 = import("./types.js").MedianP90;
18
+ export type SessionStats = import("./types.js").SessionStats;
19
+ export type ContributorBreakdown = import("./types.js").ContributorBreakdown;
20
+ export type ProjectAnalytics = import("./types.js").ProjectAnalytics;
21
+ export { computeProjectAnalytics, sessionHasCommit, sessionsPerWeek, weeklyActiveContributors, returningContributorRate, longestStreak, newContributorVelocity, sessionToCommitRate, avgDurationPerActiveWeek, outcomeDistribution, resolvedRate, sessionStats, perContributorBreakdown } from "./metrics.js";
22
+ export { median, percentile, medianAndP90 } from "./stats.js";
23
+ export { weekKey, dayKey, daysBetween, parseTime, isoDate } from "./time.js";
24
+ export { ANALYTICS_SESSION_OUTCOMES, PROJECT_OVERVIEW_SECTION_DEFS, PROJECT_OVERVIEW_SECTION_KEYS } from "./types.js";
@@ -0,0 +1,130 @@
1
+ /** @typedef {import('./types.js').AnalyticsSessionRecord} AnalyticsSessionRecord */
2
+ /** @typedef {import('./types.js').WeekCount} WeekCount */
3
+ /** @typedef {import('./types.js').WeekContributors} WeekContributors */
4
+ /** @typedef {import('./types.js').ReturningContributorRate} ReturningContributorRate */
5
+ /** @typedef {import('./types.js').LongestStreak} LongestStreak */
6
+ /** @typedef {import('./types.js').WeekNewContributors} WeekNewContributors */
7
+ /** @typedef {import('./types.js').SessionToCommitRate} SessionToCommitRate */
8
+ /** @typedef {import('./types.js').WeekAvgDuration} WeekAvgDuration */
9
+ /** @typedef {import('./types.js').OutcomeDistribution} OutcomeDistribution */
10
+ /** @typedef {import('./types.js').SessionStats} SessionStats */
11
+ /** @typedef {import('./types.js').ContributorBreakdown} ContributorBreakdown */
12
+ /** @typedef {import('./types.js').ProjectAnalytics} ProjectAnalytics */
13
+ /**
14
+ * Does this session have at least one linked commit? `commitCount > 0` wins
15
+ * when present, else the `hasCommit` flag.
16
+ * @param {AnalyticsSessionRecord} s
17
+ * @returns {boolean}
18
+ */
19
+ export function sessionHasCommit(s: AnalyticsSessionRecord): boolean;
20
+ /**
21
+ * sessionsPerWeek — number of sessions per ISO week, sorted ascending by week.
22
+ * Weeks with no sessions are omitted (callers can densify if they want a gap-
23
+ * free axis). Sessions with an unparseable `startTime` are dropped.
24
+ * @param {AnalyticsSessionRecord[]} sessions
25
+ * @returns {WeekCount[]}
26
+ */
27
+ export function sessionsPerWeek(sessions: AnalyticsSessionRecord[]): WeekCount[];
28
+ /**
29
+ * weeklyActiveContributors — distinct contributor ids active in each ISO week,
30
+ * sorted ascending by week. The host's `contributorId` is treated as an opaque
31
+ * key; empty ids are ignored.
32
+ * @param {AnalyticsSessionRecord[]} sessions
33
+ * @returns {WeekContributors[]}
34
+ */
35
+ export function weeklyActiveContributors(sessions: AnalyticsSessionRecord[]): WeekContributors[];
36
+ /**
37
+ * returningContributorRate — fraction of contributors who were active in two
38
+ * or more distinct ISO weeks. A single-week contributor is "new/one-off"; a
39
+ * multi-week contributor is "returning".
40
+ * @param {AnalyticsSessionRecord[]} sessions
41
+ * @returns {ReturningContributorRate}
42
+ */
43
+ export function returningContributorRate(sessions: AnalyticsSessionRecord[]): ReturningContributorRate;
44
+ /**
45
+ * longestStreak — the longest run of consecutive active ISO weeks across all
46
+ * sessions (project-wide, not per contributor). "Consecutive" means each active
47
+ * week's Monday is exactly 7 days after the previous active week's Monday.
48
+ * @param {AnalyticsSessionRecord[]} sessions
49
+ * @returns {LongestStreak}
50
+ */
51
+ export function longestStreak(sessions: AnalyticsSessionRecord[]): LongestStreak;
52
+ /**
53
+ * newContributorVelocity — count of contributors making their first-ever
54
+ * appearance in each ISO week, sorted ascending. A contributor is counted once,
55
+ * in the week of their earliest session. Useful as an acquisition / growth
56
+ * signal for a project or collective.
57
+ * @param {AnalyticsSessionRecord[]} sessions
58
+ * @returns {WeekNewContributors[]}
59
+ */
60
+ export function newContributorVelocity(sessions: AnalyticsSessionRecord[]): WeekNewContributors[];
61
+ /**
62
+ * sessionToCommitRate — fraction of sessions that produced at least one commit.
63
+ * Uses `commitCount > 0` when present, else the `hasCommit` flag. A session
64
+ * with neither set counts as "no commit".
65
+ * @param {AnalyticsSessionRecord[]} sessions
66
+ * @returns {SessionToCommitRate}
67
+ */
68
+ export function sessionToCommitRate(sessions: AnalyticsSessionRecord[]): SessionToCommitRate;
69
+ /**
70
+ * avgDurationPerActiveWeek — mean session duration (minutes) for each ISO week
71
+ * that had at least one session, sorted ascending. Inactive weeks are omitted
72
+ * (hence "per ACTIVE week"). Non-finite durations are ignored.
73
+ * @param {AnalyticsSessionRecord[]} sessions
74
+ * @returns {WeekAvgDuration[]}
75
+ */
76
+ export function avgDurationPerActiveWeek(sessions: AnalyticsSessionRecord[]): WeekAvgDuration[];
77
+ /**
78
+ * outcomeDistribution — counts of sessions per outcome. Sessions with no
79
+ * outcome are bucketed under `unknown`, so the four buckets always sum to
80
+ * `total`.
81
+ * @param {AnalyticsSessionRecord[]} sessions
82
+ * @returns {OutcomeDistribution}
83
+ */
84
+ export function outcomeDistribution(sessions: AnalyticsSessionRecord[]): OutcomeDistribution;
85
+ /**
86
+ * perContributorBreakdown — one rolled-up row per contributor, sorted by
87
+ * session count descending (ties broken by contributor id). Powers the
88
+ * contributor table in `ProjectOverview`. Sessions with an empty
89
+ * `contributorId` are skipped.
90
+ * @param {AnalyticsSessionRecord[]} sessions
91
+ * @returns {ContributorBreakdown[]}
92
+ */
93
+ export function perContributorBreakdown(sessions: AnalyticsSessionRecord[]): ContributorBreakdown[];
94
+ /**
95
+ * resolvedRate — the share of a contributor's KNOWN-outcome sessions that
96
+ * resolved. Unknown-outcome sessions are excluded from the denominator (an
97
+ * unrecorded outcome is not a non-resolution); `null` when no session has a
98
+ * known outcome, so callers can render a placeholder instead of a false 0%.
99
+ * @param {OutcomeDistribution} outcomes
100
+ * @returns {number | null}
101
+ */
102
+ export function resolvedRate(outcomes: OutcomeDistribution): number | null;
103
+ /**
104
+ * sessionStats — median + p90 of the four core numeric session fields across
105
+ * the input. A convenience wrapper around `medianAndP90` for the "typical vs.
106
+ * tail" card in `ProjectOverview`.
107
+ * @param {AnalyticsSessionRecord[]} sessions
108
+ * @returns {SessionStats}
109
+ */
110
+ export function sessionStats(sessions: AnalyticsSessionRecord[]): SessionStats;
111
+ /**
112
+ * computeProjectAnalytics — run every metric over a session list and assemble
113
+ * the `ProjectAnalytics` bundle. Pure: no React, no I/O. This is what
114
+ * `ProjectOverview` calls internally when handed raw records.
115
+ * @param {AnalyticsSessionRecord[]} sessions
116
+ * @returns {ProjectAnalytics}
117
+ */
118
+ export function computeProjectAnalytics(sessions: AnalyticsSessionRecord[]): ProjectAnalytics;
119
+ export type AnalyticsSessionRecord = import("./types.js").AnalyticsSessionRecord;
120
+ export type WeekCount = import("./types.js").WeekCount;
121
+ export type WeekContributors = import("./types.js").WeekContributors;
122
+ export type ReturningContributorRate = import("./types.js").ReturningContributorRate;
123
+ export type LongestStreak = import("./types.js").LongestStreak;
124
+ export type WeekNewContributors = import("./types.js").WeekNewContributors;
125
+ export type SessionToCommitRate = import("./types.js").SessionToCommitRate;
126
+ export type WeekAvgDuration = import("./types.js").WeekAvgDuration;
127
+ export type OutcomeDistribution = import("./types.js").OutcomeDistribution;
128
+ export type SessionStats = import("./types.js").SessionStats;
129
+ export type ContributorBreakdown = import("./types.js").ContributorBreakdown;
130
+ export type ProjectAnalytics = import("./types.js").ProjectAnalytics;
@@ -0,0 +1,23 @@
1
+ /** @typedef {import('./types.js').MedianP90} MedianP90 */
2
+ /**
3
+ * Linear-interpolated percentile over a numeric array. `p` is in [0, 1].
4
+ * Non-finite values are dropped first. Returns `null` for an empty input.
5
+ * @param {number[]} values
6
+ * @param {number} p
7
+ * @returns {number | null}
8
+ */
9
+ export function percentile(values: number[], p: number): number | null;
10
+ /**
11
+ * Median of a numeric array (50th percentile). `null` for an empty input.
12
+ * @param {number[]} values
13
+ * @returns {number | null}
14
+ */
15
+ export function median(values: number[]): number | null;
16
+ /**
17
+ * Compute the median and p90 of a distribution in a single pass-pair. Useful
18
+ * for "typical vs. tail" framing (e.g. duration, tokens) per metric.
19
+ * @param {number[]} values
20
+ * @returns {MedianP90}
21
+ */
22
+ export function medianAndP90(values: number[]): MedianP90;
23
+ export type MedianP90 = import("./types.js").MedianP90;
@@ -0,0 +1,32 @@
1
+ /**
2
+ * Parse an ISO-8601 string into epoch milliseconds, or `null` if invalid.
3
+ * @param {string} iso
4
+ * @returns {number | null}
5
+ */
6
+ export function parseTime(iso: string): number | null;
7
+ /**
8
+ * The UTC Monday-of-week date key (`YYYY-MM-DD`) for a given ISO timestamp.
9
+ * Returns `null` for unparseable input. ISO weeks start on Monday.
10
+ * @param {string} iso
11
+ * @returns {string | null}
12
+ */
13
+ export function weekKey(iso: string): string | null;
14
+ /**
15
+ * The UTC day key (`YYYY-MM-DD`) for a given ISO timestamp, or `null`.
16
+ * @param {string} iso
17
+ * @returns {string | null}
18
+ */
19
+ export function dayKey(iso: string): string | null;
20
+ /**
21
+ * Format a Date as a UTC `YYYY-MM-DD` string.
22
+ * @param {Date} d
23
+ * @returns {string}
24
+ */
25
+ export function isoDate(d: Date): string;
26
+ /**
27
+ * Number of whole days between two `YYYY-MM-DD` date keys (b - a).
28
+ * @param {string} a
29
+ * @param {string} b
30
+ * @returns {number}
31
+ */
32
+ export function daysBetween(a: string, b: string): number;