@markmo/europacore-session-ui 0.2.0 → 0.4.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 (63) hide show
  1. package/README.md +1 -1
  2. package/dist/ArtifactsPage-BxaqShTv.js +1178 -0
  3. package/dist/{BoardPage-BAQrGP7G.js → BoardPage-DH7p5o99.js} +274 -265
  4. package/dist/{CardDetail-CCgP8R61.js → CardDetail-LfDCJQhS.js} +42 -33
  5. package/dist/{ComparePage-FcLLhKzC.js → ComparePage-CrbCyu4u.js} +33 -33
  6. package/dist/MemoriesPage-BRA53Hlb.js +679 -0
  7. package/dist/{OverviewPage-CbfbyGNT.js → OverviewPage-BSBqY83_.js} +50 -49
  8. package/dist/{RegisterPage-3-hJNQEV.js → RegisterPage-64yGl9E-.js} +76 -76
  9. package/dist/SessionPage-C4hSlxWQ.js +906 -0
  10. package/dist/api/agentClient.d.ts +66 -1
  11. package/dist/api/wire.d.ts +540 -4
  12. package/dist/features/artifacts/ArtifactDetail.d.ts +15 -0
  13. package/dist/features/artifacts/ArtifactDialogs.d.ts +29 -0
  14. package/dist/features/artifacts/ArtifactLedger.d.ts +11 -0
  15. package/dist/features/artifacts/ArtifactStats.d.ts +9 -0
  16. package/dist/features/artifacts/ArtifactsPage.d.ts +1 -0
  17. package/dist/features/artifacts/artifactsCommands.d.ts +3 -0
  18. package/dist/features/artifacts/artifactsStore.d.ts +27 -0
  19. package/dist/features/artifacts/artifactsUi.d.ts +33 -0
  20. package/dist/features/bootstrap.d.ts +1 -0
  21. package/dist/features/chat/model/artifactAccess.d.ts +50 -0
  22. package/dist/features/chat/model/artifactCsv.d.ts +11 -0
  23. package/dist/features/chat/model/artifactExport.d.ts +45 -0
  24. package/dist/features/chat/model/artifactStats.d.ts +79 -0
  25. package/dist/features/chat/model/artifacts.d.ts +151 -0
  26. package/dist/features/chat/model/claims.d.ts +102 -0
  27. package/dist/features/chat/model/contextSources.d.ts +41 -0
  28. package/dist/features/chat/model/entries.d.ts +37 -2
  29. package/dist/features/chat/model/fleet.d.ts +11 -0
  30. package/dist/features/chat/model/format.d.ts +6 -0
  31. package/dist/features/chat/model/inspect.d.ts +11 -0
  32. package/dist/features/chat/model/memory.d.ts +3 -3
  33. package/dist/features/chat/model/memoryRecords.d.ts +79 -0
  34. package/dist/features/chat/model/monitors.d.ts +11 -0
  35. package/dist/features/chat/model/progress.d.ts +73 -0
  36. package/dist/features/chat/model/routing.d.ts +20 -0
  37. package/dist/features/chat/model/store.d.ts +5 -0
  38. package/dist/features/chat/model/tasks.d.ts +1 -1
  39. package/dist/features/chat/panels/ProgressPanel.d.ts +8 -0
  40. package/dist/features/chat/session/ComposerHistory.d.ts +1 -1
  41. package/dist/features/chat/session/SessionController.d.ts +3 -2
  42. package/dist/features/chat/session/useFileMentions.d.ts +18 -5
  43. package/dist/features/chat/transcript/ArtifactCard.d.ts +8 -0
  44. package/dist/features/chat/transcript/Rows.d.ts +12 -1
  45. package/dist/features/commands/InspectDialog.d.ts +3 -0
  46. package/dist/features/commands/dialogs.d.ts +1 -1
  47. package/dist/features/commands/registry.d.ts +1 -1
  48. package/dist/features/memories/MemoriesPage.d.ts +1 -0
  49. package/dist/features/memories/memoriesCommands.d.ts +3 -0
  50. package/dist/features/memories/memoriesController.d.ts +81 -0
  51. package/dist/features/memory/MemoryDialog.d.ts +1 -1
  52. package/dist/features/memory/memoryService.d.ts +10 -10
  53. package/dist/features/workspace/claimsCommands.d.ts +26 -0
  54. package/dist/features/workspace/collisionsWatcher.d.ts +7 -0
  55. package/dist/features/workspace/useSessionPageHooks.d.ts +1 -1
  56. package/dist/{index-NjGO7Jg1.js → index-CMPf-3JZ.js} +4821 -3447
  57. package/dist/index.d.ts +2 -0
  58. package/dist/index.js +86 -82
  59. package/dist/lib/paths.d.ts +12 -0
  60. package/dist/lib/zip.d.ts +14 -0
  61. package/dist/{promptHistory-DjSCHmEk.js → promptHistory-BR0NpLCI.js} +14 -14
  62. package/package.json +1 -1
  63. package/dist/SessionPage-CA9hAakW.js +0 -865
@@ -0,0 +1,9 @@
1
+ import type { ArtifactInfo } from '../../api/wire';
2
+ export declare function ArtifactStats({ list, project, onOpen, onLedger, }: {
3
+ list: ArtifactInfo[];
4
+ /** The repository of the session the page was opened from, for `p`. */
5
+ project: string | null;
6
+ onOpen: (a: ArtifactInfo) => void;
7
+ /** Open the ledger on these, oldest first (untouched) or as they come (stale). */
8
+ onLedger: (only: 'untouched' | 'stale') => void;
9
+ }): import("react").JSX.Element;
@@ -0,0 +1 @@
1
+ export default function ArtifactsPage(): import("react").JSX.Element;
@@ -0,0 +1,3 @@
1
+ import { type Command } from '../commands/registry';
2
+ export declare const artifactsCommand: Command;
3
+ export declare function registerArtifactsCommands(): void;
@@ -0,0 +1,27 @@
1
+ import type { ArtifactInfo } from '../../api/wire';
2
+ export interface ArtifactsState {
3
+ /** The user's own, newest first; with a session named, that session's first. */
4
+ list: ArtifactInfo[];
5
+ /** What others share with the user, on a server that keeps access. */
6
+ shared: ArtifactInfo[];
7
+ /** The repository of the session named, when it is in one. */
8
+ project: string | null;
9
+ /** The session the list was loaded for. */
10
+ session: string | null;
11
+ loaded: boolean;
12
+ loading: boolean;
13
+ error: string | null;
14
+ }
15
+ /** How long a burst of artifact events must be quiet before the list reloads. */
16
+ export declare const RELOAD_SETTLE_MS = 250;
17
+ export declare function artifactsState(): ArtifactsState;
18
+ /** Load the list (again); with `session`, that session's first. A quiet load keeps what is shown while it runs. */
19
+ export declare function loadArtifacts(session?: string | null, quiet?: boolean): Promise<void>;
20
+ /** One artifact changed here (its access, a take-down): put the server's answer in place. */
21
+ export declare function replaceArtifact(updated: ArtifactInfo): void;
22
+ /** Artifacts deleted here, gone from the list before the reload says so. */
23
+ export declare function dropArtifacts(ids: readonly string[]): void;
24
+ export declare function subscribeArtifacts(listener: () => void): () => void;
25
+ export declare function useArtifacts(): ArtifactsState;
26
+ /** For tests: forget everything. */
27
+ export declare function resetArtifacts(): void;
@@ -0,0 +1,33 @@
1
+ import type { ArtifactInfo } from '../../api/wire';
2
+ import { type ExportKind, type ExportScope } from '../chat/model/artifactExport';
3
+ import { type SessionLink } from '../chat/model/artifacts';
4
+ export declare function FormatTag({ format }: {
5
+ format: string;
6
+ }): import("react").JSX.Element;
7
+ export declare function AccessBadge({ artifact }: {
8
+ artifact: ArtifactInfo;
9
+ }): import("react").JSX.Element | null;
10
+ /** Where its published copy stands, as a badge: live, behind, expiring, expired; nothing when unpublished. */
11
+ export declare function PublicationBadge({ artifact, now }: {
12
+ artifact: ArtifactInfo;
13
+ now?: number;
14
+ }): import("react").JSX.Element | null;
15
+ /** What became of each session `ids` names: looked up as they are asked for, the answer kept. */
16
+ export declare function useSessionLinks(ids: readonly (string | null)[]): (id: string | null) => SessionLink;
17
+ /** A session's title as a link names it, or null while unknown. */
18
+ export declare function sessionTitleOf(link: SessionLink): string | null;
19
+ /** The artifact with a viewer link that still opens: a fresh one from the server when it expires within a minute. */
20
+ export declare function freshArtifact(a: ArtifactInfo): Promise<ArtifactInfo>;
21
+ /** The link to open or copy: the published page while it is up, else the viewer's (absolute); `version` pins one. */
22
+ export declare function linkFor(a: ArtifactInfo, version?: number): Promise<{
23
+ url: string;
24
+ what: 'published' | 'viewer';
25
+ }>;
26
+ /** Open a link in a new tab. The tab opens at once (a popup blocker allows that) and goes to the link once known. */
27
+ export declare function openInTab(link: () => Promise<string>): Promise<void>;
28
+ export declare function download(name: string, data: BlobPart, type: string): void;
29
+ /**
30
+ * Export `scope` as `kind`, as a download; what it says it did. The CSV never holds a viewer link. A PDF opens the
31
+ * page for the browser to print (europacorecli prints it with Chrome).
32
+ */
33
+ export declare function exportArtifacts(kind: ExportKind, scope: ExportScope, sessionTitle: (id: string | null) => string | null): Promise<string>;
@@ -1,2 +1,3 @@
1
1
  import './chat/panels/CorePanels';
2
+ import './chat/panels/ProgressPanel';
2
3
  export declare function bootstrapFeatures(): void;
@@ -0,0 +1,50 @@
1
+ /**
2
+ * Who can open an artifact, and how often it was opened (europacore `docs/artifacts.md`, "Access"): private to its
3
+ * owner, shared with everyone signed in to the workspace, or public to anyone with the link; and what changing that
4
+ * does to the links already given out. A server from before access has none of it: there, anyone with the link can
5
+ * open the page, as ever. Nothing here draws.
6
+ */
7
+ import type { ArtifactAccess, ArtifactInfo } from '../../../api/wire';
8
+ /** Who can open it; null from a server that keeps no access, where anyone with the link can. */
9
+ export declare function accessOf(a: ArtifactInfo): ArtifactAccess | null;
10
+ /** Someone else's artifact, shared with the caller: it can be opened, not changed. */
11
+ export declare const isTheirs: (a: ArtifactInfo) => boolean;
12
+ /** What rows and ticks are keyed by: the id for one's own, `owner/id` for another's (ids are unique per owner). */
13
+ export declare function artifactKey(a: ArtifactInfo): string;
14
+ export declare const ACCESS_LABEL: Record<ArtifactAccess, string>;
15
+ /** Who can open it, in a few words: "Private · only you". */
16
+ export declare function accessLine(a: ArtifactInfo): string | null;
17
+ /** The opens in the last 30 days by anyone but the owner: through the public link, or others' own links. */
18
+ export declare function othersOpens(a: ArtifactInfo): number;
19
+ /** How often it was opened, in a line: "14 opens in 30 days · 3 people · 9 by link · last 2h ago". */
20
+ export declare function viewsLine(a: ArtifactInfo, now?: number): string | null;
21
+ export type AccessChange = ArtifactAccess | 'revoke';
22
+ export interface AccessChoice {
23
+ key: string;
24
+ change: AccessChange;
25
+ label: string;
26
+ what: string;
27
+ /** It is already this. */
28
+ current?: boolean;
29
+ /** Why it cannot be chosen; absent when it can. */
30
+ unavailable?: string;
31
+ }
32
+ /** What `A` offers for `items`: each level, the current one marked, and revoking every link. */
33
+ export declare function accessChoices(items: ArtifactInfo[]): AccessChoice[];
34
+ /**
35
+ * The question to ask before `change`, or null when none is needed: making something public, ending a public link
36
+ * (for good: making it public again gives a new one), and revoking every link.
37
+ */
38
+ export declare function confirmFor(items: ArtifactInfo[], change: AccessChange): string | null;
39
+ /** Which way a change goes: "Private", "Shared with your workspace", "Public", "Links revoked". */
40
+ export declare function changedText(change: AccessChange): string;
41
+ /** What a copied or opened link does, honestly: who it opens for, and until when. */
42
+ export declare function linkNote(a: ArtifactInfo, now?: number): string;
43
+ /** A link that expires within this long is fetched afresh before it is opened or copied. */
44
+ export declare const LINK_MARGIN_MS = 60000;
45
+ /** Its link has expired, or is about to. */
46
+ export declare function linkStale(a: ArtifactInfo, now?: number): boolean;
47
+ /** What deleting it takes from others: their access, and the opens it has had lately. */
48
+ export declare function sharedBreaks(a: ArtifactInfo): string[];
49
+ /** Deleting it should ask for its word, not a plain yes: others can open it, or have lately. */
50
+ export declare function sharedOrSeen(a: ArtifactInfo): boolean;
@@ -0,0 +1,11 @@
1
+ /**
2
+ * The artifacts as a CSV file (`X` in the ledger and the usage view): a row each, for a spreadsheet. The viewer
3
+ * link is left out: its token is the key to the page, and a file is easily passed on. Nothing here writes.
4
+ */
5
+ import type { ArtifactInfo } from '../../../api/wire';
6
+ /**
7
+ * One cell, quoted when it must be. A cell a spreadsheet would read as a formula (`=`, `+`, `-`, `@`) gets a
8
+ * leading `'`, so a title cannot run anything when the file is opened.
9
+ */
10
+ export declare function csvCell(value: string | number | null | undefined): string;
11
+ export declare function artifactsCsv(list: ArtifactInfo[], sessionTitle: (id: string | null) => string | null): string;
@@ -0,0 +1,45 @@
1
+ /**
2
+ * What `X` on the artifacts screen can export, and what the files are called. The rows go to CSV; an artifact's
3
+ * files to a ZIP; its page, as printed, to a PDF; and its source as it was written, Markdown for a Markdown
4
+ * artifact and the page's HTML for an HTML one. Each is a download (europacorecli writes them to
5
+ * `.europa/exports/` in the workspace). A port of its `src/state/artifact-export.ts`; nothing here reads, writes or draws.
6
+ */
7
+ import type { ArtifactInfo } from '../../../api/wire';
8
+ export type ExportKind = 'csv' | 'zip' | 'pdf' | 'source';
9
+ export interface ExportChoice {
10
+ kind: ExportKind;
11
+ /** The key that picks it in the menu. */
12
+ key: string;
13
+ label: string;
14
+ /** What would be written, in words. */
15
+ what: string;
16
+ /** Why it cannot be picked here; absent when it can. */
17
+ unavailable?: string;
18
+ }
19
+ /** What is being exported: the rows (for CSV), the artifacts whose files go, and a version, from the versions view. */
20
+ export interface ExportScope {
21
+ rows: ArtifactInfo[];
22
+ targets: ArtifactInfo[];
23
+ version?: number;
24
+ /** How the rows were chosen, for the CSV's line: "shown", "ticked", "counted". */
25
+ rowsAre: string;
26
+ }
27
+ /** More pages than this at once are too many to print: export them as a ZIP instead (the web prints one at a time). */
28
+ export declare const PDF_LIMIT = 10;
29
+ /** The version of `a` that goes: the one picked in the versions view, else the newest. */
30
+ export declare function versionOf(a: ArtifactInfo, scope: Pick<ExportScope, 'version' | 'targets'>): number;
31
+ /**
32
+ * The choices for `scope`. `pdfMissing` says why there is nothing to print with, or is null.
33
+ * The source is offered when every target has the same format, as its own kind of file.
34
+ */
35
+ export declare function exportChoices(scope: ExportScope, pdfMissing: string | null): ExportChoice[];
36
+ /** A name safe to put in a path from an artifact's id; the server's ids already are, but a file name must be. */
37
+ export declare function safeName(id: string): string;
38
+ /** The file one artifact's version exports to: `latency-dashboard-v2.pdf`. */
39
+ export declare function exportFileName(a: Pick<ArtifactInfo, 'id'>, version: number, ext: string): string;
40
+ /** A name for an export of several, by the time it was made: `artifacts-20261030-141500.csv`. */
41
+ export declare function stampedName(ext: string, now?: Date): string;
42
+ /** A version's file path is safe in an archive: relative, forward slashes, no `.` or `..` parts. */
43
+ export declare function safeEntryPath(file: string): boolean;
44
+ /** Where a file goes inside the ZIP: under `<id>-v<n>/` for one artifact, `<id>/v<n>/` for several. */
45
+ export declare function zipEntryPath(a: Pick<ArtifactInfo, 'id'>, version: number, file: string, several: boolean): string;
@@ -0,0 +1,79 @@
1
+ /**
2
+ * What the artifacts' usage view adds up (`/artifacts --stats`, `u`): the totals, the ≈tokens the writing runs
3
+ * spent week by week, storage over every version the server keeps, what is published, what has gone untouched,
4
+ * and the heaviest. Every figure is over the artifacts the server still has: a deleted one's spend leaves the
5
+ * history with it. Nothing here draws.
6
+ */
7
+ import type { ArtifactInfo } from '../../../api/wire';
8
+ /** The chart's windows, in weeks, as `w` steps through them. */
9
+ export declare const WINDOWS: readonly [4, 8, 12, 26];
10
+ /** An artifact nobody has written to for this long is untouched, and worth a look before keeping it. */
11
+ export declare const UNTOUCHED_DAYS = 30;
12
+ /** Monday 00:00, local time, of the week `ms` falls in. */
13
+ export declare function weekStart(ms: number): number;
14
+ /** A week's label, its Monday: "5 Oct". */
15
+ export declare function weekLabel(start: number): string;
16
+ export interface Week {
17
+ start: number;
18
+ end: number;
19
+ /** What the versions written in it took, where their run's usage was measured. */
20
+ tokens: number;
21
+ versions: number;
22
+ }
23
+ export interface ArtifactStats {
24
+ count: number;
25
+ /** Made since this week's Monday. */
26
+ newThisWeek: number;
27
+ /** Null when no version carries usage (an older server); `tokensPartial` when only some do. */
28
+ tokens: number | null;
29
+ tokensPartial: boolean;
30
+ /** Per artifact that carries usage. */
31
+ perArtifact: number | null;
32
+ /** Summed over the versions whose runs were priced; `costPartial` when some were not, or carry no usage. */
33
+ cost: number | null;
34
+ costPartial: boolean;
35
+ /** Every version's files, which the server keeps until the artifact is deleted; null from older servers. */
36
+ bytes: number | null;
37
+ files: number;
38
+ versions: number;
39
+ published: {
40
+ live: number;
41
+ temporary: number;
42
+ permanent: number;
43
+ };
44
+ /** Published at an older version, or a temporary page past its expiry. */
45
+ stale: number;
46
+ /** Their ≈tokens and storage, null when none of them was measured; how many others still opened lately. */
47
+ untouched: {
48
+ count: number;
49
+ tokens: number | null;
50
+ bytes: number | null;
51
+ openedLately: number;
52
+ };
53
+ /** What others can open, and their opens in 30 days; null from a server that keeps no access. */
54
+ shared: {
55
+ count: number;
56
+ workspace: number;
57
+ public: number;
58
+ opens: number;
59
+ } | null;
60
+ byFormat: {
61
+ tag: string;
62
+ format: string;
63
+ count: number;
64
+ }[];
65
+ heaviest: ArtifactInfo[];
66
+ /** The window's weeks, oldest first; the last is this one. */
67
+ weeks: Week[];
68
+ }
69
+ /** Every version's bytes, or null when the server measures none. */
70
+ export declare function storageOf(a: ArtifactInfo): number | null;
71
+ /** Nobody has written to it for `UNTOUCHED_DAYS`. */
72
+ export declare function isUntouched(a: ArtifactInfo, now?: number): boolean;
73
+ /** A version of it was written in `[start, end)`. */
74
+ export declare function writtenIn(a: ArtifactInfo, start: number, end: number): boolean;
75
+ /** A version of it was written in the repository `project`. An older server records none, so none match. */
76
+ export declare function inProject(a: ArtifactInfo, project: string): boolean;
77
+ /** The last `count` weeks, oldest first, with what the versions written in each took. */
78
+ export declare function weeksOf(list: ArtifactInfo[], now: number, count: number): Week[];
79
+ export declare function artifactStats(list: ArtifactInfo[], now: number, weeks: number): ArtifactStats;
@@ -0,0 +1,151 @@
1
+ /**
2
+ * The pages agents make (`artifact_write`), as `/v1/artifacts` lists them, and what the artifacts screen needs
3
+ * from them: which show under each filter, how they group by session and sort, where a published copy stands,
4
+ * and what deleting them breaks (europacore docs/artifacts.md). Nothing here draws. A port of europacorecli's
5
+ * `src/state/artifacts.ts`, without the workspace archive (a browser saves a download instead).
6
+ */
7
+ import type { ArtifactInfo, Session, SessionArtifact } from '../../../api/wire';
8
+ /** `/artifacts [--table|--stats] [id|words]`: the view, and an artifact's id or words to search for. */
9
+ export declare function parseArtifactsArgs(args: string): {
10
+ view: 'list' | 'table' | 'stats';
11
+ target: string;
12
+ };
13
+ /** A temporary page this close to its expiry is expiring soon. */
14
+ export declare const EXPIRING_SOON_MS: number;
15
+ /** What a session wrote, from its server-owned `metadata.artifacts`, the newest write last. */
16
+ export declare function artifactsOf(session: Pick<Session, 'metadata'> | null): SessionArtifact[];
17
+ /** The format as a tag: HTML, MD. */
18
+ export declare function formatTag(format: string): string;
19
+ /** The newest version's file count. */
20
+ export declare function fileCount(a: ArtifactInfo): number;
21
+ /** Where an artifact's published copy stands. */
22
+ export interface Publication {
23
+ url: string;
24
+ target: string;
25
+ /** The version that was published: the newest with a publication. */
26
+ version: number;
27
+ claimUrl: string | null;
28
+ expiresAt: string | null;
29
+ /** A temporary page past its expiry. The record cannot tell whether someone claimed it first. */
30
+ expired: boolean;
31
+ /** Under `EXPIRING_SOON_MS` left. */
32
+ soon: boolean;
33
+ /** Published at an older version than the latest. */
34
+ behind: boolean;
35
+ }
36
+ export declare function publication(a: ArtifactInfo, now?: number): Publication | null;
37
+ /** The newest copy taken down, when none is up: where it was, and when it came down. */
38
+ export declare function takenDown(a: ArtifactInfo, now?: number): {
39
+ url: string;
40
+ at: string;
41
+ } | null;
42
+ /**
43
+ * Whether its published copy can be taken down from here, or why not: only a permanent Cloudflare copy can, on a
44
+ * server with its credentials; a temporary one belongs to no account until claimed, and only expires.
45
+ */
46
+ export declare function unpublishable(a: ArtifactInfo, serverCan: boolean, now?: number): {
47
+ ok: true;
48
+ } | {
49
+ ok: false;
50
+ why: string;
51
+ };
52
+ /** A published copy that needs doing again: it shows an older version, or a temporary one has expired. */
53
+ export declare function isStale(a: ArtifactInfo, now?: number): boolean;
54
+ /**
55
+ * The list's tabs. `shared` is one's own that others can open; `others` is what others share with one. The last two
56
+ * are only for a server that keeps access.
57
+ */
58
+ export type ArtifactFilter = 'all' | 'session' | 'published' | 'stale' | 'shared' | 'others';
59
+ export declare const FILTERS: ArtifactFilter[];
60
+ export declare function filtersFor(keepsAccess: boolean): ArtifactFilter[];
61
+ /** The session the screen was opened from, and the artifacts it wrote or changed. */
62
+ export interface Here {
63
+ id: string | null;
64
+ touched: ReadonlySet<string>;
65
+ }
66
+ /**
67
+ * The sessions that made, changed or published an artifact: the one that made it, then each version's writer
68
+ * and publisher, as far as the server says (an older one names only the first).
69
+ */
70
+ export declare function writersOf(a: ArtifactInfo): string[];
71
+ /**
72
+ * "This session" is what it made or changed: an artifact names the session that made it, its versions (on newer
73
+ * servers) the sessions that wrote them, and the session's own metadata lists what it wrote.
74
+ */
75
+ export declare function hereOf(session: Pick<Session, 'id' | 'metadata'> | null): Here;
76
+ export declare function inFilter(a: ArtifactInfo, filter: ArtifactFilter, here: Here, now?: number): boolean;
77
+ /** Each tab's count: one's own under the first five, and what others share under the last. */
78
+ export declare function filterCounts(list: ArtifactInfo[], here: Here, now?: number, theirs?: ArtifactInfo[]): Record<ArtifactFilter, number>;
79
+ /** What `/` searches: the title, the id, the description and the session's title. */
80
+ export declare function searchText(a: ArtifactInfo, sessionTitle: string | null): string;
81
+ /**
82
+ * What became of the session an artifact names. `deleted`: the server says there is no such session (404);
83
+ * `none`: no session made it; `unknown`: not asked yet, or the server did not say. Only the first two are orphans.
84
+ */
85
+ export type SessionLink = {
86
+ kind: 'session';
87
+ session: Session;
88
+ live: boolean;
89
+ } | {
90
+ kind: 'deleted';
91
+ } | {
92
+ kind: 'none';
93
+ } | {
94
+ kind: 'unknown';
95
+ };
96
+ export declare const isOrphan: (link: SessionLink) => link is {
97
+ kind: "deleted";
98
+ } | {
99
+ kind: "none";
100
+ };
101
+ export interface SessionGroup {
102
+ id: string;
103
+ link: SessionLink;
104
+ artifacts: ArtifactInfo[];
105
+ }
106
+ /** The artifacts by the session that made each, in the list's order; orphans apart, to show last. */
107
+ export declare function groupBySession(list: ArtifactInfo[], link: (id: string | null) => SessionLink): {
108
+ groups: SessionGroup[];
109
+ orphans: ArtifactInfo[];
110
+ };
111
+ export type SortColumn = 'type' | 'title' | 'session' | 'created' | 'updated' | 'version' | 'tokens' | 'size' | 'published' | 'access' | 'views';
112
+ /** Sorted by a column; artifacts without a value (an older server's tokens and sizes) go last either way. */
113
+ export declare function sortArtifacts(list: ArtifactInfo[], by: SortColumn, descending: boolean, sessionTitle: (id: string | null) => string | null, now?: number): ArtifactInfo[];
114
+ export interface Totals {
115
+ count: number;
116
+ versions: number;
117
+ published: number;
118
+ /** Null when no artifact carries the figure; `partial` when only some do. */
119
+ tokens: number | null;
120
+ bytes: number | null;
121
+ partial: boolean;
122
+ }
123
+ export declare function totals(list: ArtifactInfo[], now?: number): Totals;
124
+ /** The link to open or copy: the published page while it is up, else the viewer page. */
125
+ export declare function shareLink(a: ArtifactInfo, now?: number): {
126
+ url: string;
127
+ what: 'published' | 'viewer';
128
+ };
129
+ /** A viewer link at one version. */
130
+ export declare function versionLink(link: string, version: number): string;
131
+ /** A viewer link with its token hidden: the token is the key to the page, and a screen can be seen or shared. */
132
+ export declare function maskToken(link: string): string;
133
+ /** What a published title asks to be typed before it is deleted: its first word, in lower case, else its id's. */
134
+ export declare function confirmWord(a: Pick<ArtifactInfo, 'title' | 'id'>): string;
135
+ export interface Breakage {
136
+ breaks: string[];
137
+ /** What deleting here leaves up: published copies, which the server does not take down. */
138
+ staysUp: string[];
139
+ /** `yes`: a plain y/N; `type`: the word (or, for several, their count) must be typed. */
140
+ confirm: {
141
+ kind: 'yes';
142
+ } | {
143
+ kind: 'type';
144
+ word: string;
145
+ };
146
+ }
147
+ /**
148
+ * What deleting `items` breaks and what it leaves up, and how sure the person must be. A session still on the
149
+ * server keeps its transcript, whose cards for the page stop opening; a deleted one has nothing left to break.
150
+ */
151
+ export declare function whatBreaks(items: ArtifactInfo[], link: (id: string | null) => SessionLink, now?: number): Breakage;
@@ -0,0 +1,102 @@
1
+ /**
2
+ * File claims between the sessions of one repository (europacore docs/peers.md). The server keeps them: a session
3
+ * that writes a file owns it until the change is committed, a write to a file another session owns is refused, and
4
+ * the owner's agent is asked for it. The owner answers per path, the contender may counter once, and the owner's
5
+ * reply is final. The web shows what was asked and answered, and lets the user release, hand over or ask. A port
6
+ * of europacorecli's `src/state/claims.ts`.
7
+ *
8
+ * Every title, user name, path and boundary here comes from the server or another session's agent: it is made one
9
+ * plain line before it is put in a sentence.
10
+ */
11
+ import type { Claim, ClaimRequest, ClaimsView, Disposition, PeerMessage, PeerSession, Ref, Session } from '../../../api/wire';
12
+ import type { NoticeLevel } from './entries';
13
+ /** A session's `metadata.claims`, with its paths read whether the server lists them as paths or as claims. */
14
+ export interface SessionClaims {
15
+ repo: string;
16
+ checkout: string;
17
+ changed: string[];
18
+ declared: string[];
19
+ requests: ClaimRequest[];
20
+ pending: PeerMessage[];
21
+ attention: string | null;
22
+ /** Why it needs its user, in the server's words. */
23
+ attentionReason: string | null;
24
+ }
25
+ /** What the server's `metadata.claims` says of a session's claims; null when it keeps none for it. */
26
+ export declare function claimsOf(metadata: Record<string, unknown> | null | undefined): SessionClaims | null;
27
+ /** A session as others see it: “title”, its user's name when it is a teammate's, and ☁ when it runs in the cloud. */
28
+ export declare function refLabel(ref: (Pick<Ref, 'title' | 'user' | 'mine' | 'session_id'> & {
29
+ cloud?: boolean;
30
+ }) | null | undefined): string;
31
+ /** A few paths, in one line: "a.py, b.py and 2 more". */
32
+ export declare function pathsLabel(paths: readonly string[]): string;
33
+ /** Which side of a request a session is on. */
34
+ export declare function sideOf(request: ClaimRequest, sessionId: string | null | undefined): 'owner' | 'contender' | null;
35
+ /** An answer as its dispositions, with no one named: "give a.py · share b.py: the top half". */
36
+ export declare function dispositionsLine(answer: Record<string, Disposition> | null | undefined, boundary?: string | null): string;
37
+ /** Who answers and who asked, and which of them reads it: their own name becomes "you" where that reads better. */
38
+ export interface AnswerContext {
39
+ owner?: Ref | null;
40
+ contender?: Ref | null;
41
+ boundary?: string | null;
42
+ side?: 'owner' | 'contender' | null;
43
+ }
44
+ /**
45
+ * An answer in words: "“A” gave a.py to “B”, keeps src/x/; “A” and “B” share b.py: the top half". Without the two
46
+ * sessions (a tool row's own answer), its dispositions.
47
+ */
48
+ export declare function describeAnswer(answer: Record<string, Disposition> | null | undefined, ctx?: AnswerContext): string;
49
+ /** One notice: what a `claim.*` event says to the session whose stream it came on. */
50
+ export interface ClaimNotice {
51
+ level: NoticeLevel;
52
+ text: string;
53
+ }
54
+ /** The request a `claim.*` event carries: its data, or its data's `request`. */
55
+ export declare function requestOf(data: unknown): ClaimRequest | null;
56
+ /** What `claim.requested`, `claim.answered` or `claim.resolved` tells the session `sessionId`; null for nothing. */
57
+ export declare function claimNotice(type: string, request: ClaimRequest, sessionId: string | null | undefined): ClaimNotice | null;
58
+ /** Where a request has got to, for the session `sessionId`: "waiting for “A”'s answer". */
59
+ export declare function requestState(request: ClaimRequest, sessionId: string | null | undefined): string;
60
+ /** A claim in one line: its path, kind, the other holder and boundary of a shared one, and who waits for it. */
61
+ export declare function claimLine(claim: Claim, sessionId: string | null | undefined): string;
62
+ /** `/claims`: this session's claims, the others' in the repository, the open requests with their round, and what waits. */
63
+ export declare function claimsLines(view: ClaimsView, sessionId: string | null | undefined): string;
64
+ /**
65
+ * Another session of the listing as a reference. Whether it is a teammate's is the listing's `mine`; a server
66
+ * without it is read from a reference to it elsewhere in the view, or else from its user being this session's.
67
+ */
68
+ export declare function peerRef(o: PeerSession, view: ClaimsView, sessionId: string | null | undefined): Ref;
69
+ /** Whether a claim on `claimed` covers `path`: the same path, or a directory (`dir/`) above it. */
70
+ export declare function covers(claimed: string, path: string): boolean;
71
+ /** Who holds `path` in a claims view: this session, another listed one, or no one. */
72
+ export declare function holderOf(view: ClaimsView, path: string): {
73
+ claim: Claim;
74
+ session: PeerSession | null;
75
+ } | null;
76
+ /** The session a `/claims give` names: by id, or by a title only one of the others has. */
77
+ export declare function findSession(view: ClaimsView, name: string): PeerSession | 'ambiguous' | null;
78
+ /** The inbox's reasons for a contested session: who keeps what it asked for. */
79
+ export declare function contestedLines(claims: SessionClaims, sessionId: string): string[];
80
+ /** Whether a session needs its user for its claims: a request it made could not be settled. */
81
+ export declare function isContested(session: Pick<Session, 'metadata'> | null | undefined): boolean;
82
+ /** What `/claims` was asked to do. */
83
+ export type ClaimsCommand = {
84
+ verb: 'list';
85
+ } | {
86
+ verb: 'release';
87
+ paths: string[];
88
+ } | {
89
+ verb: 'give';
90
+ path: string;
91
+ to: string | null;
92
+ } | {
93
+ verb: 'ask';
94
+ path: string;
95
+ reason: string | null;
96
+ } | {
97
+ verb: 'usage';
98
+ text: string;
99
+ };
100
+ export declare const CLAIMS_USAGE = "Usage: /claims [release <path> | give <path> [session] | ask <path> [reason]]";
101
+ /** `/claims` arguments: list, `release <path>…`, `give <path> [session]` or `ask <path> [reason]`. */
102
+ export declare function parseClaimsCommand(args: string): ClaimsCommand;
@@ -0,0 +1,41 @@
1
+ /**
2
+ * A session's context sources (what it loads, in order) as the context view shows them: grouped for the stacked
3
+ * bar, merged into one text whose lines say where they came from, and read for diagnostics. Pure. A port of
4
+ * europacorecli's `src/state/context-sources.ts`.
5
+ */
6
+ import type { ContextSource, ContextSourceKind, MemoryRecord } from '../../../api/wire';
7
+ /** A slice of the context: its glyph in the stacked bar (each its own, so it reads without colour). */
8
+ export interface SourceGroup {
9
+ key: string;
10
+ label: string;
11
+ glyph: string;
12
+ kinds: ContextSourceKind[];
13
+ }
14
+ export declare const SOURCE_GROUPS: SourceGroup[];
15
+ /** The window the context has not used. */
16
+ export declare const FREE_GLYPH = "\u00B7";
17
+ export declare function groupOf(kind: ContextSourceKind): SourceGroup;
18
+ /** Each group's tokens, in the groups' order, those with none left out. */
19
+ export declare function groupTotals(sources: ContextSource[]): (SourceGroup & {
20
+ tokens: number;
21
+ })[];
22
+ /** One line of the merged view: the source it came from, and whether it is that source's first. */
23
+ export interface MergedLine {
24
+ n: number;
25
+ text: string;
26
+ first: boolean;
27
+ }
28
+ /** What a source shows in place of text it does not have: the tools, the conversation, a prompt not rendered. */
29
+ export declare function placeholder(source: ContextSource): string;
30
+ /** Every source's text in load order, each line tagged with its source's number. */
31
+ export declare function mergedLines(sources: ContextSource[]): MergedLine[];
32
+ /** The index of a source's first merged line, for jumping to it. */
33
+ export declare function firstLineOf(lines: MergedLine[], n: number): number;
34
+ /** One diagnostic card. */
35
+ export interface Diagnostic {
36
+ title: string;
37
+ tone: 'warning' | 'accent' | 'muted';
38
+ lines: string[];
39
+ }
40
+ /** What is worth knowing about the context: what memory costs every call, and the memories to look at. */
41
+ export declare function diagnostics(sources: ContextSource[], records: MemoryRecord[], window: number | null): Diagnostic[];
@@ -1,6 +1,7 @@
1
- import type { ImageInput, Pause, PlanItem, RunKind, ToolDisplay, ToolStatus } from '../../../api/wire';
1
+ import type { RouteView } from './routing';
2
+ import type { ImageInput, MonitorEnd, Pause, PeerAbout, PeerDelivery, PlanItem, Ref, RunKind, ToolDisplay, ToolStatus } from '../../../api/wire';
2
3
  /** One row of the transcript. Entries are append-only; their contents change in place. */
3
- export type Entry = UserEntry | AssistantEntry | ToolEntry | NoticeEntry | SteerEntry | DecisionEntry | RunEndEntry | DiffEntry | WakeEntry;
4
+ export type Entry = UserEntry | AssistantEntry | ToolEntry | NoticeEntry | SteerEntry | DecisionEntry | RunEndEntry | DiffEntry | WakeEntry | MonitorEntry | PeerEntry;
4
5
  export interface UserEntry {
5
6
  kind: 'user';
6
7
  key: string;
@@ -42,6 +43,8 @@ export interface ToolEntry {
42
43
  arguments: unknown;
43
44
  startedAt: number | null;
44
45
  durationMs: number | null;
46
+ /** A monitor's task row: the batches of output it has had so far, which /tasks shows. */
47
+ events?: number;
45
48
  }
46
49
  export type NoticeLevel = 'info' | 'warn' | 'error';
47
50
  export interface NoticeEntry {
@@ -71,6 +74,34 @@ export interface WakeEntry {
71
74
  runId: string | null;
72
75
  text: string;
73
76
  }
77
+ /** A message from another session's agent (`peer.message`): input for this session's agent, not the user's word. */
78
+ export interface PeerEntry {
79
+ kind: 'peer';
80
+ key: string;
81
+ /** The sending session; null when the claims themselves say it (a path come free, a cycle broken). */
82
+ from: Ref | null;
83
+ about: PeerAbout | null;
84
+ requestId: string | null;
85
+ text: string;
86
+ /** How it reached the agent; null when read back from the transcript, where the agent has read it. */
87
+ delivery: PeerDelivery | null;
88
+ }
89
+ /**
90
+ * What the agent was given of a monitor's output (`monitor_output`): new lines from a command it left running, or
91
+ * changes to files it watches, and how the monitor ended. The lines are the command's, so untrusted.
92
+ */
93
+ export interface MonitorEntry {
94
+ kind: 'monitor';
95
+ key: string;
96
+ monitorId: string;
97
+ description: string;
98
+ /** A file watch (`watch_files`), not a command. */
99
+ files: boolean;
100
+ lines: string[];
101
+ /** Lines that arrived but were not passed on. */
102
+ dropped: number;
103
+ end: MonitorEnd | null;
104
+ }
74
105
  /** A workspace diff the user asked for (/diff), shown in full. */
75
106
  export interface DiffEntry {
76
107
  kind: 'diff';
@@ -91,6 +122,8 @@ export interface RunEndEntry {
91
122
  waiting?: string | null;
92
123
  /** Calls the permission rules or mode turned down in the run. */
93
124
  denied?: number;
125
+ /** What to change, when the run stopped short (`HarnessResult.hint`). */
126
+ hint?: string | null;
94
127
  }
95
128
  export interface ActiveRun {
96
129
  id: string;
@@ -111,6 +144,8 @@ export interface UsageView {
111
144
  inputTokens: number;
112
145
  sessionCostUsd: number | null;
113
146
  costComplete: boolean;
147
+ /** The model router's tier for the turn (`model_route`); null when the session's model is not routed. */
148
+ route: RouteView | null;
114
149
  }
115
150
  export interface PlanView {
116
151
  items: PlanItem[];