cortena-ui 1.13.0 → 1.14.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.
Files changed (48) hide show
  1. package/CHANGELOG.md +36 -0
  2. package/README.md +88 -0
  3. package/dist/a2ui/views.js +1 -1
  4. package/dist/components/accordion.js +1 -1
  5. package/dist/components/actor.d.ts +103 -0
  6. package/dist/components/actor.js +175 -0
  7. package/dist/components/actor.js.map +1 -0
  8. package/dist/components/admin-permissions/role-assignment.js +1 -1
  9. package/dist/components/agent-chat-popup.js +1 -1
  10. package/dist/components/agent-chat.js +1 -1
  11. package/dist/components/app-shell.js +1 -1
  12. package/dist/components/avatar.js +1 -1
  13. package/dist/components/badge.d.ts +1 -1
  14. package/dist/components/breadcrumb.js +1 -1
  15. package/dist/components/button.d.ts +1 -1
  16. package/dist/components/calendar.js +1 -1
  17. package/dist/components/checkbox.js +1 -1
  18. package/dist/components/chip.d.ts +1 -1
  19. package/dist/components/combobox.js +1 -1
  20. package/dist/components/command.js +1 -1
  21. package/dist/components/data-table/data-table.js +1 -1
  22. package/dist/components/data-table/index.d.ts +2 -1
  23. package/dist/components/data-table/parts.js +1 -1
  24. package/dist/components/data-table/system-columns.d.ts +46 -0
  25. package/dist/components/data-table/system-columns.js +47 -2
  26. package/dist/components/data-table/system-columns.js.map +1 -1
  27. package/dist/components/date-field.js +1 -1
  28. package/dist/components/date-picker.js +1 -1
  29. package/dist/components/dropdown-menu.js +1 -1
  30. package/dist/components/dropzone.js +1 -1
  31. package/dist/components/error-banner.js +1 -1
  32. package/dist/components/help-panel.js +1 -1
  33. package/dist/components/markdown.js +1 -1
  34. package/dist/components/rich-text-editor/toolbar.js +1 -1
  35. package/dist/components/select.js +1 -1
  36. package/dist/components/sortable-list.js +1 -1
  37. package/dist/components/toast.js +1 -1
  38. package/dist/core.d.ts +2 -1
  39. package/dist/core.js +4 -3
  40. package/dist/data-table.d.ts +2 -1
  41. package/dist/data-table.js +2 -1
  42. package/dist/index.d.ts +3 -1
  43. package/dist/index.js +5 -3
  44. package/package.json +1 -1
  45. package/src/components/actor.tsx +297 -0
  46. package/src/components/data-table/index.tsx +2 -0
  47. package/src/components/data-table/system-columns.tsx +73 -0
  48. package/src/entries/core.ts +2 -0
package/CHANGELOG.md CHANGED
@@ -3,6 +3,42 @@
3
3
  Notable changes per release. Versions before 1.6.0 are recorded in the git log
4
4
  and in `../../CONSUMING.md`; this file starts where the changelog does.
5
5
 
6
+ ## 1.14.0
7
+
8
+ ### Added
9
+
10
+ - **`Actor` — one component for "who did this"** (DESIGN-120). The protocol
11
+ records the acting user and `via` on every write (§20, audit rule P-26) and
12
+ expects a trail to read "Name (Agent)". Seven extensions were each about to
13
+ format that themselves: Tasks prints the stored string raw as
14
+ `Amit (claude-code)`, Assure keeps a rich JSON actor and shows none of it.
15
+ `Actor` takes the resolved actor — `{ userId, displayName, via, avatarUrl,
16
+ at, surface }` — and **has no string input**: there is no `label`, `text` or
17
+ `children` prop, because a consumer that can pass a preformatted label is
18
+ how the inconsistency arrived. The rules it encodes: a direct action is the
19
+ name alone; an agent action is the name and a fixed ` (Agent)` in the
20
+ caption/muted style, never the agent's technical id or session; `system` is
21
+ `System`; a user with no stored display name is `Someone`, never a raw id.
22
+ Three sizes — `inline` for a sentence, `cell` for a list, `head` for a feed
23
+ row or comment with avatar and time — and a hover showing surface and time
24
+ wherever either is given. Times are `en-GB` by default and hand-written, the
25
+ same way `DateField` formats dates, so a trail does not read differently on
26
+ every machine; `locale` overrides it. `title` and `dangerouslySetInnerHTML`
27
+ are omitted from the props alongside `children`. The hover is not the only
28
+ way to reach what it says: the same text is in the DOM visually hidden, in
29
+ document order after the name, so a screen reader reads it and a `gridcell`
30
+ or link around the actor takes it into its own name. The avatar's initials
31
+ and the visible timestamp are `aria-hidden`, so neither is announced twice.
32
+ - **`actorColumn()`** in `cortena-ui/data-table`, so a list needs no custom
33
+ cell. It is an accessor column over the label rather than a display column,
34
+ so the value the table sorts, filters, searches and exports is the string
35
+ the cell paints. The header defaults to `By`.
36
+ - **`actorLabel`, `actorName`, `actorTime`** and the three wordings
37
+ (`ACTOR_AGENT_SUFFIX`, `ACTOR_SYSTEM_NAME`, `ACTOR_UNKNOWN_NAME`) are
38
+ exported for the places a React node cannot go — an `aria-label`, a CSV
39
+ cell, a `title`. `Actor` and its types come from `cortena-ui/core` and the
40
+ root barrel; `actorColumn` from `cortena-ui/data-table`.
41
+
6
42
  ## 1.13.0
7
43
 
8
44
  ### Added
package/README.md CHANGED
@@ -251,6 +251,94 @@ move the theme/help cluster **and** whatever `agentSlot` renders, which is what
251
251
  the old per-extension `className="bottom-22 lg:bottom-6"` workaround could not
252
252
  do.
253
253
 
254
+ ## Attribution: who did this
255
+
256
+ `Actor` is the only thing in the fleet that turns a recorded actor into words
257
+ (DESIGN-120, protocol §20 / audit rule P-26). Every extension stores the same
258
+ two columns on every write — the acting user and `via` — and every screen that
259
+ shows a trail has to answer the same question: did a person do this, or did
260
+ their agent? Seven extensions answering it themselves is seven answers, and
261
+ the one that prints the stored string raw shows `Amit (claude-code)`, which
262
+ names a CLI and says nothing about whether a human was in the loop.
263
+
264
+ ```tsx
265
+ <p>
266
+ <Actor userId={row.actorUserId} displayName={row.actorName} via={row.actorVia} /> changed the status
267
+ </p>
268
+ ```
269
+
270
+ **The input is the actor, never a label.** There is no `label`, `text` or
271
+ `children` prop and there will not be one: a consumer that can pass a
272
+ preformatted string eventually passes a differently formatted one, which is
273
+ exactly how the inconsistency arrived. The rules live in the component:
274
+
275
+ | `via` | `displayName` | reads as |
276
+ | --- | --- | --- |
277
+ | `user` | "Amit Sharma" | Amit Sharma |
278
+ | `user` | missing or blank | Someone |
279
+ | `agent` | "Amit Sharma" | Amit Sharma **(Agent)** |
280
+ | `agent` | missing or blank | Someone **(Agent)** |
281
+ | `system` | anything | System |
282
+
283
+ The suffix is fixed and caption-sized in `--ds-muted-foreground`. It is never
284
+ the agent's technical id or session — which agent ran is an audit question and
285
+ `actorAgentId` answers it; on screen the only thing that changes the reader's
286
+ next action is *that* an agent acted. An unknown or deleted user is `Someone`
287
+ and never the id: the server-side `actorLabel` in `packages/shared` falls back
288
+ to the id because a log line has no other anchor, and a screen does.
289
+
290
+ Three sizes. `inline` is a run of text in a sentence. `cell` is avatar-less
291
+ and one line, and truncates on its own inline-block box, inside the `td` that
292
+ truncates around it. `head` is avatar, name and time, for a feed row or a
293
+ comment header — `avatar={false}` keeps the stacked shape without the picture,
294
+ for a comment thread that has already shown it once. `at` and `surface` show on
295
+ hover at every size.
296
+
297
+ Times format as `14 Sep 2026, 19:32`: `en-GB` by default and hand-written, the
298
+ same way `DateField` does it, so one date is not spelled two ways on two
299
+ screens and a trail does not read differently on every machine. The zone stays
300
+ local, and `locale` overrides the format.
301
+
302
+ `title` and `dangerouslySetInnerHTML` are omitted from the props alongside
303
+ `children`, for the same reason: every route by which a caller could put its
304
+ own words on screen is closed.
305
+
306
+ The hover is not the only way to reach what it says. The same text is also in
307
+ the DOM, visually hidden (`sr-only`), in document order right after the name,
308
+ so a screen reader reads it where it is relevant and any ancestor whose role
309
+ takes its name from its contents — the `gridcell` a DataTable cell sits in, a
310
+ link, a button — includes it in that name. The trigger stays a plain `span`:
311
+ no tab stop, because making every actor in a 200-row grid focusable would
312
+ wreck keyboard navigation of it, and no `aria-label`, because a `role=generic`
313
+ element's label is dropped rather than announced. The avatar's initials and
314
+ `head`'s visible timestamp are `aria-hidden`, so neither is read twice.
315
+
316
+ A list uses the column helper rather than a custom cell:
317
+
318
+ ```tsx
319
+ const helper = createColumnHelper<AuditRow>();
320
+ const columns = helper.columns([
321
+ helper.accessor("action", { header: "Action", meta: { fill: true } }),
322
+ actorColumn(helper, {
323
+ actor: (row) => ({
324
+ userId: row.actorUserId,
325
+ displayName: row.actorName,
326
+ via: row.actorVia,
327
+ at: row.at,
328
+ surface: row.surface,
329
+ }),
330
+ }),
331
+ ]);
332
+ ```
333
+
334
+ It is an accessor column over `actorLabel`, not a display column, so the value
335
+ the table sorts, filters, searches and exports is the same string the cell
336
+ paints — a table sorted by **By** lands where the reader expects, and a CSV of
337
+ it reads like the screen. The header defaults to `By`.
338
+
339
+ `actorLabel`, `actorName` and `actorTime` are exported for the places a React
340
+ node cannot go: an `aria-label`, a CSV cell, a `title`.
341
+
254
342
  ## The agent pop-up
255
343
 
256
344
  `AgentChatPopup` is the extension's own Cortena Agent, in the corner of every
@@ -23,8 +23,8 @@ import { DateField, formatDateISO, parseDateISO } from "../components/date-field
23
23
  import { DataTable } from "../components/data-table/data-table.js";
24
24
  import { Chart } from "../components/chart/chart.js";
25
25
  import { Markdown } from "../components/markdown.js";
26
- import { AlertTriangle, CheckCircle2, Info, OctagonAlert, Terminal } from "lucide-react";
27
26
  import { jsx, jsxs } from "react/jsx-runtime";
27
+ import { AlertTriangle, CheckCircle2, Info, OctagonAlert, Terminal } from "lucide-react";
28
28
  import * as React from "react";
29
29
  //#region src/a2ui/views.tsx
30
30
  /**
@@ -1,9 +1,9 @@
1
1
  "use client";
2
2
  "use client";
3
3
  import { cn } from "../lib/cn.js";
4
+ import { jsx, jsxs } from "react/jsx-runtime";
4
5
  import { Accordion } from "@base-ui/react/accordion";
5
6
  import { ChevronDown } from "lucide-react";
6
- import { jsx, jsxs } from "react/jsx-runtime";
7
7
  //#region src/components/accordion.tsx
8
8
  /**
9
9
  * Accordion.
@@ -0,0 +1,103 @@
1
+ "use client";
2
+ import * as React from "react";
3
+ //#region src/components/actor.d.ts
4
+ /**
5
+ * Who acted, on one screen, in one component (DESIGN-120, protocol §20 /
6
+ * audit rule P-26).
7
+ *
8
+ * Every extension records the same two things on every write — the acting
9
+ * user and `via` — and every screen that shows a trail has to answer the same
10
+ * question: did a person do this, or did their agent? Seven extensions
11
+ * formatting that themselves is seven answers, and the one that prints the
12
+ * stored string raw shows `Amit (claude-code)`, which tells an operator the
13
+ * name of a CLI and not whether a human was in the loop.
14
+ *
15
+ * So the input is the resolved actor, never a label. There is deliberately no
16
+ * `label`, `text` or `children` prop: a consumer that could pass a string
17
+ * would eventually pass a differently formatted one, which is exactly how the
18
+ * inconsistency arrived. The rules below live here and nowhere else.
19
+ */
20
+ /**
21
+ * How the principal acted. `user` and `agent` are the protocol's two values
22
+ * (packages/shared `ActorVia`); `system` is the display-only third for a write
23
+ * the platform made on nobody's behalf — a retention sweep, a migration.
24
+ */
25
+ export type ActorVia = "user" | "agent" | "system";
26
+ /**
27
+ * inline — text only, sits inside a sentence: "Amit (Agent) changed the status".
28
+ * cell — a DataTable cell: avatar-less, one line, truncates.
29
+ * head — avatar, name and time, for a feed row or a comment header.
30
+ */
31
+ export type ActorSize = "inline" | "cell" | "head";
32
+ /**
33
+ * The suffix, fixed, in one place, so no screen can invent its own. It is
34
+ * never the agent's technical id or session: which agent ran is an audit
35
+ * question, and the audit table has `actorAgentId` for it. On screen the only
36
+ * thing that changes the reader's next action is *that* an agent acted.
37
+ */
38
+ export declare const ACTOR_AGENT_SUFFIX = "(Agent)";
39
+ /** What `via: "system"` reads as, whatever name came with the row. */
40
+ export declare const ACTOR_SYSTEM_NAME = "System";
41
+ /**
42
+ * An unknown or deleted user. Never the id: `usr_9f2c…` in a feed reads as
43
+ * noise to everyone who is not debugging, and the ids are in the audit table
44
+ * for the one person who is. The server-side `actorLabel` falls back to the
45
+ * id because a log line has no other anchor; a screen does.
46
+ */
47
+ export declare const ACTOR_UNKNOWN_NAME = "Someone";
48
+ /** What the shared actor resolver produces and what the list APIs return. */
49
+ export interface ActorValue {
50
+ /** The acting principal. Null for a system write, or a row that lost its user. */
51
+ userId: string | null;
52
+ /** The stored display name. Absent or empty means unknown or deleted. */
53
+ displayName?: string | null;
54
+ via: ActorVia;
55
+ avatarUrl?: string;
56
+ /** When it happened. Shown in `head` and in the hover for every size. */
57
+ at?: string | Date;
58
+ /** Where it happened — "Web", "MCP", "Tasks › Sprint 4". Hover only. */
59
+ surface?: string;
60
+ }
61
+ /** The name alone, before the suffix. */
62
+ export declare function actorName(actor: Pick<ActorValue, "displayName" | "via">): string;
63
+ /**
64
+ * The full label as a string: `"Amit"`, `"Amit (Agent)"`, `"System"`,
65
+ * `"Someone (Agent)"`.
66
+ *
67
+ * Exported for the places a React node cannot go — an `aria-label`, a CSV
68
+ * export, a `title` — and used by `actorColumn` as the column's sort and
69
+ * filter value, so a table sorts by what the reader sees.
70
+ */
71
+ export declare function actorLabel(actor: Pick<ActorValue, "displayName" | "via">): string;
72
+ /**
73
+ * `5 Jan 2026, 14:32` for en-GB; other locales via `Intl.DateTimeFormat`.
74
+ *
75
+ * `en-GB` by default and hand-written, exactly as `date-field.tsx` does it,
76
+ * for the same two reasons. The machine's own locale would render the same
77
+ * trail differently on every machine — the drift this component exists to
78
+ * remove — and `Intl`'s `dateStyle: "medium"` says "14 Sept 2026" where
79
+ * `DateField` says "14 Sep 2026", so two screens in one product would spell
80
+ * one date two ways. The zone stays local: what time it was *for the reader*
81
+ * is the question a feed answers.
82
+ */
83
+ export declare function actorTime(at: string | Date, locale?: string): string | undefined;
84
+ export interface ActorProps extends ActorValue, Omit<React.ComponentProps<"span">, "children" | "color" | "title" | "dangerouslySetInnerHTML"> {
85
+ /** @default "inline" */
86
+ size?: ActorSize;
87
+ /** Override the per-size default: off for `inline` and `cell`, on for `head`. */
88
+ avatar?: boolean;
89
+ /** Formatting locale for `at`. @default "en-GB" */
90
+ locale?: string;
91
+ }
92
+ /**
93
+ * Actor — "Amit", "Amit (Agent)", "System", "Someone".
94
+ *
95
+ * @example
96
+ * <p>
97
+ * <Actor userId={r.actorUserId} displayName={r.actorName} via={r.actorVia} /> changed the status
98
+ * </p>
99
+ */
100
+ declare function Actor({ userId, displayName, via, avatarUrl, at, surface, size, avatar, locale, className, ...props }: ActorProps): React.JSX.Element;
101
+ //#endregion
102
+ export { Actor };
103
+ //# sourceMappingURL=actor.d.ts.map
@@ -0,0 +1,175 @@
1
+ "use client";
2
+ "use client";
3
+ import { cn } from "../lib/cn.js";
4
+ import { Avatar, AvatarFallback, AvatarImage } from "./avatar.js";
5
+ import { Tooltip, TooltipContent, TooltipTrigger } from "./tooltip.js";
6
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
7
+ //#region src/components/actor.tsx
8
+ /**
9
+ * The suffix, fixed, in one place, so no screen can invent its own. It is
10
+ * never the agent's technical id or session: which agent ran is an audit
11
+ * question, and the audit table has `actorAgentId` for it. On screen the only
12
+ * thing that changes the reader's next action is *that* an agent acted.
13
+ */
14
+ const ACTOR_AGENT_SUFFIX = "(Agent)";
15
+ /** What `via: "system"` reads as, whatever name came with the row. */
16
+ const ACTOR_SYSTEM_NAME = "System";
17
+ /**
18
+ * An unknown or deleted user. Never the id: `usr_9f2c…` in a feed reads as
19
+ * noise to everyone who is not debugging, and the ids are in the audit table
20
+ * for the one person who is. The server-side `actorLabel` falls back to the
21
+ * id because a log line has no other anchor; a screen does.
22
+ */
23
+ const ACTOR_UNKNOWN_NAME = "Someone";
24
+ /** The name alone, before the suffix. */
25
+ function actorName(actor) {
26
+ if (actor.via === "system") return ACTOR_SYSTEM_NAME;
27
+ const name = actor.displayName?.trim();
28
+ return name ? name : ACTOR_UNKNOWN_NAME;
29
+ }
30
+ /**
31
+ * The full label as a string: `"Amit"`, `"Amit (Agent)"`, `"System"`,
32
+ * `"Someone (Agent)"`.
33
+ *
34
+ * Exported for the places a React node cannot go — an `aria-label`, a CSV
35
+ * export, a `title` — and used by `actorColumn` as the column's sort and
36
+ * filter value, so a table sorts by what the reader sees.
37
+ */
38
+ function actorLabel(actor) {
39
+ const name = actorName(actor);
40
+ return actor.via === "agent" ? `${name} ${ACTOR_AGENT_SUFFIX}` : name;
41
+ }
42
+ /** A `Date` from either accepted form, or null when it does not parse. */
43
+ function toDate(at) {
44
+ const date = at instanceof Date ? at : new Date(at);
45
+ return Number.isNaN(date.getTime()) ? null : date;
46
+ }
47
+ const MONTHS_SHORT = [
48
+ "Jan",
49
+ "Feb",
50
+ "Mar",
51
+ "Apr",
52
+ "May",
53
+ "Jun",
54
+ "Jul",
55
+ "Aug",
56
+ "Sep",
57
+ "Oct",
58
+ "Nov",
59
+ "Dec"
60
+ ];
61
+ const pad = (n) => String(n).padStart(2, "0");
62
+ const isEn = (locale) => /^en(-GB)?$/i.test(locale);
63
+ /**
64
+ * `5 Jan 2026, 14:32` for en-GB; other locales via `Intl.DateTimeFormat`.
65
+ *
66
+ * `en-GB` by default and hand-written, exactly as `date-field.tsx` does it,
67
+ * for the same two reasons. The machine's own locale would render the same
68
+ * trail differently on every machine — the drift this component exists to
69
+ * remove — and `Intl`'s `dateStyle: "medium"` says "14 Sept 2026" where
70
+ * `DateField` says "14 Sep 2026", so two screens in one product would spell
71
+ * one date two ways. The zone stays local: what time it was *for the reader*
72
+ * is the question a feed answers.
73
+ */
74
+ function actorTime(at, locale = "en-GB") {
75
+ const date = toDate(at);
76
+ if (!date) return void 0;
77
+ if (isEn(locale)) return `${`${date.getDate()} ${MONTHS_SHORT[date.getMonth()]} ${date.getFullYear()}`}, ${pad(date.getHours())}:${pad(date.getMinutes())}`;
78
+ return new Intl.DateTimeFormat(locale, {
79
+ dateStyle: "medium",
80
+ timeStyle: "short"
81
+ }).format(date);
82
+ }
83
+ /** One or two letters for the avatar fallback, as the shell's avatar does. */
84
+ function initials(name) {
85
+ const words = name.trim().split(/\s+/).filter(Boolean);
86
+ if (words.length === 0) return "?";
87
+ return ((words[0]?.charAt(0) ?? "") + (words.length > 1 ? words.at(-1)?.charAt(0) ?? "" : "")).toUpperCase();
88
+ }
89
+ /**
90
+ * Actor — "Amit", "Amit (Agent)", "System", "Someone".
91
+ *
92
+ * @example
93
+ * <p>
94
+ * <Actor userId={r.actorUserId} displayName={r.actorName} via={r.actorVia} /> changed the status
95
+ * </p>
96
+ */
97
+ function Actor({ userId, displayName, via, avatarUrl, at, surface, size = "inline", avatar, locale, className, ...props }) {
98
+ const name = actorName({
99
+ displayName,
100
+ via
101
+ });
102
+ const time = at === void 0 ? void 0 : actorTime(at, locale);
103
+ const hint = [surface, time].filter(Boolean).join(" · ") || void 0;
104
+ const showAvatar = avatar ?? size === "head";
105
+ const stacked = showAvatar || size === "head";
106
+ /**
107
+ * The hover, for everyone who never hovers (DESIGN-120 review).
108
+ *
109
+ * The tooltip trigger is a plain `span` — no tab stop, because making every
110
+ * actor in a 200-row grid focusable would wreck keyboard navigation of it,
111
+ * and no `aria-label`, because a `role=generic` element's label is dropped
112
+ * by assistive technology rather than announced. So the same text the
113
+ * tooltip shows is also in the DOM, visually hidden, in document order right
114
+ * after the name: a screen reader reads it where it is relevant, and any
115
+ * ancestor whose role takes its name from its contents — the `td` a
116
+ * DataTable cell sits in, a link, a button — includes it in that name.
117
+ */
118
+ const hintNode = hint ? /* @__PURE__ */ jsx("span", {
119
+ "data-slot": "actor-hint",
120
+ className: "sr-only",
121
+ children: hint
122
+ }) : null;
123
+ const label = /* @__PURE__ */ jsxs("span", {
124
+ "data-slot": "actor-label",
125
+ className: stacked ? "truncate" : void 0,
126
+ children: [/* @__PURE__ */ jsx("span", {
127
+ "data-slot": "actor-name",
128
+ children: name
129
+ }), via === "agent" ? /* @__PURE__ */ jsxs(Fragment, { children: [" ", /* @__PURE__ */ jsx("span", {
130
+ "data-slot": "actor-suffix",
131
+ className: "text-[length:var(--ds-text-caption)] text-[color:var(--ds-muted-foreground)]",
132
+ children: ACTOR_AGENT_SUFFIX
133
+ })] }) : null]
134
+ });
135
+ const root = stacked ? /* @__PURE__ */ jsxs("span", {
136
+ "data-slot": "actor",
137
+ "data-via": via,
138
+ "data-size": size,
139
+ className: cn("inline-flex max-w-full items-center gap-2 align-middle", className),
140
+ ...props,
141
+ children: [showAvatar ? /* @__PURE__ */ jsxs(Avatar, {
142
+ "aria-hidden": true,
143
+ className: size === "head" ? "size-8" : "size-6",
144
+ children: [avatarUrl ? /* @__PURE__ */ jsx(AvatarImage, {
145
+ src: avatarUrl,
146
+ alt: ""
147
+ }) : null, /* @__PURE__ */ jsx(AvatarFallback, { children: initials(name) })]
148
+ }) : null, /* @__PURE__ */ jsxs("span", {
149
+ className: "flex min-w-0 flex-col",
150
+ children: [
151
+ label,
152
+ hintNode,
153
+ size === "head" && time ? /* @__PURE__ */ jsx("span", {
154
+ "aria-hidden": true,
155
+ "data-slot": "actor-time",
156
+ className: "truncate text-[length:var(--ds-text-caption)] text-[color:var(--ds-muted-foreground)]",
157
+ children: time
158
+ }) : null
159
+ ]
160
+ })]
161
+ }) : /* @__PURE__ */ jsxs("span", {
162
+ "data-slot": "actor",
163
+ "data-via": via,
164
+ "data-size": size,
165
+ className: cn(size === "cell" && "inline-block max-w-full truncate align-middle", className),
166
+ ...props,
167
+ children: [label, hintNode]
168
+ });
169
+ if (!hint) return root;
170
+ return /* @__PURE__ */ jsxs(Tooltip, { children: [/* @__PURE__ */ jsx(TooltipTrigger, { render: root }), /* @__PURE__ */ jsx(TooltipContent, { children: hint })] });
171
+ }
172
+ //#endregion
173
+ export { ACTOR_AGENT_SUFFIX, ACTOR_SYSTEM_NAME, ACTOR_UNKNOWN_NAME, Actor, actorLabel, actorName, actorTime };
174
+
175
+ //# sourceMappingURL=actor.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"actor.js","names":[],"sources":["../../src/components/actor.tsx"],"sourcesContent":["\"use client\";\n\nimport type * as React from \"react\";\nimport { Avatar, AvatarFallback, AvatarImage } from \"@/components/avatar\";\nimport { Tooltip, TooltipContent, TooltipTrigger } from \"@/components/tooltip\";\nimport { cn } from \"@/lib/cn\";\n\n/**\n * Who acted, on one screen, in one component (DESIGN-120, protocol §20 /\n * audit rule P-26).\n *\n * Every extension records the same two things on every write — the acting\n * user and `via` — and every screen that shows a trail has to answer the same\n * question: did a person do this, or did their agent? Seven extensions\n * formatting that themselves is seven answers, and the one that prints the\n * stored string raw shows `Amit (claude-code)`, which tells an operator the\n * name of a CLI and not whether a human was in the loop.\n *\n * So the input is the resolved actor, never a label. There is deliberately no\n * `label`, `text` or `children` prop: a consumer that could pass a string\n * would eventually pass a differently formatted one, which is exactly how the\n * inconsistency arrived. The rules below live here and nowhere else.\n */\n\n/**\n * How the principal acted. `user` and `agent` are the protocol's two values\n * (packages/shared `ActorVia`); `system` is the display-only third for a write\n * the platform made on nobody's behalf — a retention sweep, a migration.\n */\nexport type ActorVia = \"user\" | \"agent\" | \"system\";\n\n/**\n * inline — text only, sits inside a sentence: \"Amit (Agent) changed the status\".\n * cell — a DataTable cell: avatar-less, one line, truncates.\n * head — avatar, name and time, for a feed row or a comment header.\n */\nexport type ActorSize = \"inline\" | \"cell\" | \"head\";\n\n/**\n * The suffix, fixed, in one place, so no screen can invent its own. It is\n * never the agent's technical id or session: which agent ran is an audit\n * question, and the audit table has `actorAgentId` for it. On screen the only\n * thing that changes the reader's next action is *that* an agent acted.\n */\nexport const ACTOR_AGENT_SUFFIX = \"(Agent)\";\n\n/** What `via: \"system\"` reads as, whatever name came with the row. */\nexport const ACTOR_SYSTEM_NAME = \"System\";\n\n/**\n * An unknown or deleted user. Never the id: `usr_9f2c…` in a feed reads as\n * noise to everyone who is not debugging, and the ids are in the audit table\n * for the one person who is. The server-side `actorLabel` falls back to the\n * id because a log line has no other anchor; a screen does.\n */\nexport const ACTOR_UNKNOWN_NAME = \"Someone\";\n\n/** What the shared actor resolver produces and what the list APIs return. */\nexport interface ActorValue {\n /** The acting principal. Null for a system write, or a row that lost its user. */\n userId: string | null;\n /** The stored display name. Absent or empty means unknown or deleted. */\n displayName?: string | null;\n via: ActorVia;\n avatarUrl?: string;\n /** When it happened. Shown in `head` and in the hover for every size. */\n at?: string | Date;\n /** Where it happened — \"Web\", \"MCP\", \"Tasks › Sprint 4\". Hover only. */\n surface?: string;\n}\n\n/** The name alone, before the suffix. */\nexport function actorName(actor: Pick<ActorValue, \"displayName\" | \"via\">): string {\n if (actor.via === \"system\") return ACTOR_SYSTEM_NAME;\n const name = actor.displayName?.trim();\n return name ? name : ACTOR_UNKNOWN_NAME;\n}\n\n/**\n * The full label as a string: `\"Amit\"`, `\"Amit (Agent)\"`, `\"System\"`,\n * `\"Someone (Agent)\"`.\n *\n * Exported for the places a React node cannot go — an `aria-label`, a CSV\n * export, a `title` — and used by `actorColumn` as the column's sort and\n * filter value, so a table sorts by what the reader sees.\n */\nexport function actorLabel(actor: Pick<ActorValue, \"displayName\" | \"via\">): string {\n const name = actorName(actor);\n return actor.via === \"agent\" ? `${name} ${ACTOR_AGENT_SUFFIX}` : name;\n}\n\n/** A `Date` from either accepted form, or null when it does not parse. */\nfunction toDate(at: string | Date): Date | null {\n const date = at instanceof Date ? at : new Date(at);\n return Number.isNaN(date.getTime()) ? null : date;\n}\n\nconst MONTHS_SHORT = [\n \"Jan\",\n \"Feb\",\n \"Mar\",\n \"Apr\",\n \"May\",\n \"Jun\",\n \"Jul\",\n \"Aug\",\n \"Sep\",\n \"Oct\",\n \"Nov\",\n \"Dec\",\n];\n\nconst pad = (n: number) => String(n).padStart(2, \"0\");\nconst isEn = (locale: string) => /^en(-GB)?$/i.test(locale);\n\n/**\n * `5 Jan 2026, 14:32` for en-GB; other locales via `Intl.DateTimeFormat`.\n *\n * `en-GB` by default and hand-written, exactly as `date-field.tsx` does it,\n * for the same two reasons. The machine's own locale would render the same\n * trail differently on every machine — the drift this component exists to\n * remove — and `Intl`'s `dateStyle: \"medium\"` says \"14 Sept 2026\" where\n * `DateField` says \"14 Sep 2026\", so two screens in one product would spell\n * one date two ways. The zone stays local: what time it was *for the reader*\n * is the question a feed answers.\n */\nexport function actorTime(at: string | Date, locale = \"en-GB\"): string | undefined {\n const date = toDate(at);\n if (!date) return undefined;\n if (isEn(locale)) {\n const day = `${date.getDate()} ${MONTHS_SHORT[date.getMonth()]} ${date.getFullYear()}`;\n return `${day}, ${pad(date.getHours())}:${pad(date.getMinutes())}`;\n }\n return new Intl.DateTimeFormat(locale, { dateStyle: \"medium\", timeStyle: \"short\" }).format(date);\n}\n\n/** One or two letters for the avatar fallback, as the shell's avatar does. */\nfunction initials(name: string): string {\n const words = name.trim().split(/\\s+/).filter(Boolean);\n if (words.length === 0) return \"?\";\n const first = words[0]?.charAt(0) ?? \"\";\n const last = words.length > 1 ? (words.at(-1)?.charAt(0) ?? \"\") : \"\";\n return (first + last).toUpperCase();\n}\n\nexport interface ActorProps\n extends ActorValue,\n // Every way a caller could put its own words on screen is closed, not\n // only `children`: `title` would be a second, unformatted label sitting\n // in the native hover, and `dangerouslySetInnerHTML` would replace the\n // label outright. The component's whole value is that there is exactly\n // one spelling of who acted.\n Omit<React.ComponentProps<\"span\">, \"children\" | \"color\" | \"title\" | \"dangerouslySetInnerHTML\"> {\n /** @default \"inline\" */\n size?: ActorSize;\n /** Override the per-size default: off for `inline` and `cell`, on for `head`. */\n avatar?: boolean;\n /** Formatting locale for `at`. @default \"en-GB\" */\n locale?: string;\n}\n\n/**\n * Actor — \"Amit\", \"Amit (Agent)\", \"System\", \"Someone\".\n *\n * @example\n * <p>\n * <Actor userId={r.actorUserId} displayName={r.actorName} via={r.actorVia} /> changed the status\n * </p>\n */\nfunction Actor({\n userId,\n displayName,\n via,\n avatarUrl,\n at,\n surface,\n size = \"inline\",\n avatar,\n locale,\n className,\n ...props\n}: ActorProps) {\n const name = actorName({ displayName, via });\n const time = at === undefined ? undefined : actorTime(at, locale);\n const hint = [surface, time].filter(Boolean).join(\" · \") || undefined;\n const showAvatar = avatar ?? size === \"head\";\n // Two lines rather than one, and with it where the ellipsis lives. `head`\n // keeps its stacked shape — name over time — even with `avatar={false}`,\n // which is a real state: a comment thread that has already shown the avatar\n // once does not repeat it on every reply. In the stacked shape the label is\n // a flex item, which is block-level and can clip; in the flat one it is\n // inline, and an inline box has no overflow to hide, so `truncate` on it\n // would be a silent no-op and the inline-block root wears it instead.\n const stacked = showAvatar || size === \"head\";\n\n /**\n * The hover, for everyone who never hovers (DESIGN-120 review).\n *\n * The tooltip trigger is a plain `span` — no tab stop, because making every\n * actor in a 200-row grid focusable would wreck keyboard navigation of it,\n * and no `aria-label`, because a `role=generic` element's label is dropped\n * by assistive technology rather than announced. So the same text the\n * tooltip shows is also in the DOM, visually hidden, in document order right\n * after the name: a screen reader reads it where it is relevant, and any\n * ancestor whose role takes its name from its contents — the `td` a\n * DataTable cell sits in, a link, a button — includes it in that name.\n */\n const hintNode = hint ? (\n <span data-slot=\"actor-hint\" className=\"sr-only\">\n {hint}\n </span>\n ) : null;\n\n // Name and suffix stay in one inline formatting context so the separating\n // space survives: a lone space text node between two *flex items* is dropped\n // by the layout, and `Amit(Agent)` is not the label the protocol names.\n const label = (\n <span data-slot=\"actor-label\" className={stacked ? \"truncate\" : undefined}>\n <span data-slot=\"actor-name\">{name}</span>\n {via === \"agent\" ? (\n <>\n {\" \"}\n <span\n data-slot=\"actor-suffix\"\n className=\"text-[length:var(--ds-text-caption)] text-[color:var(--ds-muted-foreground)]\"\n >\n {ACTOR_AGENT_SUFFIX}\n </span>\n </>\n ) : null}\n </span>\n );\n\n const root = stacked ? (\n <span\n data-slot=\"actor\"\n data-via={via}\n data-size={size}\n className={cn(\"inline-flex max-w-full items-center gap-2 align-middle\", className)}\n {...props}\n >\n {showAvatar ? (\n // Decorative: the initials in the fallback are the name that is\n // already written beside them, and an assistive technology reading\n // \"A S Amit Sharma\" is worse than one reading \"Amit Sharma\".\n <Avatar aria-hidden className={size === \"head\" ? \"size-8\" : \"size-6\"}>\n {avatarUrl ? <AvatarImage src={avatarUrl} alt=\"\" /> : null}\n <AvatarFallback>{initials(name)}</AvatarFallback>\n </Avatar>\n ) : null}\n {/* `min-w-0` is what lets the label's `truncate` bite: without it a flex\n item's min size is its content and nothing ever overflows. */}\n <span className=\"flex min-w-0 flex-col\">\n {label}\n {hintNode}\n {size === \"head\" && time ? (\n // `aria-hidden`, and not because the time does not matter: the\n // hidden hint above already carries it, together with the surface,\n // and without this a screen reader reads the timestamp twice.\n <span\n aria-hidden\n data-slot=\"actor-time\"\n className=\"truncate text-[length:var(--ds-text-caption)] text-[color:var(--ds-muted-foreground)]\"\n >\n {time}\n </span>\n ) : null}\n </span>\n </span>\n ) : (\n <span\n data-slot=\"actor\"\n data-via={via}\n data-size={size}\n // `inline` stays a plain inline box: it is a run of text in a sentence,\n // and `truncate` on an inline box does nothing at all, so claiming it\n // would only look like a guarantee. `cell` is inline-block, which is a\n // box the ellipsis can happen in; the DataTable's own `td` truncates\n // around it.\n className={cn(size === \"cell\" && \"inline-block max-w-full truncate align-middle\", className)}\n {...props}\n >\n {label}\n {hintNode}\n </span>\n );\n\n if (!hint) return root;\n return (\n <Tooltip>\n <TooltipTrigger render={root} />\n <TooltipContent>{hint}</TooltipContent>\n </Tooltip>\n );\n}\n\nexport { Actor };\n"],"mappings":"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"}
@@ -9,8 +9,8 @@ import { Dialog, DialogBody, DialogContent, DialogDescription, DialogFooter, Dia
9
9
  import { ErrorBanner } from "../error-banner.js";
10
10
  import { adminErrorMessage, sourceGroupOf } from "./types.js";
11
11
  import { useAdminPermissions } from "./context.js";
12
- import { Users } from "lucide-react";
13
12
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
13
+ import { Users } from "lucide-react";
14
14
  import * as React from "react";
15
15
  //#region src/components/admin-permissions/role-assignment.tsx
16
16
  /**
@@ -5,8 +5,8 @@ import { BrandMark } from "./app-shell.js";
5
5
  import { Button } from "./button.js";
6
6
  import { viewStorageKey, windowSessionStorage } from "../agent-chat/session.js";
7
7
  import { AgentChat } from "./agent-chat.js";
8
- import { Maximize2, Minimize2, X } from "lucide-react";
9
8
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
9
+ import { Maximize2, Minimize2, X } from "lucide-react";
10
10
  import * as React from "react";
11
11
  //#region src/components/agent-chat-popup.tsx
12
12
  /**
@@ -15,8 +15,8 @@ import { useAgentChat } from "../agent-chat/store.js";
15
15
  import { sessionTitle } from "../agent-chat/types.js";
16
16
  import { mcpAppExtensionId } from "../agent-chat/mcp-app/resource.js";
17
17
  import "../agent-chat/mcp-app/bridge.js";
18
- import { Check, ChevronDown, ChevronRight, MessageSquarePlus, Send, ShieldCheck, ShieldX, Sparkles, Square, X } from "lucide-react";
19
18
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
19
+ import { Check, ChevronDown, ChevronRight, MessageSquarePlus, Send, ShieldCheck, ShieldX, Sparkles, Square, X } from "lucide-react";
20
20
  import * as React from "react";
21
21
  //#region src/components/agent-chat.tsx
22
22
  /**
@@ -4,8 +4,8 @@ import { cn } from "../lib/cn.js";
4
4
  import { Avatar, AvatarFallback, AvatarImage } from "./avatar.js";
5
5
  import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuSeparator, DropdownMenuTrigger } from "./dropdown-menu.js";
6
6
  import { useCortenaTheme } from "../hooks/use-cortena-theme.js";
7
- import { CircleQuestionMark, LogOut, Menu, Monitor, Moon, Settings, Sun, User, X } from "lucide-react";
8
7
  import { jsx, jsxs } from "react/jsx-runtime";
8
+ import { CircleQuestionMark, LogOut, Menu, Monitor, Moon, Settings, Sun, User, X } from "lucide-react";
9
9
  import { getMark } from "cortena-design/marks";
10
10
  import * as React from "react";
11
11
  //#region src/components/app-shell.tsx
@@ -1,8 +1,8 @@
1
1
  "use client";
2
2
  "use client";
3
3
  import { cn } from "../lib/cn.js";
4
- import { jsx } from "react/jsx-runtime";
5
4
  import { Avatar } from "@base-ui/react/avatar";
5
+ import { jsx } from "react/jsx-runtime";
6
6
  //#region src/components/avatar.tsx
7
7
  /**
8
8
  * Avatar.
@@ -3,7 +3,7 @@ import { VariantProps } from "class-variance-authority";
3
3
  import * as React from "react";
4
4
  //#region src/components/badge.d.ts
5
5
  declare const badgeVariants: (props?: ({
6
- variant?: "default" | "success" | "warn" | "destructive" | "danger" | "info" | "outline" | "warning" | "neutral" | "secondary" | null | undefined;
6
+ variant?: "default" | "success" | "warn" | "destructive" | "danger" | "info" | "warning" | "neutral" | "secondary" | "outline" | null | undefined;
7
7
  } & import("class-variance-authority/types").ClassProp) | undefined) => string;
8
8
  export interface BadgeProps extends React.ComponentProps<"span">, VariantProps<typeof badgeVariants> {}
9
9
  declare function Badge({ className, variant, ...props }: BadgeProps): React.JSX.Element;
@@ -2,8 +2,8 @@
2
2
  "use client";
3
3
  import { cn } from "../lib/cn.js";
4
4
  import { renderWith } from "../lib/render.js";
5
- import { ChevronRight, MoreHorizontal } from "lucide-react";
6
5
  import { jsx, jsxs } from "react/jsx-runtime";
6
+ import { ChevronRight, MoreHorizontal } from "lucide-react";
7
7
  //#region src/components/breadcrumb.tsx
8
8
  /**
9
9
  * Breadcrumb — the trail above a page title.
@@ -14,7 +14,7 @@ import { Button } from "@base-ui/react/button";
14
14
  * rendered element, which is Base UI's equivalent.
15
15
  */
16
16
  declare const buttonVariants: (props?: ({
17
- variant?: "link" | "destructive" | "outline" | "secondary" | "primary" | "ghost" | "soft" | null | undefined;
17
+ variant?: "link" | "destructive" | "secondary" | "outline" | "primary" | "ghost" | "soft" | null | undefined;
18
18
  size?: "sm" | "md" | "lg" | "icon" | "icon-sm" | null | undefined;
19
19
  } & import("class-variance-authority/types").ClassProp) | undefined) => string;
20
20
  export interface ButtonProps extends React.ComponentProps<typeof Button>, VariantProps<typeof buttonVariants> {}
@@ -2,8 +2,8 @@
2
2
  "use client";
3
3
  import { cn } from "../lib/cn.js";
4
4
  import { Button } from "./button.js";
5
- import { ChevronDown, ChevronLeft, ChevronRight, ChevronUp } from "lucide-react";
6
5
  import { jsx } from "react/jsx-runtime";
6
+ import { ChevronDown, ChevronLeft, ChevronRight, ChevronUp } from "lucide-react";
7
7
  import * as React from "react";
8
8
  import { DayPicker, getDefaultClassNames } from "react-day-picker";
9
9
  //#region src/components/calendar.tsx
@@ -1,8 +1,8 @@
1
1
  "use client";
2
2
  "use client";
3
3
  import { cn } from "../lib/cn.js";
4
- import { Check, Minus } from "lucide-react";
5
4
  import { jsx } from "react/jsx-runtime";
5
+ import { Check, Minus } from "lucide-react";
6
6
  import { Checkbox } from "@base-ui/react/checkbox";
7
7
  //#region src/components/checkbox.tsx
8
8
  function Checkbox$1({ className, indeterminate, ...props }) {
@@ -7,7 +7,7 @@ import * as React from "react";
7
7
  * sentence case and the body font.
8
8
  */
9
9
  declare const chipVariants: (props?: ({
10
- variant?: "default" | "accent" | "outline" | null | undefined;
10
+ variant?: "default" | "outline" | "accent" | null | undefined;
11
11
  size?: "default" | "sm" | null | undefined;
12
12
  } & import("class-variance-authority/types").ClassProp) | undefined) => string;
13
13
  export interface ChipProps extends React.ComponentProps<"span">, VariantProps<typeof chipVariants> {}
@@ -2,8 +2,8 @@
2
2
  "use client";
3
3
  import { cn } from "../lib/cn.js";
4
4
  import { inputClassName } from "./input.js";
5
- import { Check, ChevronDown, X } from "lucide-react";
6
5
  import { jsx, jsxs } from "react/jsx-runtime";
6
+ import { Check, ChevronDown, X } from "lucide-react";
7
7
  import { createContext, useContext } from "react";
8
8
  import { Combobox } from "@base-ui/react/combobox";
9
9
  //#region src/components/combobox.tsx
@@ -2,8 +2,8 @@
2
2
  "use client";
3
3
  import { cn } from "../lib/cn.js";
4
4
  import { Dialog, DialogContent, DialogDescription, DialogTitle } from "./dialog.js";
5
- import { Search } from "lucide-react";
6
5
  import { jsx, jsxs } from "react/jsx-runtime";
6
+ import { Search } from "lucide-react";
7
7
  import { Command } from "cmdk";
8
8
  //#region src/components/command.tsx
9
9
  /**
@@ -7,8 +7,8 @@ import { ErrorBanner } from "../error-banner.js";
7
7
  import { Skeleton } from "../skeleton.js";
8
8
  import { DataTableColumnHeader, DataTablePagination, DataTableToolbar } from "./parts.js";
9
9
  import { useDataTable } from "./use-data-table.js";
10
- import { Inbox } from "lucide-react";
11
10
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
11
+ import { Inbox } from "lucide-react";
12
12
  import * as React from "react";
13
13
  import { useVirtualizer } from "@tanstack/react-virtual";
14
14
  //#region src/components/data-table/data-table.tsx