@knpkv/herdr-work 0.10.0 → 0.12.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/dist/view.js CHANGED
@@ -1,16 +1,16 @@
1
1
  import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { Button, StateLabel, Text } from "@knpkv/rly/primitives";
3
- import { DecisionBar, Hero, Region, StageRail, TimelineRow } from "@knpkv/rly/patterns";
3
+ import { Icon } from "@knpkv/rly/foundations";
4
+ import { DecisionBar, Hero, HeroWord, Region } from "@knpkv/rly/patterns";
4
5
  import { useEffect, useRef, useState } from "react";
5
- import { activityShownOf, finishedNotShown, goalsNotShown } from "./model.js";
6
+ import { activityShownOf } from "./model.js";
6
7
  import { decodeWorkBoardNavigationGoal, encodeWorkBoardNavigationGoal } from "./navigation.js";
7
8
  import { workRequestClockText, workRequestDecidability } from "./request-decision.js";
8
9
  import { displayStateOf, observedFor } from "./display-state.js";
9
- import { workTriage, workTriageGroups, workTriageGroupTitle, workTriageSentence } from "./work-triage.js";
10
+ import { workGoalFinishedAt, workTriage, workTriageGroups, workTriageGroupTitle, workTriageSentence } from "./work-triage.js";
10
11
  /** The request clock's wording ("52s", "4m 12s", "11m", "expiring"), shared with hosts that show the same clocks. */
11
12
  export { workRequestClockText } from "./request-decision.js";
12
13
  const windows = ["now", "day", "week", "month"];
13
- const stageOrder = ["local", "review", "pull_request", "merged", "deployed"];
14
14
  const initialVisibleGoalCount = 10;
15
15
  const selectedGoalFragment = "work-selected-goal";
16
16
  const goalStates = [
@@ -67,17 +67,30 @@ const agentStatusLabel = {
67
67
  gone: "gone"
68
68
  };
69
69
  const deliveryLabel = {
70
- local: "Local",
71
- review: "Review",
70
+ local: "In progress",
71
+ review: "In review",
72
72
  pull_request: "Pull request",
73
73
  merged: "Merged",
74
74
  deployed: "Deployed"
75
75
  };
76
76
  const reviewPresentation = {
77
- not_requested: { label: "Not requested", tone: "neutral" },
78
- requested: { label: "Requested", tone: "caution" },
79
- changes_requested: { label: "Changes requested", tone: "critical" },
80
- approved: { label: "Approved", tone: "positive" }
77
+ not_requested: { label: "Not requested", evidence: "no review yet", tone: "neutral" },
78
+ requested: { label: "Requested", evidence: "review requested", tone: "caution" },
79
+ changes_requested: { label: "Changes requested", evidence: "changes requested", tone: "critical" },
80
+ approved: { label: "Approved", evidence: "approved", tone: "positive" }
81
+ };
82
+ const checksPresentation = {
83
+ none: { label: "no checks", tone: "neutral" },
84
+ pending: { label: "checks running", tone: "progress" },
85
+ passing: { label: "checks passing", tone: "positive" },
86
+ failing: { label: "checks failing", tone: "critical" }
87
+ };
88
+ const stateIcon = {
89
+ neutral: "minus",
90
+ positive: "check",
91
+ critical: "alert",
92
+ caution: "clock",
93
+ progress: "loader"
81
94
  };
82
95
  const requestPresentation = {
83
96
  open: { label: "Open", tone: "caution" },
@@ -89,6 +102,17 @@ const formatTimestamp = (timestamp) => new Intl.DateTimeFormat("en-GB", {
89
102
  dateStyle: "medium",
90
103
  timeStyle: "short"
91
104
  }).format(timestamp);
105
+ /** The board's timestamp formatter also supplies compact clocks. */
106
+ const formatClock = (timestamp) => formatTimestamp(timestamp).split(", ").at(-1) ?? formatTimestamp(timestamp);
107
+ const ageOf = (timestamp, asOf) => {
108
+ const minutes = Math.max(0, Math.floor((asOf - timestamp) / 60_000));
109
+ if (minutes < 60)
110
+ return `${minutes}m ago`;
111
+ if (minutes < 1_440)
112
+ return `${Math.floor(minutes / 60)}h ago`;
113
+ const days = Math.floor(minutes / 1_440);
114
+ return `${days} ${days === 1 ? "day" : "days"} ago`;
115
+ };
92
116
  const formatSpend = (goal) => goal.spend === null
93
117
  ? "Not recorded"
94
118
  : new Intl.NumberFormat("en", {
@@ -102,12 +126,6 @@ const blockersFor = (goal) => {
102
126
  };
103
127
  const activityFor = (goal) => goal.activity ?? [];
104
128
  const requestsFor = (goal) => goal.requests ?? [];
105
- const hierarchyLabel = (goal) => {
106
- const hierarchy = goal.agentHierarchy;
107
- if (hierarchy === undefined || hierarchy === null)
108
- return "No agent hierarchy recorded";
109
- return `${hierarchy.agent.host} / ${hierarchy.agent.name}`;
110
- };
111
129
  /** Renders the persisted approval deep link after its origin is bound at ingress. */
112
130
  const exactLink = (target, label) => (_jsx("a", { className: "work-exact-link", href: target.url, children: label }));
113
131
  /** Renders the persisted review destination without rewriting its credential-free URL. */
@@ -118,24 +136,37 @@ const reviewLabel = (review) => {
118
136
  }
119
137
  return (_jsx(StateLabel, { label: reviewPresentation[review.state].label, size: "compact", tone: reviewPresentation[review.state].tone }));
120
138
  };
121
- /** Delivery as words: past stages are done, the current one is "now" in the goal's state ink. */
122
- const stagesFor = (goal, shown) => {
123
- const current = stageOrder.indexOf(goal.delivery);
124
- return stageOrder.map((stage, index) => ({
125
- id: `${goal.id}-${stage}`,
126
- name: deliveryLabel[stage],
127
- state: index < current ? "done" : index === current ? "now" : "not yet",
128
- tone: index === current ? displayPresentation[shown].tone : "neutral"
129
- }));
139
+ /** PR delivery includes review; local work includes it only when recorded. Abandoned work stops at its last step. */
140
+ const GoalProgress = ({ goal, observed }) => {
141
+ const shown = observed?.displayState ?? goal.state;
142
+ const merged = observed?.pullRequest?.fact.state === "merged" || goal.delivery === "merged";
143
+ const hasPullRequest = merged || observed?.pullRequest != null || goal.delivery === "pull_request";
144
+ const hasReview = hasPullRequest ||
145
+ goal.delivery === "review" ||
146
+ shown === "review" ||
147
+ (goal.review != null && goal.review.state !== "not_requested");
148
+ const finished = !hasPullRequest && (shown === "completed" || shown === "deployed");
149
+ const names = hasReview
150
+ ? ["Planned", "In progress", "In review", hasPullRequest ? "Merged" : "Done"]
151
+ : ["Planned", "In progress", "Done"];
152
+ const finalStep = names.length - 1;
153
+ const current = merged || finished ? finalStep : hasReview ? 2 : shown === "planned" ? 0 : 1;
154
+ const abandoned = shown === "abandoned";
155
+ return (_jsxs("section", { "aria-labelledby": "work-delivery-title", className: "work-delivery", children: [_jsx("h3", { className: "work-group-title", id: "work-delivery-title", children: "Delivery" }), _jsx("ol", { "aria-label": `Delivery of ${goal.title}`, className: "work-row-progress", "data-steps": names.length, role: "list", children: names.map((name, index) => (_jsxs("li", { "aria-current": !abandoned && index === current ? "step" : undefined, "aria-label": abandoned && index === current ? `${name}, abandoned here` : undefined, "data-reached": index < current || (!abandoned && index === current), "data-stopped": abandoned && index === current, "data-tone": displayPresentation[shown].tone, children: [_jsx("span", { "aria-hidden": "true", className: "work-step-number", children: index + 1 }), _jsx("span", { className: "work-step-name", children: name }), abandoned && index === current ? (_jsx("span", { className: "work-step-status", children: "Abandoned" })) : !abandoned && index === current && current !== finalStep ? (_jsx(StateLabel, { icon: stateIcon[displayPresentation[shown].tone], label: "Now", size: "compact", tone: displayPresentation[shown].tone })) : (_jsx("span", { className: "work-step-status", children: index < current || (!abandoned && index === current) ? "Done" : "Not yet" }))] }, name))) }), hasPullRequest ? null : (_jsx(Text, { tone: "secondary", variant: "meta", children: "No pull request" }))] }));
156
+ };
157
+ /** CI and review come only from an observed PR. Its confirmation time says when those facts were last read. */
158
+ const GoalEvidence = ({ goal, observed }) => {
159
+ const pullRequest = observed?.pullRequest;
160
+ if (pullRequest == null && goal.delivery !== "pull_request" && goal.delivery !== "merged")
161
+ return null;
162
+ const ci = pullRequest == null
163
+ ? { label: "checks unknown", tone: "neutral" }
164
+ : checksPresentation[pullRequest.fact.checks];
165
+ const review = pullRequest == null
166
+ ? { evidence: "review unknown", tone: "neutral" }
167
+ : reviewPresentation[pullRequest.fact.review];
168
+ return (_jsxs("div", { className: "work-row-evidence", children: [_jsxs("span", { className: "work-evidence-chip", children: [_jsx(StateLabel, { className: "work-ci-fact", icon: stateIcon[ci.tone], label: ci.label, size: "compact", tone: ci.tone }), _jsx("span", { className: "work-row-read", children: pullRequest == null ? (" · Not read") : (_jsxs(_Fragment, { children: [observed?.unknown?.source === "github" ? " · last read " : " · read ", _jsx("time", { dateTime: new Date(pullRequest.confirmedAt).toISOString(), title: formatTimestamp(pullRequest.confirmedAt), children: formatClock(pullRequest.confirmedAt) })] })) })] }), _jsxs("span", { className: "work-evidence-chip", children: [_jsx(StateLabel, { className: "work-review-fact", icon: stateIcon[review.tone], label: review.evidence, size: "compact", tone: review.tone }), _jsx("span", { className: "work-row-read", children: pullRequest == null ? (" · Not read") : (_jsxs(_Fragment, { children: [observed?.unknown?.source === "github" ? " · last read" : " · read", " ", _jsx("time", { dateTime: new Date(pullRequest.confirmedAt).toISOString(), title: formatTimestamp(pullRequest.confirmedAt), children: formatClock(pullRequest.confirmedAt) })] })) })] })] }));
130
169
  };
131
- /**
132
- * The repository as a row names it: its last path segment ("npm" for a checkout at
133
- * /home/…/knpkv.dev/npm, or for "knpkv/npm"). The detail keeps the full value.
134
- */
135
- const repositoryName = (repository) => repository
136
- .split("/")
137
- .filter((segment) => segment.length > 0)
138
- .at(-1) ?? repository;
139
170
  const rowCaption = (goal, observed, decisions) => {
140
171
  const open = requestsFor(goal).filter(({ state }) => state === "open");
141
172
  if (open.length > 0) {
@@ -151,16 +182,14 @@ const rowCaption = (goal, observed, decisions) => {
151
182
  : `, ${workRequestClockText(soonest.expiresAt, decisions.now)}${soonest.expiresAt > decisions.now ? " left" : ""}`;
152
183
  return {
153
184
  blocking: false,
154
- text: open.length === 1
155
- ? `Needs approval: ${open[0]?.summary ?? ""}${clock}`
156
- : `${open.length} requests need approval${clock}`
185
+ text: open.length === 1 ? `${open[0]?.summary ?? ""}${clock}` : `${open.length} requests need approval${clock}`
157
186
  };
158
187
  }
159
188
  const blockers = blockersFor(goal);
160
189
  if (blockers.length > 0)
161
190
  return { blocking: true, text: blockers[0]?.summary ?? "Blocked" };
162
191
  if (observed?.stale === true && observed.agent !== null) {
163
- return { blocking: false, text: `Owner gone since ${formatTimestamp(observed.agent.observedAt)}` };
192
+ return { blocking: false, text: `Owner gone since ${formatClock(observed.agent.observedAt)}` };
164
193
  }
165
194
  if (observed?.unknown != null) {
166
195
  return {
@@ -174,24 +203,29 @@ const rowCaption = (goal, observed, decisions) => {
174
203
  return { blocking: false, text: `${goal.owner.name}, ${deliveryLabel[goal.delivery].toLowerCase()}` };
175
204
  };
176
205
  /** The caption under the hero: the request waiting longest, or the latest change. */
177
- const summaryCaption = (summary, tense) => {
206
+ const summaryCaption = (summary, tense, snapshot) => {
178
207
  switch (summary._tag) {
179
208
  case "Attention":
180
209
  return summary.oldestRequest === null
181
210
  ? undefined
182
- : `${tense === "present" ? "Waiting longest" : "Waiting longest then"}: ${summary.oldestRequest.request.summary} on ${summary.oldestRequest.goal.title}, requested ${formatTimestamp(summary.oldestRequest.request.requestedAt)}.`;
183
- case "Clear":
184
- return summary.latest === null
185
- ? undefined
186
- : `${summary.moving} moving. Last change: ${summary.latest.title}, ${formatTimestamp(summary.latest.updatedAt)}.`;
211
+ : `${tense === "present" ? "Waiting longest" : "Waiting longest then"}: ${summary.oldestRequest.request.summary} on ${summary.oldestRequest.goal.title}${tense === "past" ? "." : `, requested ${ageOf(summary.oldestRequest.request.requestedAt, snapshot.asOf)}.`}`;
212
+ case "Clear": {
213
+ const rows = workTriage(snapshot).rows;
214
+ const planned = rows.filter((row) => row.group === "planned").length;
215
+ const finished = rows
216
+ .filter((row) => row.group === "done" || row.group === "earlier")
217
+ .map(({ goal }) => ({ goal, at: workGoalFinishedAt(goal, observedFor(snapshot, goal.id)) }))
218
+ .toSorted((left, right) => right.at - left.at)[0];
219
+ return `${summary.moving} ${summary.moving === 1 ? "goal" : "goals"} ${tense === "past" ? "were " : ""}moving, ${planned} planned.${finished === undefined ? "" : ` Last finished: ${finished.goal.title}, ${ageOf(finished.at, snapshot.asOf)}.`}`;
220
+ }
187
221
  case "Empty":
188
- return "Delegate work to an agent and its goal appears here once the hub admits it.";
222
+ return undefined;
189
223
  }
190
224
  };
191
225
  /**
192
226
  * What the timeline shows for one goal, newest first: the owner's recorded activity, plus what the
193
227
  * reconciler observed (a pull request, the owner's agent) and any source it could not read. Observed
194
- * events carry their provenance as a shape and words; an unreadable source is drawn hatched.
228
+ * events keep source detail and provenance in their accessible descriptions beside terse visible titles.
195
229
  */
196
230
  const timelineFor = (goal, observed) => {
197
231
  const recorded = activityFor(goal).map((entry) => ({
@@ -199,7 +233,7 @@ const timelineFor = (goal, observed) => {
199
233
  dateTime: new Date(entry.occurredAt).toISOString(),
200
234
  detail: activityKindLabel[entry.kind],
201
235
  id: entry.id,
202
- time: formatTimestamp(entry.occurredAt),
236
+ time: formatClock(entry.occurredAt),
203
237
  title: entry.summary
204
238
  }));
205
239
  const seen = [];
@@ -212,7 +246,7 @@ const timelineFor = (goal, observed) => {
212
246
  detail: `${checksLabel[fact.checks]}, last read ${formatTimestamp(confirmedAt)}`,
213
247
  id: `observed-pull-request-${fact.repository}-${fact.pullRequest}`,
214
248
  provenance: { kind: "auto", label: "Observed on GitHub" },
215
- time: formatTimestamp(at),
249
+ time: formatClock(at),
216
250
  title: `Pull request #${fact.pullRequest} ${pullRequestStateLabel[fact.state]}`
217
251
  });
218
252
  }
@@ -224,7 +258,7 @@ const timelineFor = (goal, observed) => {
224
258
  detail: `${fact.host}, last read ${formatTimestamp(confirmedAt)}`,
225
259
  id: `observed-agent-${fact.host}-${fact.agentId}`,
226
260
  provenance: { kind: "auto", label: "Observed in herdr" },
227
- time: formatTimestamp(observedAt),
261
+ time: formatClock(observedAt),
228
262
  title: `Agent ${agentStatusLabel[fact.status]}`
229
263
  });
230
264
  }
@@ -239,13 +273,20 @@ const timelineFor = (goal, observed) => {
239
273
  kind: "unknown",
240
274
  label: lastGoodAt === null ? "Never read" : `Last good read ${formatTimestamp(lastGoodAt)}`
241
275
  },
242
- time: formatTimestamp(since),
276
+ time: formatClock(since),
243
277
  title: `Couldn't read ${sourceLabel[source]}`
244
278
  });
245
279
  }
246
280
  return [...recorded, ...seen].toSorted((left, right) => Date.parse(right.dateTime) - Date.parse(left.dateTime));
247
281
  };
248
- const requestDecisionFor = (request, decisions) => {
282
+ const requestDecisionFor = (request, decisions, historical) => {
283
+ // A recorded open request is never a live approval target; no current queue, clock or handler reaches this bar.
284
+ if (historical && request.state === "open" && request.approvalTarget !== null) {
285
+ return {
286
+ _tag: "Bar",
287
+ bar: (_jsx(DecisionBar, { onApprove: () => undefined, onReject: () => undefined, state: { _tag: "off", reason: "Decisions are off in the past." }, target: request.summary }))
288
+ };
289
+ }
249
290
  const decidability = workRequestDecidability(request, decisions);
250
291
  if (decidability._tag === "Elsewhere" || decisions === undefined)
251
292
  return { _tag: "Elsewhere" };
@@ -284,17 +325,21 @@ const requestDecisionFor = (request, decisions) => {
284
325
  };
285
326
  };
286
327
  /** One request in a goal's detail: its title once, then the bar, the hub link or the outcome. */
287
- const RequestItem = ({ decisions, externalLinks, request }) => {
288
- const decision = requestDecisionFor(request, externalLinks === "enabled" ? decisions : undefined);
328
+ const RequestItem = ({ asOf, decisions, externalLinks, historical, request }) => {
329
+ const decision = requestDecisionFor(request, externalLinks === "enabled" ? decisions : undefined, historical && externalLinks === "enabled");
289
330
  const presentation = requestPresentation[request.state];
290
- return (_jsxs("li", { children: [decision._tag === "Bar" ? null : (_jsxs("span", { className: "work-request-heading", children: [_jsx(Text, { children: request.summary }), _jsx("span", { className: "work-row-state", "data-tone": presentation.tone, children: presentation.label })] })), decision._tag === "Bar" ? (decision.bar) : decision._tag === "Settled" ? (decision.refusal === null ? null : (_jsx(Text, { tone: "secondary", variant: "meta", children: decision.refusal }))) : request.state !== "open" ? null : request.approvalTarget === null ? (_jsx(Text, { tone: "secondary", variant: "meta", children: "No approval link recorded." })) : externalLinks === "disabled" ? (_jsxs(Text, { tone: "secondary", variant: "meta", children: ["Approve this on the hub (", request.approvalTarget.host, ")."] })) : (exactLink(request.approvalTarget, `Approve on ${request.approvalTarget.host}`)), decision._tag === "Elsewhere" ? null : (_jsx("p", { "aria-atomic": "true", className: "work-request-announcement", role: "status", children: decision._tag === "Settled" ? decision.announcement : "" }))] }));
331
+ return (_jsxs("li", { children: [decision._tag === "Bar" ? null : (_jsxs("span", { className: "work-request-heading", children: [_jsx(StateLabel, { className: "work-row-state", icon: request.state === "rejected" ? "close" : stateIcon[presentation.tone], label: presentation.label, size: "compact", tone: presentation.tone }), _jsx(Text, { as: "strong", variant: "meta", children: request.summary }), request.state === "open" ? null : (_jsxs(Text, { tone: "secondary", variant: "meta", children: ["requested ", ageOf(request.requestedAt, asOf)] }))] })), request.state === "open" ? (_jsxs("div", { className: "work-request-meta", children: [decision._tag === "Bar" ? _jsx(StateLabel, { icon: "clock", label: "Open", size: "compact", tone: "caution" }) : null, _jsxs(Text, { tone: "secondary", variant: "meta", children: ["requested ", ageOf(request.requestedAt, asOf)] })] })) : null, decision._tag === "Bar" ? (decision.bar) : decision._tag === "Settled" ? (decision.refusal === null ? null : (_jsx(Text, { tone: "secondary", variant: "meta", children: decision.refusal }))) : request.state !== "open" ? null : request.approvalTarget === null ? (_jsx(Text, { tone: "secondary", variant: "meta", children: "No approval link recorded." })) : externalLinks === "disabled" ? (_jsxs(Text, { tone: "secondary", variant: "meta", children: ["Approve this on the hub (", request.approvalTarget.host, ")."] })) : (exactLink(request.approvalTarget, `Approve on ${request.approvalTarget.host}`)), decision._tag === "Elsewhere" ? null : (_jsx("p", { "aria-atomic": "true", className: "work-request-announcement", role: "status", children: decision._tag === "Settled" ? decision.announcement : "" }))] }));
291
332
  };
292
333
  /** Everything about one goal, in reading order: what it is, where it is, what blocks it, what happened. */
293
- const GoalDetail = ({ decisions, externalLinks, goal, snapshot }) => {
334
+ const GoalDetail = ({ closeControl, decisions, externalLinks, goal, snapshot }) => {
294
335
  const family = familyForGoal(snapshot, goal.id);
295
336
  const observed = observedFor(snapshot, goal.id);
296
337
  const shown = observed?.displayState ?? goal.state;
297
338
  const activity = timelineFor(goal, observed);
339
+ const readDay = new Date(snapshot.observedAt).toDateString();
340
+ const agent = goal.agentHierarchy?.agent;
341
+ const agentName = agent?.name ?? goal.owner.name;
342
+ const agentIdentity = agent === undefined ? agentName : `${agent.host} / ${agentName}`;
298
343
  // Only the live window carries the overlay; there "nothing observed" is itself a reading.
299
344
  const overlay = snapshot.observed !== undefined;
300
345
  // A goal-level approval target (older checkpoints carry one without requests); skipped when a
@@ -304,16 +349,23 @@ const GoalDetail = ({ decisions, externalLinks, goal, snapshot }) => {
304
349
  requestsFor(goal).some(({ approvalTarget }) => approvalTarget?.url === goal.approvalTarget?.url)
305
350
  ? null
306
351
  : goal.approvalTarget;
307
- return (_jsxs("div", { className: "work-detail", children: [_jsx(Text, { tone: "secondary", children: goal.detail }), _jsx(StageRail, { heading: `Delivery of ${goal.title}`, size: "words", stages: stagesFor(goal, shown) }), _jsxs("dl", { className: "work-facts", children: [_jsxs("div", { children: [_jsx("dt", { children: "State" }), _jsxs("dd", { children: [displayPresentation[shown].label, shown === goal.state ? null : (_jsxs(Text, { as: "p", className: "work-fact-note", tone: "secondary", variant: "meta", children: ["Observed; recorded as ", statePresentation[goal.state].label.toLowerCase()] }))] })] }), overlay ? (_jsxs("div", { children: [_jsx("dt", { children: "Pull request" }), _jsx("dd", { children: observed?.pullRequest == null
308
- ? observed === null && snapshot.observedOmitted !== undefined
309
- ? "Not in this read: live state was trimmed to the most recently updated goals"
310
- : "None known"
311
- : `#${observed.pullRequest.fact.pullRequest} ${pullRequestStateLabel[observed.pullRequest.fact.state]}, ${checksLabel[observed.pullRequest.fact.checks]}` })] })) : null, _jsxs("div", { children: [_jsx("dt", { children: "Owner" }), _jsx("dd", { children: goal.owner.name })] }), _jsxs("div", { children: [_jsx("dt", { children: "Agent" }), _jsxs("dd", { children: [hierarchyLabel(goal), goal.agentHierarchy?.agent.relationship === undefined || goal.agentHierarchy === null
352
+ return (_jsxs("div", { className: "work-detail", children: [_jsxs("div", { className: "work-detail-heading", children: [_jsx(Text, { as: "h3", variant: "card-title", children: goal.title }), _jsx(StateLabel, { icon: stateIcon[displayPresentation[shown].tone], label: displayPresentation[shown].label, size: "compact", tone: displayPresentation[shown].tone }), shown === goal.state ? null : (_jsxs(Text, { className: "work-fact-note", tone: "secondary", variant: "meta", children: ["Observed; recorded as ", statePresentation[goal.state].label.toLowerCase()] }))] }), observed?.stale === true && observed.agent !== null ? (_jsxs("p", { className: "work-note", "data-tone": "held", children: [_jsx("b", { children: "Owner gone" }), " since ", formatClock(observed.agent.observedAt), ": this unfinished goal has no live agent."] })) : null, _jsx(GoalProgress, { goal: goal, observed: observed }), overlay ? _jsx(GoalEvidence, { goal: goal, observed: observed }) : null, _jsxs("dl", { className: "work-facts", children: [_jsxs("div", { children: [_jsx("dt", { children: "Pull request" }), _jsxs("dd", { children: [observed?.pullRequest == null
353
+ ? observed === null && snapshot.observedOmitted !== undefined
354
+ ? "Not in this read: live state was trimmed to the most recently updated goals"
355
+ : "None yet"
356
+ : `#${observed.pullRequest.fact.pullRequest} ${pullRequestStateLabel[observed.pullRequest.fact.state]}${observed.stale ? `, ${checksLabel[observed.pullRequest.fact.checks]}` : ""}`, observed?.pullRequest == null ? null : (_jsx(Text, { as: "p", className: "work-fact-note", tone: "secondary", variant: "meta", children: "Observed on GitHub" }))] })] }), goal.review == null ? null : (_jsxs("div", { children: [_jsx("dt", { children: "Review" }), _jsxs("dd", { children: [reviewLabel(goal.review), overlay ? null : ", as recorded", goal.review?.url === null || goal.review?.url === undefined ? null : externalLinks ===
357
+ "disabled" ? null : (_jsxs(_Fragment, { children: [" ", reviewLink(goal.review.url)] })), goal.review?.summary === null || goal.review?.summary === undefined ? null : (_jsx(Text, { tone: "secondary", variant: "meta", children: goal.review.summary }))] })] })), _jsxs("div", { children: [_jsx("dt", { children: "Repository" }), _jsx("dd", { children: goal.repository.repository })] }), _jsxs("div", { children: [_jsx("dt", { children: "Branch" }), _jsx("dd", { children: goal.repository.branch })] }), goal.owner.name === agentName ? null : (_jsxs("div", { children: [_jsx("dt", { children: "Owner" }), _jsx("dd", { children: goal.owner.name })] })), _jsxs("div", { children: [_jsx("dt", { children: "Agent" }), _jsxs("dd", { children: [observed?.agent == null
358
+ ? `${agentIdentity}, as recorded`
359
+ : `${agentIdentity}, ${agentStatusLabel[observed.agent.fact.status]}${observed.agent.fact.status === "gone" ? ` since ${formatClock(observed.agent.observedAt)}` : ""}`, observed?.agent == null ? null : (_jsx(Text, { as: "p", className: "work-fact-note", tone: "secondary", variant: "meta", children: "Observed in herdr" })), goal.agentHierarchy?.agent.relationship === undefined || goal.agentHierarchy === null
312
360
  ? null
313
- : `, ${goal.agentHierarchy.agent.relationship.relation} from ${goal.agentHierarchy.agent.relationship.parentAgentId}`] })] }), _jsxs("div", { children: [_jsx("dt", { children: "Repository" }), _jsxs("dd", { children: [goal.repository.repository, ", ", _jsx("code", { children: goal.repository.branch })] })] }), _jsxs("div", { children: [_jsx("dt", { children: "Review" }), _jsxs("dd", { children: [reviewLabel(goal.review), goal.review?.url === null || goal.review?.url === undefined ? null : externalLinks ===
314
- "disabled" ? null : (_jsxs(_Fragment, { children: [" ", reviewLink(goal.review.url)] })), goal.review?.summary === null || goal.review?.summary === undefined ? null : (_jsx(Text, { tone: "secondary", variant: "meta", children: goal.review.summary }))] })] }), _jsxs("div", { children: [_jsx("dt", { children: "Spend" }), _jsx("dd", { children: formatSpend(goal) })] })] }), observed?.stale === true && observed.agent !== null ? (_jsxs("p", { className: "work-note", "data-tone": "held", children: [_jsx("b", { children: "Owner gone" }), " since ", formatTimestamp(observed.agent.observedAt), ": this unfinished goal has no live agent."] })) : null, observed?.unknown == null ? null : (_jsxs("p", { className: "work-note", "data-tone": "unknown", children: [_jsxs("b", { children: ["Couldn't read ", sourceLabel[observed.unknown.source]] }), " since ", formatTimestamp(observed.unknown.since), ":", " ", observed.unknown.reason, ".", " ", observed.unknown.lastGoodAt === null
361
+ : `, ${goal.agentHierarchy.agent.relationship.relation} from ${goal.agentHierarchy.agent.relationship.parentAgentId}`] })] }), goal.spend === null ? null : (_jsxs("div", { children: [_jsx("dt", { children: "Spend" }), _jsx("dd", { children: formatSpend(goal) })] }))] }), goal.detail === goal.title ? null : _jsx(Text, { tone: "secondary", children: goal.detail }), observed?.unknown == null ? null : (_jsxs("p", { className: "work-note", "data-tone": "unknown", children: [_jsxs("b", { children: ["Couldn't read ", sourceLabel[observed.unknown.source]] }), " since ", formatTimestamp(observed.unknown.since), ":", " ", observed.unknown.reason, ".", " ", observed.unknown.lastGoodAt === null
315
362
  ? "It has never been read, so nothing here comes from it."
316
- : `Facts from it are as of ${formatTimestamp(observed.unknown.lastGoodAt)}.`] })), blockersFor(goal).map((blocker) => (_jsxs("p", { className: "work-note", "data-tone": "blocked", children: [_jsx("b", { children: "Blocked" }), " since ", formatTimestamp(blocker.since), ": ", blocker.summary] }, `${blocker.since}-${blocker.summary}`))), _jsxs("section", { "aria-labelledby": "work-requests-title", className: "work-detail-section", children: [_jsx("h3", { className: "work-group-title", id: "work-requests-title", children: "Requests" }), requestsFor(goal).length === 0 ? (_jsx(Text, { tone: "secondary", children: goal.requests === undefined ? "No requests recorded." : "No outstanding requests." })) : (_jsx("ul", { className: "work-detail-list", children: requestsFor(goal).map((request) => (_jsx(RequestItem, { decisions: decisions, externalLinks: externalLinks, request: request }, request.id))) }))] }), _jsxs("section", { "aria-labelledby": "work-activity-title", className: "work-detail-section", children: [_jsx("h3", { className: "work-group-title", id: "work-activity-title", children: "Activity" }), activityOmittedFor(snapshot, goal) === 0 ? null : (_jsx(Text, { tone: "secondary", variant: "meta", children: activityShownOf(goal.activity?.length ?? 0, activityOmittedFor(snapshot, goal)) })), activity.length === 0 ? (_jsx(Text, { tone: "secondary", children: goal.activity === undefined ? "No activity recorded." : "Activity is clear." })) : (_jsx("ol", { "aria-label": `Activity on ${goal.title}`, className: "work-activity", children: activity.map((event, index) => (_jsx(TimelineRow, { continued: index < activity.length - 1, event: event }, event.id))) }))] }), family === null ? null : (_jsxs("section", { "aria-labelledby": "work-family-title", className: "work-detail-section", children: [_jsx("h3", { className: "work-group-title", id: "work-family-title", children: "Superseded history" }), _jsxs("details", { className: "work-family-history", children: [_jsxs("summary", { children: ["Show ", family.superseded.length, " superseded"] }), _jsx("ul", { className: "work-detail-list", children: family.superseded.map((entry) => (_jsxs("li", { children: [_jsxs("span", { className: "work-request-heading", children: [_jsx(Text, { children: entry.title }), _jsx("span", { className: "work-row-state", "data-tone": statePresentation[entry.state].tone, children: statePresentation[entry.state].label })] }), _jsxs(Text, { tone: "secondary", variant: "meta", children: [entry.summary, ", ", formatTimestamp(entry.updatedAt)] }), blockersFor(entry).map((blocker) => (_jsxs(Text, { tone: "secondary", variant: "meta", children: ["Blocked since ", formatTimestamp(blocker.since), ": ", blocker.summary] }, `${blocker.since}-${blocker.summary}`))), entry.review === undefined || entry.review === null ? null : (_jsxs(Text, { tone: "secondary", variant: "meta", children: ["Review ", reviewPresentation[entry.review.state].label.toLowerCase(), entry.review.summary === null ? "" : `: ${entry.review.summary}`] }))] }, entry.id))) })] })] })), _jsxs("div", { className: "work-links", children: [goal.connectTarget === null ? (_jsx(Text, { tone: "secondary", children: "No exact Connect target recorded." })) : externalLinks === "disabled" ? (_jsx(Text, { tone: "secondary", variant: "meta", children: "Connect target recorded." })) : (_jsx("a", { className: "work-connect-link", href: goal.connectTarget.url, children: "Open the agent in Connect" })), goalApproval === null ? null : externalLinks === "disabled" ? (_jsxs(Text, { tone: "secondary", variant: "meta", children: ["Approval target recorded on ", goalApproval.host, "."] })) : (exactLink(goalApproval, `Open ${goalApproval.host} approval`))] })] }));
363
+ : `Facts from it are as of ${formatTimestamp(observed.unknown.lastGoodAt)}.`] })), blockersFor(goal).map((blocker) => (_jsxs("p", { className: "work-note", "data-tone": "blocked", children: [_jsx("b", { children: "Blocked" }), " since ", formatTimestamp(blocker.since), ": ", blocker.summary] }, `${blocker.since}-${blocker.summary}`))), _jsxs("section", { "aria-labelledby": "work-requests-title", className: "work-detail-section", children: [_jsx("h3", { className: "work-group-title", id: "work-requests-title", children: "Requests" }), requestsFor(goal).length === 0 ? (_jsx(Text, { tone: "secondary", children: goal.requests === undefined ? "No requests recorded." : "No outstanding requests." })) : (_jsx("ul", { className: "work-detail-list", children: requestsFor(goal).map((request) => (_jsx(RequestItem, { asOf: snapshot.asOf, decisions: decisions, externalLinks: externalLinks, historical: snapshot.window !== "now", request: request }, request.id))) }))] }), _jsxs("section", { "aria-labelledby": "work-activity-title", className: "work-detail-section", children: [_jsx("h3", { className: "work-group-title", id: "work-activity-title", children: "Activity" }), activityOmittedFor(snapshot, goal) === 0 ? null : (_jsx(Text, { tone: "secondary", variant: "meta", children: activityShownOf(goal.activity?.length ?? 0, activityOmittedFor(snapshot, goal)) })), activity.length === 0 ? (_jsx(Text, { tone: "secondary", children: goal.activity === undefined ? "No activity recorded." : "Activity is clear." })) : (_jsx("ol", { "aria-label": `Activity on ${goal.title}`, className: "work-activity", children: activity.map((event) => {
364
+ const descriptionId = `work-activity-${goal.id}-${event.id}`;
365
+ const eventAt = Date.parse(event.dateTime);
366
+ const date = new Date(eventAt).toDateString() === readDay ? null : formatTimestamp(eventAt);
367
+ return (_jsxs("li", { "aria-describedby": descriptionId, className: "work-activity-row", "data-rly-timeline-event-id": event.id, children: [_jsx("time", { dateTime: event.dateTime, children: event.time }), _jsx("span", { children: event.title }), _jsxs("span", { className: "work-accessible-detail", "data-rly-timeline-provenance": event.provenance?.kind, id: descriptionId, children: [event.detail, event.provenance === undefined ? "" : `. ${event.provenance.label}`, date === null ? "" : `. ${date}`] })] }, event.id));
368
+ }) }))] }), family === null ? null : (_jsxs("section", { "aria-labelledby": "work-family-title", className: "work-detail-section", children: [_jsx("h3", { className: "work-group-title", id: "work-family-title", children: "Superseded history" }), _jsxs("details", { className: "work-family-history", children: [_jsxs("summary", { children: ["Show ", family.superseded.length, " superseded"] }), _jsx("ul", { className: "work-detail-list", children: family.superseded.map((entry) => (_jsxs("li", { children: [_jsxs("span", { className: "work-request-heading", children: [_jsx(Text, { children: entry.title }), _jsx("span", { className: "work-row-state", "data-tone": statePresentation[entry.state].tone, children: statePresentation[entry.state].label })] }), _jsxs(Text, { tone: "secondary", variant: "meta", children: [entry.summary, ", ", formatTimestamp(entry.updatedAt)] }), blockersFor(entry).map((blocker) => (_jsxs(Text, { tone: "secondary", variant: "meta", children: ["Blocked since ", formatTimestamp(blocker.since), ": ", blocker.summary] }, `${blocker.since}-${blocker.summary}`))), entry.review === undefined || entry.review === null ? null : (_jsxs(Text, { tone: "secondary", variant: "meta", children: ["Review ", reviewPresentation[entry.review.state].label.toLowerCase(), entry.review.summary === null ? "" : `: ${entry.review.summary}`] }))] }, entry.id))) })] })] })), _jsxs("div", { className: "work-links", children: [goal.connectTarget === null ? (_jsx(Text, { tone: "secondary", children: "No exact Connect target recorded." })) : externalLinks === "disabled" ? (_jsx(Text, { tone: "secondary", variant: "meta", children: "Connect target recorded." })) : (_jsxs("a", { className: "work-connect-link", href: `${goal.connectTarget.url}&open=stage`, children: [observed?.stale === true ? "Find" : "Open", " ", agentName, " in Connect", _jsx(Icon, { decorative: true, name: "arrow-right", size: "small" })] })), goalApproval === null ? null : externalLinks === "disabled" ? (_jsxs(Text, { tone: "secondary", variant: "meta", children: ["Approval target recorded on ", goalApproval.host, "."] })) : (exactLink(goalApproval, `Open ${goalApproval.host} approval`)), closeControl] })] }));
317
369
  };
318
370
  const activityKindLabel = {
319
371
  note: "Note",
@@ -326,25 +378,19 @@ const activityKindLabel = {
326
378
  const snapshotFor = (snapshots, window) => snapshots[window];
327
379
  /** How many older activities the snapshot left out of this goal's timeline. */
328
380
  const activityOmittedFor = (snapshot, goal) => snapshot.activityOmitted?.[goal.id] ?? 0;
329
- /**
330
- * The board header's line, as whole sentences joined by a space, so each piece ends in exactly one period:
331
- * the window and its time, then what the live window could not show, then any finished or older goals it left out.
332
- */
333
- const headerSentences = (window, snapshot) => {
334
- const when = `${window === "now" ? "Live" : windowLabel[window]}, as of ${formatTimestamp(snapshot.asOf)}.`;
381
+ /** Header read time and live-read limitations. Omitted goal counts belong to the board. */
382
+ const headerSentences = (window, snapshot, host) => {
383
+ const when = `Durable goals${host === undefined ? "" : ` on ${host}`}, read ${formatClock(snapshot.observedAt)}.`;
335
384
  const live = window !== "now"
336
385
  ? []
337
386
  : snapshot.observed === undefined
338
387
  ? [
339
- "Live state not available: this hub sends no observed facts (its herdr-work predates the reconciler, or the overlay did not fit the response), so states are as recorded.",
340
- "Update herdr-work on the hub to see them."
388
+ "Live state not available: this hub sends no observed facts, so owner and pull request lines show only what each goal recorded. Update herdr-work on the hub to see them."
341
389
  ]
342
390
  : snapshot.observedOmitted === undefined
343
391
  ? []
344
392
  : [`Live state shown for the most recently updated goals; ${String(snapshot.observedOmitted)} left out.`];
345
- const finished = snapshot.finishedOmitted === undefined ? [] : [`${finishedNotShown(snapshot.finishedOmitted)}.`];
346
- const cut = snapshot.goalsOmitted === undefined ? [] : [`${goalsNotShown(snapshot.goalsOmitted)}.`];
347
- return [when, ...live, ...finished, ...cut];
393
+ return [when, ...live];
348
394
  };
349
395
  const familyForGoal = (snapshot, goalId) => (snapshot.families ?? []).find((group) => group.canonicalGoalId === goalId) ?? null;
350
396
  const familyLabelForGoal = (snapshot, goal) => {
@@ -358,8 +404,9 @@ const withFragment = (href, fragment) => {
358
404
  const fragmentIndex = href.indexOf("#");
359
405
  return `${fragmentIndex === -1 ? href : href.slice(0, fragmentIndex)}#${fragment}`;
360
406
  };
361
- export const WorkBoard = ({ decisions, externalLinks = "enabled", initialGoalId, initialWindow = "now", navigation, snapshots }) => {
362
- const [window, setWindow] = useState(initialWindow);
407
+ export const WorkBoard = ({ decisions, externalLinks = "enabled", host, initialGoalId, initialWindow = "now", navigation, snapshots }) => {
408
+ const [localWindow, setWindow] = useState(initialWindow);
409
+ const window = navigation === undefined ? localWindow : initialWindow;
363
410
  const snapshot = snapshotFor(snapshots, window);
364
411
  const directInitialGoal = snapshot.goals.find(({ id }) => id === initialGoalId);
365
412
  const boardNavigation = directInitialGoal === undefined ? decodeWorkBoardNavigationGoal(initialGoalId ?? null) : null;
@@ -372,15 +419,24 @@ export const WorkBoard = ({ decisions, externalLinks = "enabled", initialGoalId,
372
419
  ? requestedInitialSelectedGoal
373
420
  : undefined;
374
421
  const initialSelectedId = initialSelectedGoal?.id ?? null;
375
- const [selectedId, setSelectedId] = useState(initialSelectedId);
376
- const [detailsOpen, setDetailsOpen] = useState(initialSelectedGoal !== undefined &&
377
- (boardNavigation?.detailsOpen ?? (initialGoalId !== undefined && initialGoalId !== null)));
378
- const [statusFilter, setStatusFilter] = useState(initialStatusFilter);
379
- const [visibleGoalCount, setVisibleGoalCount] = useState(boardNavigation?.visibleGoalCount ?? initialVisibleGoalCount);
422
+ const initialDetailsOpen = initialSelectedGoal !== undefined &&
423
+ (boardNavigation?.detailsOpen ?? (initialGoalId !== undefined && initialGoalId !== null));
424
+ const [localSelectedId, setSelectedId] = useState(initialSelectedId);
425
+ const [localDetailsOpen, setDetailsOpen] = useState(initialDetailsOpen);
426
+ const [localStatusFilter, setStatusFilter] = useState(initialStatusFilter);
427
+ const [localVisibleGoalCount, setVisibleGoalCount] = useState(boardNavigation?.visibleGoalCount ?? initialVisibleGoalCount);
428
+ const selectedId = navigation === undefined ? localSelectedId : initialSelectedId;
429
+ const detailsOpen = navigation === undefined ? localDetailsOpen : initialDetailsOpen;
430
+ const statusFilter = navigation === undefined ? localStatusFilter : initialStatusFilter;
431
+ const visibleGoalCount = navigation === undefined ? localVisibleGoalCount : (boardNavigation?.visibleGoalCount ?? initialVisibleGoalCount);
380
432
  const detailsRef = useRef(null);
381
433
  const selectedLinkRowRef = useRef(null);
382
434
  const selectedRowRef = useRef(null);
435
+ const previousDetailsOpen = useRef(detailsOpen);
383
436
  const triage = workTriage(snapshot);
437
+ const finishedGoalCount = triage.rows.filter(({ displayState }) => displayState === "completed" || displayState === "deployed" || displayState === "abandoned").length;
438
+ const hasGoalOmissions = (snapshot.goalsOmitted ?? 0) > 0 || (snapshot.finishedOmitted ?? 0) > 0;
439
+ const finishedCount = finishedGoalCount > 0 || (snapshot.finishedOmitted ?? 0) > 0 ? (_jsxs(Text, { className: "work-finished-count", tone: "secondary", variant: "meta", children: [finishedGoalCount, " finished ", finishedGoalCount === 1 ? "goal" : "goals", (snapshot.finishedOmitted ?? 0) > 0 ? ` · ${snapshot.finishedOmitted} older not shown` : null] })) : null;
384
440
  // The overlay by goal, built once per snapshot: rows, captions and filters all read it.
385
441
  const overlay = new Map((snapshot.observed ?? []).map((entry) => [entry.goalId, entry]));
386
442
  const observedOf = (goal) => overlay.get(goal.id) ?? null;
@@ -388,9 +444,7 @@ export const WorkBoard = ({ decisions, externalLinks = "enabled", initialGoalId,
388
444
  // A historical window is the state as of its time; say so, never in the present tense.
389
445
  const tense = window === "now" ? "present" : "past";
390
446
  const sentence = workTriageSentence(triage.summary, tense);
391
- const heroFact = tense === "present"
392
- ? sentence
393
- : `As of ${formatTimestamp(snapshot.asOf)}, ${sentence.charAt(0).toLowerCase()}${sentence.slice(1)}`;
447
+ const heroFact = triage.summary._tag === "Attention" && triage.summary.blocked > 0 ? (_jsxs(_Fragment, { children: [sentence.slice(0, -`${triage.summary.blocked} blocked`.length), _jsx(HeroWord, { tone: "blocked", children: `${triage.summary.blocked} blocked` })] })) : tense === "past" && triage.summary._tag === "Attention" ? (_jsxs(_Fragment, { children: [sentence.split("needed you")[0], _jsx(HeroWord, { tone: "held", children: "needed you" })] })) : triage.summary._tag === "Empty" && tense === "past" ? ("Nothing needed you") : (sentence);
394
448
  const groupById = new Map(triage.rows.map((row) => [row.goal.id, row.group]));
395
449
  const ordered = triage.rows.map((row) => row.goal);
396
450
  // Filters match what each row shows: the observed state where there is one.
@@ -408,24 +462,42 @@ export const WorkBoard = ({ decisions, externalLinks = "enabled", initialGoalId,
408
462
  detailsRef.current?.querySelector("h2")?.focus();
409
463
  }, [detailsOpen, selectedId]);
410
464
  useEffect(() => {
465
+ const closing = previousDetailsOpen.current && !detailsOpen;
466
+ previousDetailsOpen.current = detailsOpen;
411
467
  if (navigation !== undefined &&
412
468
  !detailsOpen &&
413
469
  selectedId !== null &&
414
- document.location.hash === `#${selectedGoalFragment}`) {
470
+ (closing || document.location.hash === `#${selectedGoalFragment}`)) {
415
471
  selectedLinkRowRef.current?.focus();
416
472
  }
417
473
  }, [detailsOpen, navigation, selectedId]);
418
474
  useEffect(() => {
419
- if (selectedId === null || selectedFilteredGoalIndex !== -1)
475
+ if (navigation !== undefined || selectedId === null || selectedFilteredGoalIndex !== -1)
420
476
  return;
421
477
  setDetailsOpen(false);
422
478
  setSelectedId(null);
423
479
  setVisibleGoalCount(initialVisibleGoalCount);
424
- }, [selectedFilteredGoalIndex, selectedId]);
480
+ }, [navigation, selectedFilteredGoalIndex, selectedId]);
425
481
  const goalRow = (goal) => {
426
- const caption = rowCaption(goal, observedOf(goal), externalLinks === "enabled" ? decisions : undefined);
427
- const content = (_jsxs(_Fragment, { children: [_jsxs("span", { className: "work-row-title", children: [_jsxs("span", { className: "work-row-meta", children: [repositoryName(goal.repository.repository), ", ", _jsx("code", { children: goal.repository.branch })] }), goal.title] }), _jsx("span", { className: "work-row-state", "data-tone": displayPresentation[shownOf(goal)].tone, children: displayPresentation[shownOf(goal)].label }), _jsxs("span", { className: "work-row-caption", "data-blocking": caption.blocking, children: [caption.text, familyLabelForGoal(snapshot, goal) === null ? null : `, ${familyLabelForGoal(snapshot, goal)}`] })] }));
428
- return navigation === undefined ? (_jsx("button", { "aria-controls": detailsOpen && selected?.id === goal.id ? "work-goal-details" : undefined, "aria-expanded": detailsOpen && selected?.id === goal.id, "aria-pressed": selected?.id === goal.id, className: "work-board-row", id: selected?.id === goal.id ? selectedGoalFragment : undefined, onClick: () => {
482
+ const observed = observedOf(goal);
483
+ const shown = shownOf(goal);
484
+ const caption = rowCaption(goal, observed, externalLinks === "enabled" && window === "now" ? decisions : undefined);
485
+ const open = requestsFor(goal).filter((request) => request.state === "open");
486
+ const host = observed?.agent?.fact.host ?? goal.connectTarget?.host ?? goal.agentHierarchy?.agent.host;
487
+ const agentName = goal.agentHierarchy?.agent.name ?? goal.owner.name;
488
+ const pr = observed?.pullRequest?.fact;
489
+ const terminal = shown === "completed" || shown === "deployed" || shown === "abandoned";
490
+ const stage = pr === undefined
491
+ ? `Stage: ${deliveryLabel[goal.delivery]}`
492
+ : `PR #${pr.pullRequest} ${pullRequestStateLabel[pr.state]}, ${checksLabel[pr.checks]}${pr.review === "not_requested" ? "" : ` · Review ${reviewPresentation[pr.review].label.toLowerCase()}`}`;
493
+ const metadata = goal.owner.name === "Unassigned"
494
+ ? `Unassigned · ${goal.repository.repository}`
495
+ : terminal
496
+ ? `${agentName} · ${shown === "abandoned" ? "" : goal.delivery === "merged" || pr?.state === "merged" ? "Merged · " : "Done · "}${displayPresentation[shown].label} ${ageOf(pr?.closedAt ?? goal.updatedAt, snapshot.asOf)}`
497
+ : `${agentName}${host === undefined ? "" : ` on ${host}`} · ${stage}${blockersFor(goal).length === 0 || open.length > 0 ? "" : ` · ${blockersFor(goal)[0]?.summary ?? "Blocked"}`}`;
498
+ const hasCaption = open.length > 0 || observed?.stale === true || observed?.unknown != null;
499
+ const content = (_jsxs(_Fragment, { children: [_jsx("span", { className: "work-row-title", children: goal.title }), _jsx(StateLabel, { className: "work-row-state", icon: stateIcon[displayPresentation[shown].tone], label: displayPresentation[shown].label, size: "compact", tone: displayPresentation[shown].tone }), _jsxs("span", { className: "work-row-meta", children: [metadata, familyLabelForGoal(snapshot, goal) === null ? null : ` · ${familyLabelForGoal(snapshot, goal)}`] }), hasCaption ? (_jsx("span", { className: "work-row-caption", "data-blocking": caption.blocking, children: open.length === 0 ? (caption.text) : (_jsxs(_Fragment, { children: [_jsxs("span", { className: "work-request-line", children: [_jsx(StateLabel, { className: "work-row-state", icon: "clock", label: "Open", size: "compact", tone: "caution" }), " ", _jsx("span", { className: "work-request-title", children: caption.text })] }), " ", _jsx("span", { className: "work-request-age", children: window === "now" ? ageOf(open[0]?.requestedAt ?? snapshot.asOf, snapshot.asOf) : "was open then" })] })) })) : null] }));
500
+ const control = navigation === undefined ? (_jsx("button", { "aria-controls": detailsOpen && selected?.id === goal.id ? "work-goal-details" : undefined, "aria-expanded": detailsOpen && selected?.id === goal.id, "aria-pressed": selected?.id === goal.id, className: "work-board-row", id: selected?.id === goal.id ? selectedGoalFragment : undefined, onClick: () => {
429
501
  setDetailsOpen(true);
430
502
  setSelectedId(goal.id);
431
503
  }, ref: selected?.id === goal.id ? selectedRowRef : undefined, type: "button", children: content })) : (_jsx("a", { "aria-current": selected?.id === goal.id ? "true" : undefined, className: "work-board-row", href: navigation({
@@ -439,6 +511,7 @@ export const WorkBoard = ({ decisions, externalLinks = "enabled", initialGoalId,
439
511
  }),
440
512
  window
441
513
  }), id: selected?.id === goal.id ? selectedGoalFragment : undefined, ref: selected?.id === goal.id ? selectedLinkRowRef : undefined, children: content }));
514
+ return control;
442
515
  };
443
516
  const timeTravel = (_jsx("div", { "aria-label": "Choose work snapshot", className: "work-time-controls", role: "group", children: windows.map((option) => {
444
517
  if (navigation === undefined) {
@@ -472,12 +545,12 @@ export const WorkBoard = ({ decisions, externalLinks = "enabled", initialGoalId,
472
545
  }) }));
473
546
  const statusFilterControls = (_jsx("div", { "aria-label": "Filter goals by status", className: "work-status-filters", role: "group", children: statusFilters.map((state) => {
474
547
  const label = state === "all" ? "All" : statePresentation[state].label;
475
- return navigation === undefined ? (_jsx("button", { "aria-pressed": statusFilter === state, className: "work-status-filter", onClick: () => {
548
+ return navigation === undefined ? (_jsx("button", { "aria-pressed": statusFilter === state, className: "work-status-filter", onFocus: ({ currentTarget }) => currentTarget.scrollIntoView({ block: "nearest", inline: "nearest" }), onClick: () => {
476
549
  setDetailsOpen(false);
477
550
  setSelectedId(null);
478
551
  setStatusFilter(state);
479
552
  setVisibleGoalCount(initialVisibleGoalCount);
480
- }, type: "button", children: label }, state)) : (_jsx("a", { "aria-current": statusFilter === state ? "page" : undefined, className: "work-status-filter", href: navigation({
553
+ }, type: "button", children: label }, state)) : (_jsx("a", { "aria-current": statusFilter === state ? "page" : undefined, className: "work-status-filter", onFocus: ({ currentTarget }) => currentTarget.scrollIntoView({ block: "nearest", inline: "nearest" }), href: navigation({
481
554
  goalId: encodeWorkBoardNavigationGoal({
482
555
  detailsOpen: false,
483
556
  goalId: null,
@@ -487,7 +560,35 @@ export const WorkBoard = ({ decisions, externalLinks = "enabled", initialGoalId,
487
560
  window
488
561
  }), children: label }, state));
489
562
  }) }));
490
- return (_jsxs("section", { className: "work-page", "aria-labelledby": "work-board-title", children: [_jsxs("header", { className: "work-page-intro", children: [_jsx(Text, { as: "h1", id: "work-board-title", variant: "card-title", children: "Work" }), _jsx(Text, { tone: "secondary", variant: "meta", children: headerSentences(window, snapshot).join(" ") })] }), _jsx(Hero, { caption: summaryCaption(triage.summary, tense), fact: heroFact, label: "Work summary" }), timeTravel, snapshot.goals.length === 0 ? (_jsx(Region, { title: "Goals", children: _jsx(Text, { tone: "secondary", children: window === "now" ? (_jsxs(_Fragment, { children: ["No goals yet. Delegate work to an agent with", " ", _jsx("code", { children: "fleetctl submit HOST agent.delegate work REPOSITORY PROMPT" }), " (HOST is a name from", " ", _jsx("code", { children: "fleetctl hosts" }), "); its goal appears here once the hub admits it."] })) : ("No goals at this checkpoint.") }) })) : (_jsxs("div", { className: "work-board-layout", "data-has-detail": selected !== null && detailsOpen, children: [_jsxs(Region, { actions: statusFilterControls, className: "work-board-list", count: filteredGoals.length, title: "Goals", children: [_jsxs(Text, { "aria-live": "polite", tone: "secondary", variant: "meta", children: ["Showing ", visibleGoals.length, " of ", filteredGoals.length, " goals"] }), filteredGoals.length === 0 ? _jsx(Text, { tone: "secondary", children: "No goals match this status." }) : null, visibleGroups.map(({ goals, group }) => (_jsxs("section", { "aria-labelledby": `work-group-${group}`, className: "work-group", children: [_jsxs("h3", { className: "work-group-title", id: `work-group-${group}`, children: [workTriageGroupTitle[group], " ", _jsxs("span", { className: "work-group-count", children: ["(", goals.length, ")"] })] }), _jsx("ul", { className: "work-rows", children: goals.map((goal) => (_jsx("li", { children: goalRow(goal) }, goal.id))) })] }, group))), visibleGoals.length < filteredGoals.length ? (navigation === undefined ? (_jsx(Button, { onClick: () => setVisibleGoalCount((count) => Math.min(count + initialVisibleGoalCount, filteredGoals.length)), children: "Load 10 more" })) : (_jsx("a", { className: "work-load-more-link", href: navigation({
563
+ const closeControl = (label) => navigation === undefined ? (_jsx(Button, { onClick: () => {
564
+ setDetailsOpen(false);
565
+ (selectedRowRef.current ?? selectedLinkRowRef.current)?.focus();
566
+ }, className: label === "Close" ? "work-close-heading" : undefined, variant: label === "Close" ? "quiet" : "secondary", children: label })) : (_jsx("a", { className: `work-exact-link work-close-control${label === "Close" ? " work-close-heading" : ""}`, href: withFragment(navigation({
567
+ goalId: encodeWorkBoardNavigationGoal({
568
+ detailsOpen: false,
569
+ goalId: selectedId,
570
+ statusFilter,
571
+ visibleGoalCount
572
+ }),
573
+ window
574
+ }), selectedGoalFragment), children: label }));
575
+ return (_jsxs("section", { className: "work-page", "aria-labelledby": "work-board-title", children: [_jsxs("header", { className: "work-page-intro", children: [_jsx(Text, { as: "h1", id: "work-board-title", variant: "section-title", children: "Work" }), _jsx(Text, { tone: "secondary", variant: "meta", children: headerSentences(window, snapshot, host)[0] })] }), headerSentences(window, snapshot, host)
576
+ .slice(1)
577
+ .map((sentence) => (_jsxs("p", { className: "work-note work-overlay-note", "data-tone": "held", children: [_jsx(Icon, { decorative: true, name: "clock", size: "small" }), _jsx("span", { children: sentence })] }, sentence))), externalLinks === "disabled" ? (_jsx("p", { className: "work-note", children: "Read-only on the local network. Requests are decided on the hub." })) : null, window === "now" ? null : (_jsxs("div", { className: "work-note work-history-note", children: [_jsxs("span", { children: ["Work as it was ", windowLabel[window].toLowerCase(), ", ", formatTimestamp(snapshot.asOf), ". Decisions are off in the past."] }), navigation === undefined ? (_jsx(Button, { onClick: () => {
578
+ setWindow("now");
579
+ setDetailsOpen(false);
580
+ setSelectedId(null);
581
+ setStatusFilter("all");
582
+ setVisibleGoalCount(initialVisibleGoalCount);
583
+ }, variant: "secondary", children: "Back to now" })) : (_jsx("a", { className: "work-exact-link", href: navigation({ goalId: null, window: "now" }), children: "Back to now" }))] })), snapshot.goals.length === 0 && (window === "now" || hasGoalOmissions) ? null : (_jsx(Hero, { caption: summaryCaption(triage.summary, tense, snapshot), fact: heroFact, label: "Work summary", size: "heading" })), _jsxs("div", { className: "work-board-controls", children: [timeTravel, statusFilterControls] }), snapshot.goals.length === 0 ? (_jsx(Region, { actions: (snapshot.goalsOmitted ?? 0) > 0 ? (_jsxs(Text, { "aria-live": "polite", tone: "secondary", variant: "meta", children: ["Showing 0 of ", snapshot.goalsOmitted, " goals"] })) : undefined, className: "work-empty-board", count: snapshot.goalsOmitted ?? 0, title: "Goals", children: _jsxs("div", { className: "work-empty-copy", children: [hasGoalOmissions ? (_jsx(Text, { as: "strong", children: "No goals in this read." })) : window === "now" ? (_jsx(Text, { as: "strong", children: "No goals yet." })) : null, hasGoalOmissions ? null : (_jsx(Text, { tone: "secondary", children: window === "now" ? (_jsxs(_Fragment, { children: ["Delegate work to an agent with", " ", _jsx("code", { children: "fleetctl submit HOST agent.delegate work REPOSITORY PROMPT" }), " (HOST is a name from", " ", _jsx("code", { children: "fleetctl hosts" }), "); its goal appears here once the hub admits it."] })) : ("No goals at this checkpoint.") })), finishedCount] }) })) : (_jsxs("div", { className: "work-board-layout", "data-has-detail": selected !== null && detailsOpen, children: [selected === null || !detailsOpen ? null : (_jsx(Region, { actions: closeControl("Close"), "aria-label": "Goal details", className: "work-inspector", headingId: "work-goal-details-title", id: "work-goal-details", ref: detailsRef, title: "Goal details", children: _jsx(GoalDetail, { closeControl: closeControl("Close details"), decisions: snapshot.window === "now" ? decisions : undefined, externalLinks: externalLinks, goal: selected, snapshot: snapshot }) })), _jsxs(Region, { actions: filteredGoals.length === 0 ? undefined : (_jsxs(Text, { "aria-live": "polite", tone: "secondary", variant: "meta", children: ["Showing ", visibleGoals.length, " of", " ", filteredGoals.length + (statusFilter === "all" ? (snapshot.goalsOmitted ?? 0) : 0), " goals"] })), className: "work-board-list", count: statusFilter === "all"
584
+ ? filteredGoals.length + (snapshot.goalsOmitted ?? 0)
585
+ : filteredGoals.length === 0
586
+ ? `0 of ${snapshot.goals.length + (snapshot.goalsOmitted ?? 0)}`
587
+ : filteredGoals.length, title: "Goals", children: [filteredGoals.length === 0 ? (_jsxs("div", { className: "work-filter-empty", children: [_jsx(Text, { tone: "secondary", children: "No goals match this status." }), navigation === undefined ? (_jsx(Button, { onClick: () => setStatusFilter("all"), variant: "secondary", children: "Show all" })) : (_jsx("a", { className: "work-exact-link", href: navigation({ goalId: null, window }), children: "Show all" }))] })) : null, visibleGroups.map(({ goals, group }) => (_jsxs("section", { "aria-labelledby": `work-group-${group}`, className: "work-group", children: [_jsxs("h3", { className: "work-group-title", id: `work-group-${group}`, children: [group === "planned"
588
+ ? "Planned"
589
+ : group === "needs-you" && tense === "past"
590
+ ? "Needed you"
591
+ : workTriageGroupTitle[group], " ", _jsxs("span", { className: "work-group-count", children: ["(", goals.length, ")"] })] }), _jsx("ul", { className: "work-rows", children: goals.map((goal) => (_jsx("li", { children: goalRow(goal) }, goal.id))) })] }, group))), filteredGoals.length > 0 ? finishedCount : null, visibleGoals.length < filteredGoals.length ? (navigation === undefined ? (_jsx(Button, { onClick: () => setVisibleGoalCount((count) => Math.min(count + initialVisibleGoalCount, filteredGoals.length)), children: "Load 10 more" })) : (_jsx("a", { className: "work-load-more-link", href: navigation({
491
592
  goalId: encodeWorkBoardNavigationGoal({
492
593
  detailsOpen,
493
594
  goalId: selectedId,
@@ -495,18 +596,6 @@ export const WorkBoard = ({ decisions, externalLinks = "enabled", initialGoalId,
495
596
  visibleGoalCount: Math.min(visibleGoalCount + initialVisibleGoalCount, filteredGoals.length)
496
597
  }),
497
598
  window
498
- }), children: "Load 10 more" }))) : null] }), selected === null || !detailsOpen ? null : (_jsx(Region, { actions: navigation === undefined ? (_jsx(Button, { onClick: () => {
499
- setDetailsOpen(false);
500
- const selectedRow = selectedRowRef.current ?? selectedLinkRowRef.current;
501
- selectedRow?.focus();
502
- }, variant: "secondary", children: "Close details" })) : (_jsx("a", { className: "work-exact-link", href: withFragment(navigation({
503
- goalId: encodeWorkBoardNavigationGoal({
504
- detailsOpen: false,
505
- goalId: selectedId,
506
- statusFilter,
507
- visibleGoalCount
508
- }),
509
- window
510
- }), selectedGoalFragment), children: "Close details" })), "aria-label": "Goal details", className: "work-inspector", headingId: "work-goal-details-title", id: "work-goal-details", ref: detailsRef, title: selected.title, children: _jsx(GoalDetail, { decisions: decisions, externalLinks: externalLinks, goal: selected, snapshot: snapshot }) }))] }))] }));
599
+ }), children: "Load 10 more" }))) : null] })] }))] }));
511
600
  };
512
601
  //# sourceMappingURL=view.js.map