@agimon-ai/po-artifact 0.0.0-alpha.63 → 0.0.0-alpha.65

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.
@@ -844,7 +844,7 @@ function ArtifactsRailView(props) {
844
844
  });
845
845
  const filtered = sortArtifacts(matching(filters), sort, direction);
846
846
  const filtering = query !== "" || filters.status !== "all" || filters.type !== "any" || filters.modified !== "any";
847
- const rows = layout === "tree" ? artifactTree(filtered, (path) => filtering || expanded.has(path) || openPath?.startsWith(`${path}/`) === true) : filtered.map((item) => ({
847
+ const rows = layout === "tree" ? artifactTree(filtered, (path) => filtering || expanded.has(path)) : filtered.map((item) => ({
848
848
  kind: "file",
849
849
  item,
850
850
  depth: 0
@@ -1307,7 +1307,11 @@ function ArtifactsFace(props) {
1307
1307
  if (sessionId === null) return;
1308
1308
  openArtifact(props, item.path, browse.filters.location);
1309
1309
  if (!temporaryLocation) markArtifactViewed(sessionId, item);
1310
- update({ openPath: item.path });
1310
+ const parents = item.path.split("/").slice(0, -1).map((_, index, segments) => segments.slice(0, index + 1).join("/"));
1311
+ update({
1312
+ openPath: item.path,
1313
+ expanded: [...browse.expanded, ...parents.filter((path) => !browse.expanded.includes(path))]
1314
+ });
1311
1315
  },
1312
1316
  onMarkAllViewed: sessionId === null ? void 0 : () => markAllArtifactsViewed(sessionId, snapshot.items),
1313
1317
  renderThumbnail: (item) => sessionId !== null && artifactKind(item.path) === "Image" && item.size <= THUMBNAIL_BYTES ? /* @__PURE__ */ jsx(ArtifactThumbnail, {
@@ -1 +1 @@
1
- {"version":3,"file":"web.mjs","names":["channelArtifacts","dockArtifacts","fileLinksArtifacts"],"sources":["../../src/types/artifacts.ts","../../src/constants/artifacts.ts","../../src/extensions/workspaces/sessions/(frontend)/_lib/artifactView.ts","../../src/extensions/workspaces/sessions/(frontend)/_lib/artifactsStore.ts","../../src/extensions/workspaces/sessions/(frontend)/channel/artifacts.web.ts","../../src/types/apiRoutes.ts","../../generated/client.ts","../../src/extensions/workspaces/sessions/(frontend)/_lib/artifactsApi.ts","../../src/extensions/workspaces/sessions/(frontend)/_lib/authorSourceAction.ts","../../src/extensions/workspaces/sessions/(frontend)/_components/ArtifactPreviewView.tsx","../../src/extensions/workspaces/sessions/(frontend)/_components/ArtifactPreviewPanel.tsx","../../src/extensions/workspaces/sessions/(frontend)/_components/ArtifactsPanel.tsx","../../src/extensions/workspaces/sessions/(frontend)/_components/ArtifactsRailView.tsx","../../src/extensions/workspaces/sessions/(frontend)/_components/ArtifactsFace.tsx","../../src/extensions/workspaces/sessions/(frontend)/dock/artifacts.web.tsx","../../src/extensions/workspaces/sessions/(frontend)/_lib/temporaryFiles.ts","../../src/extensions/workspaces/sessions/(frontend)/file-links/artifacts.web.ts","../../generated/web.ts"],"sourcesContent":["export type ArtifactScope = 'artifacts' | 'temporary';\n\n/** Workflow owns the visibility of its reserved artifact subtree. */\nexport type ArtifactWorkflowVisibility = (relativePath: string, kind: 'file' | 'directory') => boolean;\n\nexport interface ArtifactItem {\n /** Relative to the current session's artifact directory. */\n path: string;\n name: string;\n size: number;\n modifiedAt: number;\n}\n\nexport interface ArtifactSnapshot {\n items: ArtifactItem[];\n /** Host-admitted root used only to recognize session temporary-file references. */\n temporaryRoot?: string;\n error?: string;\n}\n\nexport interface ArtifactPreview {\n path: string;\n content: string;\n mimeType: string;\n unavailable?: boolean;\n reason?: string;\n}\n\nexport const artifactsChannelType = 'artifacts';\n","export const ARTIFACT_DIRECTORY = 'po-artifacts';\nexport const ARTIFACTS_SERVICE = 'po/artifacts';\nexport const WORKFLOW_ARTIFACT_DIRECTORY = 'workflow';\n/** Autocompact mirrors compaction history here; the recent-artifacts card leaves it out. */\nexport const COMPACTION_ARTIFACT_DIRECTORY = 'compaction';\nexport const MAX_PREVIEW_BYTES = 1024 * 1024;\nexport const MAX_CONTENT_BYTES = 25 * 1024 * 1024;\n/** Videos up to this size are served, but only through range requests of at most MAX_CONTENT_BYTES. */\nexport const MAX_RANGED_VIDEO_BYTES = 128 * 1024 * 1024;\nexport const ARTIFACT_REFRESH_MS = 2000;\n\nexport const ARTIFACT_CONTENT_TYPES: Readonly<Record<string, string>> = {\n '.avif': 'image/avif',\n '.bmp': 'image/bmp',\n '.gif': 'image/gif',\n '.jpeg': 'image/jpeg',\n '.jpg': 'image/jpeg',\n '.png': 'image/png',\n '.svg': 'image/svg+xml',\n '.webp': 'image/webp',\n '.ico': 'image/vnd.microsoft.icon',\n '.mp3': 'audio/mpeg',\n '.wav': 'audio/wav',\n '.m4a': 'audio/mp4',\n '.ogg': 'audio/ogg',\n '.m4v': 'video/mp4',\n '.mov': 'video/quicktime',\n '.mp4': 'video/mp4',\n '.webm': 'video/webm',\n '.pdf': 'application/pdf',\n '.md': 'text/markdown; charset=utf-8',\n '.markdown': 'text/markdown; charset=utf-8',\n '.txt': 'text/plain; charset=utf-8',\n '.html': 'text/html; charset=utf-8',\n '.htm': 'text/html; charset=utf-8',\n};\n","import { COMPACTION_ARTIFACT_DIRECTORY } from '../../../../../constants/artifacts';\nimport type { ArtifactItem, ArtifactSnapshot } from '../../../../../types/artifacts';\n\nexport type ArtifactLayout = 'tree' | 'list' | 'grid';\nexport type ArtifactKind = 'Markdown' | 'Image' | 'Code' | 'Data' | 'Document' | 'Other';\nexport type ArtifactModified = 'any' | 'today' | '7days' | '30days';\nexport type ArtifactSort = 'name' | 'size' | 'modified';\nexport type ArtifactSortDirection = 'asc' | 'desc';\n\nexport interface ArtifactFilters {\n query?: string;\n type?: ArtifactKind | 'any';\n modified?: ArtifactModified;\n}\n\nexport function isArtifactLayout(value: unknown): value is ArtifactLayout {\n return value === 'tree' || value === 'list' || value === 'grid';\n}\n\nexport function artifactKind(path: string): ArtifactKind {\n if (/\\.(?:md|markdown)$/iu.test(path)) return 'Markdown';\n if (/\\.(?:png|jpe?g|gif|webp|avif|bmp|svg|ico|tiff?)$/iu.test(path)) return 'Image';\n if (/\\.(?:jsonl?|csv|tsv|ya?ml|xml|toml|parquet|sqlite|db)$/iu.test(path)) return 'Data';\n if (\n /\\.(?:[cm]?[jt]sx?|html?|css|scss|sass|less|py|sh|bash|go|rs|rb|java|c|cpp|cc|h|hpp|sql|swift|kt|kts|php|vue|svelte)$/iu.test(\n path,\n )\n )\n return 'Code';\n if (/\\.(?:pdf|txt|rtf|docx?|xlsx?|pptx?|odt|ods|odp)$/iu.test(path)) return 'Document';\n return 'Other';\n}\n\n/** Time is supplied by the caller. Today starts at local midnight; day windows are inclusive. */\nexport function filterArtifacts(items: readonly ArtifactItem[], filters: ArtifactFilters, now: number): ArtifactItem[] {\n const query = (filters.query ?? '').trim().toLowerCase();\n const modified = filters.modified ?? 'any';\n const day = 24 * 60 * 60 * 1000;\n const midnight = new Date(now);\n midnight.setHours(0, 0, 0, 0);\n const since = modified === 'today' ? midnight.getTime() : now - (modified === '7days' ? 7 : 30) * day;\n return items.filter(\n (item) =>\n item.path.toLowerCase().includes(query) &&\n (!filters.type || filters.type === 'any' || artifactKind(item.path) === filters.type) &&\n (modified === 'any' || (item.modifiedAt >= since && item.modifiedAt <= now)),\n );\n}\n\n/** Sort a copy, with an ascending full-path tie breaker in either direction. */\nexport function sortArtifacts(\n items: readonly ArtifactItem[],\n sort: ArtifactSort,\n direction: ArtifactSortDirection,\n): ArtifactItem[] {\n return [...items].sort((left, right) => {\n const order =\n sort === 'name'\n ? comparePaths(left.name.toLowerCase(), right.name.toLowerCase())\n : sort === 'size'\n ? left.size - right.size\n : left.modifiedAt - right.modifiedAt;\n return order * (direction === 'asc' ? 1 : -1) || comparePaths(left.path, right.path);\n });\n}\n\nfunction comparePaths(left: string, right: string): number {\n return left < right ? -1 : left > right ? 1 : 0;\n}\n\ninterface ArtifactDirectory {\n path: string;\n dirs: Map<string, ArtifactDirectory>;\n files: ArtifactItem[];\n count: number;\n}\n\nexport type ArtifactTreeRow =\n | { kind: 'dir'; path: string; name: string; depth: number; open: boolean; count: number }\n | { kind: 'file'; item: ArtifactItem; depth: number };\n\n/** Derive folders from already filtered, sorted files. Folders precede files and compact single-child chains. */\nexport function artifactTree(items: readonly ArtifactItem[], isOpen: (path: string) => boolean): ArtifactTreeRow[] {\n const root: ArtifactDirectory = { path: '', dirs: new Map(), files: [], count: 0 };\n for (const item of items) {\n let dir = root;\n dir.count++;\n for (const segment of item.path.split('/').slice(0, -1)) {\n let next = dir.dirs.get(segment);\n if (!next) {\n next = { path: dir.path ? `${dir.path}/${segment}` : segment, dirs: new Map(), files: [], count: 0 };\n dir.dirs.set(segment, next);\n }\n dir = next;\n dir.count++;\n }\n dir.files.push(item);\n }\n const rows: ArtifactTreeRow[] = [];\n const walk = (dir: ArtifactDirectory, depth: number): void => {\n for (const [segment, child] of [...dir.dirs].sort(([left], [right]) => comparePaths(left, right))) {\n let name = segment;\n let node = child;\n while (node.files.length === 0 && node.dirs.size === 1) {\n const [[nextName, next]] = [...node.dirs] as [[string, ArtifactDirectory]];\n name = `${name}/${nextName}`;\n node = next;\n }\n const open = isOpen(node.path);\n rows.push({ kind: 'dir', path: node.path, name, depth, open, count: node.count });\n if (open) walk(node, depth + 1);\n }\n for (const item of dir.files) rows.push({ kind: 'file', item, depth });\n };\n walk(root, 0);\n return rows;\n}\n\n/** `Modified today` on the same calendar day, otherwise the short date. */\nexport function modifiedLabel(modifiedAt: number, now: number): string {\n const date = new Date(modifiedAt);\n return date.toDateString() === new Date(now).toDateString()\n ? 'Modified today'\n : `Modified ${date.toLocaleDateString('en-US', { month: 'short', day: 'numeric' })}`;\n}\n\n/** What the person has seen: New (never opened), Edited (changed since opened), or Viewed. */\nexport type ArtifactStatus = 'new' | 'edited' | 'viewed';\n\n/** One session's seen record in this browser. */\nexport interface ArtifactSeenRecord {\n /** Newest server mtime when this browser first saw the session; older unopened files count as seen. */\n baseline: number;\n /** The mtime each file had when the person last opened it. */\n seen: Readonly<Record<string, number>>;\n}\n\nexport function artifactStatus(item: ArtifactItem, record: ArtifactSeenRecord | undefined): ArtifactStatus {\n if (record === undefined) return 'viewed';\n const seen = record.seen[item.path];\n if (seen !== undefined) return item.modifiedAt > seen ? 'edited' : 'viewed';\n return item.modifiedAt > record.baseline ? 'new' : 'viewed';\n}\n\n/** The web rail has no List layout; a stored `list` (shared with native) reads as Tree there. */\nexport type ArtifactRailLayout = 'tree' | 'grid';\nexport type ArtifactStatusFilter = 'all' | ArtifactStatus;\nexport type ArtifactLocation = 'artifacts' | 'temporary';\n\nexport interface ArtifactRailFilters {\n status: ArtifactStatusFilter;\n type: ArtifactKind | 'any';\n modified: ArtifactModified;\n location: ArtifactLocation;\n}\n\nexport const DEFAULT_ARTIFACT_RAIL_FILTERS: ArtifactRailFilters = {\n status: 'all',\n type: 'any',\n modified: 'any',\n location: 'artifacts',\n};\n\n/** Compact age for a narrow row: `now`, `5m`, `3h`, `2d`, then the short date. */\nexport function ageLabel(modifiedAt: number, now: number): string {\n const minutes = Math.floor(Math.max(0, now - modifiedAt) / 60000);\n if (minutes < 1) return 'now';\n if (minutes < 60) return `${minutes}m`;\n if (minutes < 60 * 24) return `${Math.floor(minutes / 60)}h`;\n if (minutes < 60 * 24 * 7) return `${Math.floor(minutes / (60 * 24))}d`;\n return new Date(modifiedAt).toLocaleDateString('en-US', { month: 'short', day: 'numeric' });\n}\nexport function sizeLabel(size: number): string {\n return size < 1024\n ? `${size} B`\n : size < 1024 * 1024\n ? `${Math.ceil(size / 1024)} KB`\n : `${(size / (1024 * 1024)).toFixed(1)} MB`;\n}\n\nexport function sortedArtifacts(items: readonly ArtifactItem[]): ArtifactItem[] {\n return [...items].sort(\n (left, right) =>\n right.modifiedAt - left.modifiedAt || (left.path < right.path ? -1 : left.path > right.path ? 1 : 0),\n );\n}\n\n/** The recent card shows the person's documents; compaction history stays in the full grid. */\nexport function recentArtifacts(items: readonly ArtifactItem[]): ArtifactItem[] {\n return sortedArtifacts(items.filter((item) => !item.path.startsWith(`${COMPACTION_ARTIFACT_DIRECTORY}/`))).slice(\n 0,\n 3,\n );\n}\n\nexport function artifactTabId(sessionId: string, path: string): string {\n return `artifact:${encodeURIComponent(sessionId)}:${encodeURIComponent(path)}`;\n}\n\n/** Resolves document assets within the artifact folder, never into another filesystem root. */\nexport function artifactAssetPath(documentPath: string, imagePath: string): string {\n if (!imagePath || imagePath.startsWith('/') || imagePath.includes('\\\\') || /^[a-z][a-z0-9+.-]*:/iu.test(imagePath))\n throw new Error('Artifact images must use a relative path.');\n const segments = documentPath.split('/').slice(0, -1);\n for (const segment of imagePath.split('/')) {\n if (segment === '' || segment === '.') continue;\n if (segment === '..') {\n if (segments.length === 0) throw new Error('The image is outside this artifact folder.');\n segments.pop();\n } else segments.push(segment);\n }\n if (segments.length === 0) throw new Error('The image path is empty.');\n return segments.join('/');\n}\n\nexport function artifactPreviewMode(path: string): 'markdown' | 'html' | 'media' | 'code' | 'text' {\n if (/\\.(?:png|jpe?g|gif|webp|avif|bmp|svg|ico|mp3|wav|m4a|ogg|mp4|mov|webm|pdf)$/iu.test(path)) return 'media';\n if (/\\.(?:md|markdown)$/iu.test(path)) return 'markdown';\n if (/\\.html?$/iu.test(path)) return 'html';\n if (/\\.(?:[cm]?[jt]sx?|json|ya?ml|css|scss|py|sh|bash|go|rs|rb|java|c|cpp|h|sql|xml|toml)$/iu.test(path))\n return 'code';\n return 'text';\n}\n\n/** A malformed channel frame must not replace the current session's known inventory. */\nexport function parseArtifactSnapshot(input: unknown): ArtifactSnapshot | null {\n if (typeof input !== 'object' || input === null || !('items' in input) || !Array.isArray(input.items)) return null;\n if ('error' in input && input.error !== undefined && typeof input.error !== 'string') return null;\n const items: ArtifactItem[] = [];\n for (const item of input.items) {\n if (\n typeof item !== 'object' ||\n item === null ||\n typeof item.path !== 'string' ||\n !item.path ||\n item.path.startsWith('/') ||\n item.path.includes('\\\\') ||\n item.path.split('/').some((part: string) => part === '..' || part === '.') ||\n typeof item.name !== 'string' ||\n !item.name ||\n typeof item.size !== 'number' ||\n !Number.isFinite(item.size) ||\n item.size < 0 ||\n typeof item.modifiedAt !== 'number' ||\n !Number.isFinite(item.modifiedAt) ||\n item.modifiedAt < 0\n )\n return null;\n items.push({ path: item.path, name: item.name, size: item.size, modifiedAt: item.modifiedAt });\n }\n return {\n items: sortedArtifacts(items),\n ...('temporaryRoot' in input && typeof input.temporaryRoot === 'string'\n ? { temporaryRoot: input.temporaryRoot }\n : {}),\n ...('error' in input && typeof input.error === 'string' ? { error: input.error } : {}),\n };\n}\n","import { defineGlobalStore, defineSessionStore } from '@agimon-ai/po-core/web';\n\nimport { artifactsChannelType, type ArtifactItem, type ArtifactSnapshot } from '../../../../../types/artifacts';\nimport {\n artifactStatus,\n DEFAULT_ARTIFACT_RAIL_FILTERS,\n isArtifactLayout,\n parseArtifactSnapshot,\n type ArtifactLayout,\n type ArtifactRailFilters,\n type ArtifactSeenRecord,\n type ArtifactSort,\n type ArtifactSortDirection,\n} from './artifactView';\n\nexport const artifacts = defineSessionStore<ArtifactSnapshot & { loaded: boolean }>({ items: [], loaded: false });\n\nexport const artifactsChannel = artifacts.channel<ArtifactSnapshot>({\n channel: artifactsChannelType,\n parse: parseArtifactSnapshot,\n reduce: (_current, snapshot) => ({ ...snapshot, loaded: true }),\n});\n\nconst LAYOUT_KEY = 'po.artifacts.layout.v1';\n\nexport function readArtifactLayout(): ArtifactLayout {\n try {\n const value = globalThis.localStorage.getItem(LAYOUT_KEY);\n return isArtifactLayout(value) ? value : 'tree';\n } catch {\n return 'tree';\n }\n}\n\nexport const artifactLayout = defineGlobalStore<ArtifactLayout>(readArtifactLayout());\n\nexport function setArtifactLayout(layout: ArtifactLayout): void {\n artifactLayout.update(() => layout);\n try {\n globalThis.localStorage.setItem(LAYOUT_KEY, layout);\n } catch {\n // A blocked or full store only loses the preference after this page closes.\n }\n}\n\n/** Sessions remembered per browser record; the stalest session is forgotten first. */\nconst SESSION_LIMIT = 50;\nconst SEEN_KEY = 'po.artifacts.seen.v1';\nconst BROWSE_KEY = 'po.artifacts.browse.v1';\n/** Files remembered per session; the earliest opened is forgotten first and then reads by the baseline. */\nconst SEEN_PATH_LIMIT = 1000;\nconst EXPANDED_LIMIT = 200;\n\ntype SessionRecords<T> = Readonly<Record<string, T>>;\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n\nfunction readSessions<T>(key: string, parse: (value: unknown) => T | undefined): SessionRecords<T> {\n try {\n const stored: unknown = JSON.parse(globalThis.localStorage.getItem(key) ?? '{}');\n if (!isRecord(stored)) return {};\n return Object.fromEntries(\n Object.entries(stored).flatMap(([sessionId, value]) => {\n const parsed = parse(value);\n return parsed === undefined ? [] : [[sessionId, parsed] as const];\n }),\n );\n } catch {\n return {};\n }\n}\n\n/** Moves the session to the newest end so the cap drops the stalest one. */\nfunction withSession<T>(records: SessionRecords<T>, sessionId: string, value: T): SessionRecords<T> {\n return Object.fromEntries(\n [...Object.entries(records).filter(([id]) => id !== sessionId), [sessionId, value] as const].slice(-SESSION_LIMIT),\n );\n}\n\nfunction save(key: string, records: SessionRecords<unknown>): void {\n try {\n globalThis.localStorage.setItem(key, JSON.stringify(records));\n } catch {\n // A blocked or full store keeps the record for this page only.\n }\n}\n\nfunction parseSeen(value: unknown): ArtifactSeenRecord | undefined {\n if (!isRecord(value) || typeof value.baseline !== 'number' || !isRecord(value.seen)) return undefined;\n const seen = Object.fromEntries(\n Object.entries(value.seen).filter((entry): entry is [string, number] => typeof entry[1] === 'number'),\n );\n return { baseline: value.baseline, seen };\n}\n\n/**\n * What the person has seen, per session, in this browser.\n *\n * ponytail: \"viewed\" means opened from the Artifacts face or from an artifact\n * link that opens Po's own preview. An Author tab opened from a transcript link\n * and returning to an already open tab are not recorded. Add a host \"tab\n * opened\" hook if people notice.\n */\nexport const artifactSeen = defineGlobalStore<SessionRecords<ArtifactSeenRecord>>(readSessions(SEEN_KEY, parseSeen));\n\n/** The baseline for a session seen for the first time: files already listed count as seen. */\nfunction firstRecord(sessionId: string): ArtifactSeenRecord | undefined {\n const snapshot = artifacts.select(artifacts.store.state, sessionId);\n if (!snapshot.loaded || snapshot.error !== undefined) return undefined;\n return { baseline: Math.max(0, ...snapshot.items.map((item) => item.modifiedAt)), seen: {} };\n}\n\nfunction updateSeen(sessionId: string, update: (record: ArtifactSeenRecord) => ArtifactSeenRecord): void {\n const current = artifactSeen.store.state[sessionId] ?? firstRecord(sessionId);\n // Nothing to compare against until the session's list arrives; the seed records the baseline then.\n if (current === undefined) return;\n const next = update(current);\n if (next === current) return;\n artifactSeen.update((records) => withSession(records, sessionId, next));\n save(SEEN_KEY, artifactSeen.store.state);\n}\n\nexport function markArtifactViewed(sessionId: string, item: Pick<ArtifactItem, 'path' | 'modifiedAt'>): void {\n updateSeen(sessionId, (record) => {\n if (record.seen[item.path] === item.modifiedAt) return record;\n const others = Object.entries(record.seen).filter(([path]) => path !== item.path);\n const entries = [...others, [item.path, item.modifiedAt] as const].slice(-SEEN_PATH_LIMIT);\n return { ...record, seen: Object.fromEntries(entries) };\n });\n}\n\n/** Everything listed now counts as seen; anything newer than the newest file reads as New again. */\nexport function markAllArtifactsViewed(sessionId: string, items: readonly ArtifactItem[]): void {\n updateSeen(sessionId, () => ({\n baseline: Math.max(0, ...items.map((item) => item.modifiedAt)),\n seen: {},\n }));\n}\n\n/** Files the person has not opened yet or that changed since: New plus Edited. */\nexport function unviewedArtifactCount(sessionId: string | null): number {\n if (sessionId === null) return 0;\n const record = artifactSeen.store.state[sessionId];\n return artifacts\n .select(artifacts.store.state, sessionId)\n .items.filter((item) => artifactStatus(item, record) !== 'viewed').length;\n}\n\n/**\n * The first list this browser receives for a session sets its baseline: files\n * already there count as seen, so an old session opens calm instead of every\n * file reading New. Runs from the store, not the face, so a batch Po makes\n * before the person opens the Artifacts face still reads New.\n */\nfunction seedBaselines(): void {\n for (const sessionId of Object.keys(artifacts.store.state)) {\n if (artifactSeen.store.state[sessionId] !== undefined) continue;\n const record = firstRecord(sessionId);\n if (record !== undefined) updateSeen(sessionId, () => record);\n }\n}\nartifacts.store.subscribe(seedBaselines);\n\n/** Where the person left the Artifacts face, per session. The search text is not saved across reloads. */\nexport interface ArtifactBrowseState {\n filters: ArtifactRailFilters;\n sort: ArtifactSort;\n direction: ArtifactSortDirection;\n expanded: readonly string[];\n /** The file last opened from the face, kept highlighted. */\n openPath?: string;\n query: string;\n searchOpen: boolean;\n}\n\nexport const DEFAULT_ARTIFACT_BROWSE: ArtifactBrowseState = {\n filters: DEFAULT_ARTIFACT_RAIL_FILTERS,\n sort: 'modified',\n direction: 'desc',\n expanded: [],\n query: '',\n searchOpen: false,\n};\n\nfunction oneOf<T extends string>(value: unknown, options: readonly T[], fallback: T): T {\n return options.includes(value as T) ? (value as T) : fallback;\n}\n\nfunction parseBrowse(value: unknown): ArtifactBrowseState | undefined {\n if (!isRecord(value)) return undefined;\n const filters = isRecord(value.filters) ? value.filters : {};\n return {\n filters: {\n status: oneOf(filters.status, ['all', 'new', 'edited', 'viewed'], 'all'),\n type: oneOf(filters.type, ['any', 'Markdown', 'Image', 'Code', 'Data', 'Document', 'Other'], 'any'),\n modified: oneOf(filters.modified, ['any', 'today', '7days', '30days'], 'any'),\n location: oneOf(filters.location, ['artifacts', 'temporary'], 'artifacts'),\n },\n sort: oneOf(value.sort, ['name', 'size', 'modified'], 'modified'),\n direction: oneOf(value.direction, ['asc', 'desc'], 'desc'),\n expanded: Array.isArray(value.expanded)\n ? value.expanded.filter((path): path is string => typeof path === 'string').slice(0, EXPANDED_LIMIT)\n : [],\n ...(typeof value.openPath === 'string' ? { openPath: value.openPath } : {}),\n query: '',\n searchOpen: false,\n };\n}\n\nexport const artifactBrowse = defineGlobalStore<SessionRecords<ArtifactBrowseState>>(\n readSessions(BROWSE_KEY, parseBrowse),\n);\n\nexport function updateArtifactBrowse(\n sessionId: string,\n update: (state: ArtifactBrowseState) => ArtifactBrowseState,\n): void {\n const next = update(artifactBrowse.store.state[sessionId] ?? DEFAULT_ARTIFACT_BROWSE);\n artifactBrowse.update((records) => withSession(records, sessionId, next));\n // The query lives for the page only: a search that hides files after a reload reads as missing files.\n save(\n BROWSE_KEY,\n Object.fromEntries(\n Object.entries(artifactBrowse.store.state).map(([id, state]) => [\n id,\n { ...state, query: '', searchOpen: false, expanded: state.expanded.slice(0, EXPANDED_LIMIT) },\n ]),\n ),\n );\n}\n","import { defineChannelFile } from '@agimon-ai/po-core/web';\n\nimport { artifactsChannel } from '../_lib/artifactsStore';\nexport default defineChannelFile(artifactsChannel);\n","import type { ApiResponseOf, ApiRoutes } from '@agimon-ai/po-core/web';\n\nimport type { ArtifactPreview, ArtifactSnapshot } from './artifacts';\n\nconst routes = {\n list: {\n method: 'GET',\n path: '/',\n query: ['scope'],\n response: undefined as unknown as ApiResponseOf<ArtifactSnapshot>,\n },\n preview: {\n method: 'GET',\n path: '/preview',\n query: ['path', 'scope'],\n response: undefined as unknown as ApiResponseOf<ArtifactPreview>,\n },\n content: {\n method: 'GET',\n path: '/content',\n query: ['path', 'scope'],\n raw: true,\n },\n} as const satisfies ApiRoutes;\n\nexport default routes;\n","// Generated by @agimon-ai/po-build. Do not edit by hand.\nimport { createApiClient, sessionApiAddress } from '@agimon-ai/po-core/web';\nimport { browserTransport } from '@agimon-ai/po-web-security/browser';\n\nimport routes from '../src/types/apiRoutes';\n\n/** Scopes the tree mounts 'artifacts' at. */\nexport const apiScopes = ['session'] as const;\n\nexport const api = createApiClient(routes, {\n scopes: apiScopes,\n basePath: 'artifacts',\n transport: (input, init) => browserTransport.fetch(input, init),\n sessionAddress: sessionApiAddress,\n});\n","import { api } from '../../../../../../generated/client';\nimport { MAX_CONTENT_BYTES, MAX_RANGED_VIDEO_BYTES } from '../../../../../constants/artifacts';\nimport type { ArtifactPreview, ArtifactScope, ArtifactSnapshot } from '../../../../../types/artifacts';\nimport { artifacts } from './artifactsStore';\nimport { artifactAssetPath, parseArtifactSnapshot } from './artifactView';\n\nexport async function refreshArtifacts(sessionId: string, signal: AbortSignal): Promise<void> {\n const before = artifacts.select(artifacts.store.state, sessionId);\n try {\n const result = await api.session(sessionId).list({ signal });\n if (signal.aborted || artifacts.select(artifacts.store.state, sessionId) !== before) return;\n const snapshot = result.ok ? parseArtifactSnapshot(result.data) : null;\n artifacts.update(sessionId, () =>\n snapshot\n ? { ...snapshot, loaded: true }\n : {\n ...before,\n loaded: true,\n error: result.ok\n ? 'The session answered with no artifact list.'\n : result.error || 'Artifacts could not be loaded.',\n },\n );\n } catch (error) {\n if (!signal.aborted && artifacts.select(artifacts.store.state, sessionId) === before)\n artifacts.update(sessionId, () => ({\n ...before,\n loaded: true,\n error: error instanceof Error ? error.message : String(error),\n }));\n }\n}\n\nexport async function fetchArtifacts(\n sessionId: string,\n signal: AbortSignal,\n scope: ArtifactScope = 'artifacts',\n): Promise<ArtifactSnapshot> {\n const result = await api.session(sessionId).list({ ...(scope === 'temporary' ? { query: { scope } } : {}), signal });\n if (!result.ok) throw new Error(result.error || 'Files could not be loaded.');\n const snapshot = parseArtifactSnapshot(result.data);\n if (!snapshot) throw new Error('The session returned an invalid file list.');\n return snapshot;\n}\n\nexport async function fetchArtifactPreview(\n sessionId: string,\n path: string,\n signal: AbortSignal,\n scope: ArtifactScope = 'artifacts',\n): Promise<ArtifactPreview> {\n const result = await api\n .session(sessionId)\n .preview({ query: { path, ...(scope === 'temporary' ? { scope } : {}) }, signal });\n if (!result.ok) throw new Error(result.error || 'This artifact could not be read.');\n const preview = result.data;\n if (\n !preview ||\n typeof preview.path !== 'string' ||\n typeof preview.content !== 'string' ||\n typeof preview.mimeType !== 'string'\n )\n throw new Error('The session answered with no artifact.');\n return preview;\n}\n\n/** Generated raw calls keep media and Markdown asset reads on the sealed artifact transport. */\nexport async function artifactBlob(\n sessionId: string,\n path: string,\n signal?: AbortSignal,\n scope: ArtifactScope = 'artifacts',\n): Promise<Blob> {\n const session = api.session(sessionId);\n const query = { path, ...(scope === 'temporary' ? { scope } : {}) };\n const result = await session.content({ query, ...(signal ? { signal } : {}) });\n if (result.ok) return result.response.blob();\n if (result.status !== 413) throw new Error(result.error || 'This artifact could not be loaded.');\n // Videos past the download cap are served only in bounded ranges of one version of the file.\n const parts: Blob[] = [];\n let offset = 0;\n let size = 1;\n let version: string | undefined;\n let type = '';\n while (offset < size) {\n const part = await session.content({\n query,\n headers: {\n range: `bytes=${offset}-${offset + MAX_CONTENT_BYTES - 1}`,\n ...(version ? { 'if-match': version } : {}),\n },\n ...(signal ? { signal } : {}),\n });\n const match = part.ok ? /^bytes (\\d+)-(\\d+)\\/(\\d+)$/u.exec(part.response.headers.get('content-range') ?? '') : null;\n if (!part.ok || part.status !== 206 || !match || Number(match[1]) !== offset)\n throw new Error(\n part.ok ? 'This artifact changed while loading.' : part.error || 'This artifact could not be loaded.',\n );\n size = Number(match[3]);\n if (size > MAX_RANGED_VIDEO_BYTES) throw new Error('This artifact is too large to load.');\n version ??= part.response.headers.get('etag') ?? undefined;\n type ||= part.response.headers.get('content-type') ?? '';\n const blob = await part.response.blob();\n if (blob.size !== Number(match[2]) - offset + 1) throw new Error('This artifact changed while loading.');\n parts.push(blob);\n offset += blob.size;\n }\n return new Blob(parts, { type });\n}\n\nexport async function loadArtifactImage(\n sessionId: string,\n documentPath: string,\n imagePath: string,\n scope: ArtifactScope = 'artifacts',\n) {\n const path = artifactAssetPath(documentPath, imagePath);\n const blob = await artifactBlob(sessionId, path, undefined, scope);\n if (!blob.type.startsWith('image/')) throw new Error('This artifact asset is not an image.');\n const url = URL.createObjectURL(blob);\n return { url, dispose: () => URL.revokeObjectURL(url), path };\n}\n","import type { SlotDeclaration, TransientTab, WebPluginSlotProps } from '@agimon-ai/po-core/web';\n\n/**\n * Author's `author.open-source` slot, declared by duck type. A web plugin can't\n * import another feature package, so this mirrors po-browse's local copy.\n */\ninterface AuthorSourceAction {\n version: 1;\n createTab(input: { sessionId: string; path: string }): TransientTab;\n}\n\nexport const authorSourceActionSlot: SlotDeclaration<AuthorSourceAction> = {\n slot: 'author.open-source',\n parse(input) {\n if (typeof input !== 'object' || input === null) return null;\n const action = input as Partial<AuthorSourceAction>;\n return action.version === 1 && typeof action.createTab === 'function' ? (action as AuthorSourceAction) : null;\n },\n};\n\n/** Author's open action when the installed plugin contributes it. */\nexport function authorSourceAction(props: WebPluginSlotProps): AuthorSourceAction | undefined {\n return props.sessionId !== null ? props.slotData?.(authorSourceActionSlot)?.[0]?.data : undefined;\n}\n","import { Breadcrumb, CodeEditor, Markdown, type MarkdownMediaReview } from '@agimon-ai/po-web-components';\nimport type { ReactNode } from 'react';\n\nimport type { ArtifactPreview } from '../../../../../types/artifacts';\nimport { artifactPreviewMode } from '../_lib/artifactView';\n\ninterface ArtifactPreviewViewProps {\n path: string;\n preview?: ArtifactPreview;\n error?: string;\n media?: ReactNode;\n loadImage?: (path: string) => Promise<{ url: string; dispose: () => void; path?: string }>;\n /** How the opened picture's provenance names this document to a reviewer. */\n documentPath?: string;\n renderMediaReview?: MarkdownMediaReview;\n}\n\nexport function ArtifactPreviewView({\n path,\n preview,\n error,\n media,\n loadImage,\n documentPath,\n renderMediaReview,\n}: ArtifactPreviewViewProps) {\n const mode = artifactPreviewMode(path);\n return (\n <div\n data-testid=\"artifact-preview\"\n data-artifact-path={path}\n className=\"flex min-h-0 flex-1 flex-col bg-po-bg text-po-text\"\n >\n <header className=\"flex shrink-0 items-center gap-2 border-b border-po-border px-4 py-3\">\n <Breadcrumb path={path} className=\"min-w-0 flex-1\" />\n <span className=\"text-sm text-po-dim\">Artifact</span>\n </header>\n <div className=\"min-h-0 flex-1 overflow-auto p-4\">\n {error ? (\n <p role=\"alert\" className=\"text-sm text-po-red\">\n {error}\n </p>\n ) : !preview ? (\n <p role=\"status\" className=\"text-sm text-po-dim\">\n Reading this artifact...\n </p>\n ) : mode === 'media' ? (\n media\n ) : preview.unavailable ? (\n <p className=\"text-sm text-po-dim\">{preview.reason ?? 'This artifact cannot be previewed.'}</p>\n ) : mode === 'markdown' ? (\n <Markdown\n text={preview.content}\n loadImage={loadImage}\n documentPath={documentPath}\n renderMediaReview={renderMediaReview}\n />\n ) : mode === 'html' ? (\n <iframe\n title={path}\n sandbox=\"\"\n srcDoc={preview.content}\n className=\"h-96 w-full rounded-md border border-po-border bg-po-deep\"\n />\n ) : mode === 'code' ? (\n <CodeEditor\n value={preview.content}\n path={path}\n readOnly\n className=\"min-h-64 rounded-md border border-po-border\"\n />\n ) : (\n <pre className=\"whitespace-pre-wrap break-words font-mono text-sm text-po-text\">{preview.content}</pre>\n )}\n </div>\n </div>\n );\n}\n","import type { TransientTab, WebPluginSlotProps } from '@agimon-ai/po-core/web';\nimport { MediaPreview, markdownMediaReview } from '@agimon-ai/po-web-components';\nimport { useStore } from '@tanstack/react-store';\nimport { useCallback, useEffect, useState } from 'react';\n\nimport type { ArtifactPreview, ArtifactScope } from '../../../../../types/artifacts';\nimport { artifactBlob, fetchArtifactPreview, loadArtifactImage } from '../_lib/artifactsApi';\nimport { artifacts, markArtifactViewed } from '../_lib/artifactsStore';\nimport { artifactTabId } from '../_lib/artifactView';\nimport { ArtifactPreviewView } from './ArtifactPreviewView';\n\nfunction ArtifactMedia({\n sessionId,\n path,\n revision,\n scope,\n}: {\n sessionId: string;\n path: string;\n revision: string;\n scope: ArtifactScope;\n}) {\n const [loaded, setLoaded] = useState<{ source: string; url?: string; mimeType?: string; error?: string }>();\n const source = `${scope}:${sessionId}:${path}:${revision}`;\n useEffect(() => {\n const controller = new AbortController();\n let url: string | undefined;\n void artifactBlob(sessionId, path, controller.signal, scope)\n .then((blob) => {\n if (controller.signal.aborted) return;\n url = URL.createObjectURL(blob);\n setLoaded({ source, url, mimeType: blob.type });\n })\n .catch((error: unknown) => {\n if (!controller.signal.aborted)\n setLoaded({ source, error: error instanceof Error ? error.message : String(error) });\n });\n return () => {\n controller.abort();\n if (url !== undefined) URL.revokeObjectURL(url);\n };\n }, [sessionId, path, source, scope]);\n const current = loaded?.source === source ? loaded : undefined;\n return current?.url ? (\n <MediaPreview src={current.url} path={path} contentType={current.mimeType} />\n ) : (\n <p\n role={current?.error ? 'alert' : 'status'}\n className={current?.error ? 'text-sm text-po-red' : 'text-sm text-po-dim'}\n >\n {current?.error ?? 'Loading artifact media...'}\n </p>\n );\n}\n\n/** Review provenance names artifacts the way Author opens them; a temporary file keeps its plain path. */\nfunction provenance(scope: ArtifactScope, relative: string): string {\n return scope === 'artifacts' ? `artifact:${relative}` : relative;\n}\n\nexport function ArtifactPreviewPanel(props: WebPluginSlotProps & { path: string; scope?: ArtifactScope }) {\n const { path, sessionId, scope = 'artifacts' } = props;\n const snapshot = useStore(artifacts.store, (state) => artifacts.select(state, sessionId));\n const item = snapshot.items.find((candidate) => candidate.path === path);\n const revision =\n scope === 'temporary'\n ? 'temporary'\n : item\n ? `${item.modifiedAt}:${item.size}`\n : snapshot.loaded\n ? 'missing'\n : 'initial';\n const [loaded, setLoaded] = useState<{\n sessionId: string;\n path: string;\n revision: string;\n preview?: ArtifactPreview;\n error?: string;\n }>();\n useEffect(() => {\n if (sessionId === null || revision === 'missing') return;\n const controller = new AbortController();\n void fetchArtifactPreview(sessionId, path, controller.signal, scope)\n .then((preview) => {\n if (!controller.signal.aborted) setLoaded({ sessionId, path, revision, preview });\n })\n .catch((error: unknown) => {\n if (!controller.signal.aborted)\n setLoaded({ sessionId, path, revision, error: error instanceof Error ? error.message : String(error) });\n });\n return () => controller.abort();\n }, [sessionId, path, revision, scope]);\n const current =\n loaded?.sessionId === sessionId && loaded.path === path && loaded.revision === revision ? loaded : undefined;\n const loadImage = useCallback(\n (imagePath: string) => {\n if (sessionId === null) return Promise.reject(new Error('The session is unavailable.'));\n return loadArtifactImage(sessionId, path, imagePath, scope).then((image) => ({\n ...image,\n path: provenance(scope, image.path),\n }));\n },\n [sessionId, path, scope],\n );\n return (\n <ArtifactPreviewView\n path={path}\n preview={current?.preview}\n error={\n sessionId === null\n ? 'The session is unavailable.'\n : revision === 'missing'\n ? 'This artifact no longer exists.'\n : current?.error\n }\n loadImage={loadImage}\n documentPath={provenance(scope, path)}\n renderMediaReview={markdownMediaReview(props)}\n media={\n sessionId === null ? undefined : (\n <ArtifactMedia sessionId={sessionId} path={path} revision={revision} scope={scope} />\n )\n }\n />\n );\n}\n\nexport function artifactTab(sessionId: string, path: string, scope: ArtifactScope = 'artifacts'): TransientTab {\n return {\n id: `${scope === 'temporary' ? 'temporary:' : ''}${artifactTabId(sessionId, path)}`,\n label: path.split('/').at(-1) ?? path,\n panel: (props) => <ArtifactPreviewPanel {...props} sessionId={sessionId} path={path} scope={scope} />,\n // A transcript link to an artifact counts as viewing it; temporary files are not tracked.\n ...(scope === 'artifacts'\n ? {\n onOpen: (owner: string) => {\n const item = artifacts.select(artifacts.store.state, owner).items.find((entry) => entry.path === path);\n if (item !== undefined) markArtifactViewed(owner, item);\n },\n }\n : {}),\n };\n}\n","import type { WebPluginSlotProps } from '@agimon-ai/po-core/web';\nimport { ImageIcon } from '@agimon-ai/po-web-components';\nimport { useStore } from '@tanstack/react-store';\nimport { useEffect, useRef, useState } from 'react';\n\nimport type { ArtifactItem, ArtifactScope, ArtifactSnapshot } from '../../../../../types/artifacts';\nimport { artifactBlob, fetchArtifacts } from '../_lib/artifactsApi';\nimport { artifacts } from '../_lib/artifactsStore';\nimport { authorSourceAction } from '../_lib/authorSourceAction';\nimport { artifactTab } from './ArtifactPreviewPanel';\n\n/** With Author installed, an artifact opens straight in Author's own (read-only) canvas tab. */\nexport function openArtifact(props: WebPluginSlotProps, path: string, scope: ArtifactScope = 'artifacts'): void {\n if (props.sessionId === null) return;\n if (scope === 'temporary') {\n props.openTransientTab(artifactTab(props.sessionId, path, scope));\n return;\n }\n const author = authorSourceAction(props);\n props.openTransientTab(\n author?.createTab({ sessionId: props.sessionId, path: `artifact:${path}` }) ?? artifactTab(props.sessionId, path),\n );\n}\n\n/** Temporary files fetch on open and whenever the artifact channel pushes a snapshot. */\nexport function useTemporaryFiles(sessionId: string | null, enabled: boolean): ArtifactSnapshot | undefined {\n const snapshot = useStore(artifacts.store, (state) => artifacts.select(state, sessionId));\n const [temporary, setTemporary] = useState<ArtifactSnapshot & { sessionId: string }>();\n useEffect(() => {\n if (sessionId === null || !enabled) return;\n const controller = new AbortController();\n const load = async (): Promise<void> => {\n try {\n const result = await fetchArtifacts(sessionId, controller.signal, 'temporary');\n if (!controller.signal.aborted) setTemporary({ ...result, sessionId });\n } catch (error) {\n if (!controller.signal.aborted)\n setTemporary((before) => ({\n sessionId,\n items: before?.sessionId === sessionId ? before.items : [],\n error: error instanceof Error ? error.message : String(error),\n }));\n }\n };\n void load();\n return () => {\n controller.abort();\n };\n }, [sessionId, enabled, snapshot]);\n return temporary?.sessionId === sessionId ? temporary : undefined;\n}\n\n/** No thumbnail request until its image cell intersects the scrolling inventory. */\nexport function ArtifactThumbnail({ sessionId, item }: { sessionId: string; item: ArtifactItem }) {\n const cell = useRef<HTMLSpanElement>(null);\n const [loaded, setLoaded] = useState<{ revision: string; url: string }>();\n const revision = `${sessionId}:${item.path}:${item.modifiedAt}:${item.size}`;\n useEffect(() => {\n const element = cell.current;\n if (!element) return;\n const controller = new AbortController();\n let url: string | undefined;\n const load = () => {\n void artifactBlob(sessionId, item.path, controller.signal)\n .then((blob) => {\n if (controller.signal.aborted || blob.size > 5 * 1024 * 1024 || !blob.type.startsWith('image/')) return;\n url = URL.createObjectURL(blob);\n setLoaded({ revision, url });\n })\n .catch(() => {\n /* The kind icon is the thumbnail fallback. */\n });\n };\n const observer =\n typeof IntersectionObserver === 'undefined'\n ? undefined\n : new IntersectionObserver((entries) => {\n if (entries.some((entry) => entry.isIntersecting)) {\n observer?.disconnect();\n load();\n }\n });\n if (observer) observer.observe(element);\n else load();\n return () => {\n observer?.disconnect();\n controller.abort();\n if (url) URL.revokeObjectURL(url);\n };\n }, [sessionId, item.path, revision]);\n return (\n <span ref={cell} className=\"flex h-full w-full items-center justify-center\">\n {loaded?.revision === revision ? (\n <img src={loaded.url} alt=\"\" className=\"h-full w-full object-cover\" />\n ) : (\n <ImageIcon aria-hidden className=\"size-8\" />\n )}\n </span>\n );\n}\n","import {\n Badge,\n Button,\n ChevronDownIcon,\n ChevronRightIcon,\n Dot,\n DropdownMenu,\n DropdownMenuContent,\n DropdownMenuItem,\n DropdownMenuLabel,\n DropdownMenuRadioGroup,\n DropdownMenuRadioItem,\n DropdownMenuSeparator,\n DropdownMenuShortcut,\n DropdownMenuTrigger,\n EmptyState,\n FileIcon,\n FolderIcon,\n GridIcon,\n ImageIcon,\n Input,\n SearchIcon,\n SlidersIcon,\n tabVariants,\n} from '@agimon-ai/po-web-components';\nimport { useEffect, useRef, type KeyboardEvent, type ReactNode } from 'react';\n\nimport type { ArtifactItem } from '../../../../../types/artifacts';\nimport {\n ageLabel,\n artifactKind,\n artifactTree,\n filterArtifacts,\n sortArtifacts,\n type ArtifactKind,\n type ArtifactModified,\n type ArtifactSort,\n type ArtifactSortDirection,\n type ArtifactLocation,\n type ArtifactRailFilters,\n type ArtifactRailLayout,\n type ArtifactStatus,\n type ArtifactStatusFilter,\n DEFAULT_ARTIFACT_RAIL_FILTERS,\n} from '../_lib/artifactView';\n\nexport interface ArtifactsRailViewProps {\n items: readonly ArtifactItem[];\n loading?: boolean;\n error?: string;\n onRetry?: () => void;\n /** Caller-supplied initial clock, so ages and Modified windows render deterministically. */\n now: number;\n /** New, Edited or Viewed per file. Absent for locations that are not tracked, such as temporary files. */\n statusOf?: (item: ArtifactItem) => ArtifactStatus;\n layout: ArtifactRailLayout;\n onLayoutChange: (layout: ArtifactRailLayout) => void;\n query: string;\n onQueryChange: (query: string) => void;\n searchOpen: boolean;\n onSearchOpenChange: (open: boolean) => void;\n filters: ArtifactRailFilters;\n onFiltersChange: (filters: ArtifactRailFilters) => void;\n sort: ArtifactSort;\n direction: ArtifactSortDirection;\n onSortChange: (sort: ArtifactSort, direction: ArtifactSortDirection) => void;\n expanded: ReadonlySet<string>;\n onToggleFolder: (path: string) => void;\n /** The file showing in the main area, highlighted so the person keeps their place. */\n openPath?: string;\n onOpen: (item: ArtifactItem) => void;\n onMarkAllViewed?: () => void;\n renderThumbnail?: (item: ArtifactItem) => ReactNode;\n /** Story and test seam: render one menu already open. */\n defaultMenuOpen?: 'filter' | 'sort';\n}\n\nconst STATUS_LABELS: Record<ArtifactStatusFilter, string> = {\n all: 'All',\n new: 'New',\n edited: 'Edited',\n viewed: 'Viewed',\n};\nconst TYPE_OPTIONS: readonly (ArtifactKind | 'any')[] = [\n 'any',\n 'Markdown',\n 'Image',\n 'Code',\n 'Data',\n 'Document',\n 'Other',\n];\nconst MODIFIED_LABELS: Record<ArtifactModified, string> = {\n any: 'Any time',\n today: 'Today',\n '7days': 'Past 7 days',\n '30days': 'Past 30 days',\n};\nconst LOCATION_LABELS: Record<ArtifactLocation, string> = { artifacts: 'Artifacts', temporary: 'Temporary files' };\nconst SORT_LABELS = {\n 'modified:desc': 'Recently changed',\n 'modified:asc': 'Oldest first',\n 'name:asc': 'Name A to Z',\n 'name:desc': 'Name Z to A',\n 'size:desc': 'Largest first',\n 'size:asc': 'Smallest first',\n} as const;\ntype SortKey = keyof typeof SORT_LABELS;\n\nfunction StatusMark({ status }: { status: ArtifactStatus | undefined }) {\n if (status === 'new')\n return (\n <Badge tone=\"green\" size=\"xs\" className=\"shrink-0 bg-po-tint-green\">\n New\n </Badge>\n );\n if (status === 'edited')\n return (\n <Badge tone=\"green\" size=\"xs\" className=\"shrink-0\">\n Edited\n </Badge>\n );\n return status === 'viewed' ? <span className=\"sr-only\">, viewed</span> : null;\n}\n\n/** The right-rail Artifacts face: every file, newest first, with what the person has not seen yet. */\nexport function ArtifactsRailView(props: ArtifactsRailViewProps) {\n const {\n items,\n loading,\n error,\n onRetry,\n now,\n statusOf,\n layout,\n onLayoutChange,\n query,\n onQueryChange,\n searchOpen,\n onSearchOpenChange,\n filters,\n onFiltersChange,\n sort,\n direction,\n onSortChange,\n expanded,\n onToggleFolder,\n openPath,\n onOpen,\n onMarkAllViewed,\n renderThumbnail,\n defaultMenuOpen,\n } = props;\n const statuses = new Map(items.map((item) => [item.path, statusOf?.(item)]));\n const newCount = items.filter((item) => statuses.get(item.path) === 'new').length;\n const editedCount = items.filter((item) => statuses.get(item.path) === 'edited').length;\n // The files a set of filters keeps; each filter option counts with the other groups as they are.\n const matching = (choice: ArtifactRailFilters) =>\n filterArtifacts(items, { query, type: choice.type, modified: choice.modified }, now).filter(\n (item) => choice.status === 'all' || statuses.get(item.path) === choice.status,\n );\n const countWith = (change: Partial<ArtifactRailFilters>) => (\n <DropdownMenuShortcut className=\"pl-4 tabular-nums\">\n {matching({ ...filters, ...change }).length}\n </DropdownMenuShortcut>\n );\n const filtered = sortArtifacts(matching(filters), sort, direction);\n const filtering = query !== '' || filters.status !== 'all' || filters.type !== 'any' || filters.modified !== 'any';\n const rows =\n layout === 'tree'\n ? artifactTree(\n filtered,\n // Folders holding the open file stay open, so the person keeps their place.\n (path) => filtering || expanded.has(path) || openPath?.startsWith(`${path}/`) === true,\n )\n : filtered.map((item) => ({ kind: 'file' as const, item, depth: 0 }));\n const unviewedUnder = (folder: string) =>\n filtered.filter((item) => item.path.startsWith(`${folder}/`) && statuses.get(item.path) !== 'viewed' && statusOf)\n .length;\n const sortValue = `${sort}:${direction}` as SortKey;\n const clear = () => {\n onQueryChange('');\n onFiltersChange({ ...DEFAULT_ARTIFACT_RAIL_FILTERS, location: filters.location });\n };\n const toggleStatus = (status: ArtifactStatus) =>\n onFiltersChange({ ...filters, status: filters.status === status ? 'all' : status });\n const moveFocus = (event: KeyboardEvent<HTMLButtonElement>) => {\n if (event.key !== 'ArrowDown' && event.key !== 'ArrowUp') return;\n const inventory = event.currentTarget.closest('[data-testid=\"artifacts-grid\"]');\n const buttons = [...(inventory?.querySelectorAll<HTMLButtonElement>('[data-artifact-row]') ?? [])];\n const index = buttons.indexOf(event.currentTarget);\n if (index < 0) return;\n event.preventDefault();\n buttons[Math.max(0, Math.min(buttons.length - 1, index + (event.key === 'ArrowDown' ? 1 : -1)))]?.focus();\n };\n\n return (\n <section\n data-testid=\"artifacts-grid\"\n aria-label=\"Artifacts\"\n className=\"flex min-h-0 flex-1 flex-col bg-po-rail text-po-text\"\n >\n <div role=\"toolbar\" aria-label=\"Artifact view\" className=\"flex shrink-0 items-center gap-1 px-3 pt-3 pb-2\">\n <DropdownMenu defaultOpen={defaultMenuOpen === 'filter'}>\n <DropdownMenuTrigger asChild>\n <Button variant=\"ghost\" size=\"sm\" className=\"text-po-text\">\n <SlidersIcon aria-hidden className=\"size-3.5\" />\n Filter\n {filters.status !== 'all' ||\n filters.type !== 'any' ||\n filters.modified !== 'any' ||\n filters.location !== 'artifacts' ? (\n <Dot tone=\"green\" aria-label=\"Filters on\" />\n ) : null}\n </Button>\n </DropdownMenuTrigger>\n <DropdownMenuContent align=\"start\" className=\"w-56\">\n {statusOf ? (\n <>\n <DropdownMenuLabel>Status</DropdownMenuLabel>\n <DropdownMenuRadioGroup\n value={filters.status}\n onValueChange={(status) => onFiltersChange({ ...filters, status: status as ArtifactStatusFilter })}\n >\n {(Object.keys(STATUS_LABELS) as ArtifactStatusFilter[]).map((status) => (\n <DropdownMenuRadioItem key={status} value={status}>\n {STATUS_LABELS[status]}\n {countWith({ status })}\n </DropdownMenuRadioItem>\n ))}\n </DropdownMenuRadioGroup>\n <DropdownMenuSeparator />\n </>\n ) : null}\n <DropdownMenuLabel>Type</DropdownMenuLabel>\n <DropdownMenuRadioGroup\n value={filters.type}\n onValueChange={(type) => onFiltersChange({ ...filters, type: type as ArtifactKind | 'any' })}\n >\n {TYPE_OPTIONS.map((type) => (\n <DropdownMenuRadioItem key={type} value={type}>\n {type === 'any' ? 'All types' : type}\n {countWith({ type })}\n </DropdownMenuRadioItem>\n ))}\n </DropdownMenuRadioGroup>\n <DropdownMenuSeparator />\n <DropdownMenuLabel>Modified</DropdownMenuLabel>\n <DropdownMenuRadioGroup\n value={filters.modified}\n onValueChange={(modified) => onFiltersChange({ ...filters, modified: modified as ArtifactModified })}\n >\n {(Object.keys(MODIFIED_LABELS) as ArtifactModified[]).map((modified) => (\n <DropdownMenuRadioItem key={modified} value={modified}>\n {MODIFIED_LABELS[modified]}\n {countWith({ modified })}\n </DropdownMenuRadioItem>\n ))}\n </DropdownMenuRadioGroup>\n <DropdownMenuSeparator />\n <DropdownMenuLabel>Location</DropdownMenuLabel>\n <DropdownMenuRadioGroup\n value={filters.location}\n onValueChange={(location) => onFiltersChange({ ...filters, location: location as ArtifactLocation })}\n >\n {(Object.keys(LOCATION_LABELS) as ArtifactLocation[]).map((location) => (\n <DropdownMenuRadioItem key={location} value={location}>\n {LOCATION_LABELS[location]}\n </DropdownMenuRadioItem>\n ))}\n </DropdownMenuRadioGroup>\n {filtering ? (\n <>\n <DropdownMenuSeparator />\n <DropdownMenuItem onSelect={clear}>Reset filters</DropdownMenuItem>\n </>\n ) : null}\n </DropdownMenuContent>\n </DropdownMenu>\n <DropdownMenu defaultOpen={defaultMenuOpen === 'sort'}>\n <DropdownMenuTrigger asChild>\n <Button variant=\"ghost\" size=\"sm\" className=\"text-po-text\">\n Sort\n <ChevronDownIcon aria-hidden className=\"size-3\" />\n </Button>\n </DropdownMenuTrigger>\n <DropdownMenuContent align=\"start\" className=\"w-48\">\n <DropdownMenuRadioGroup\n value={sortValue}\n onValueChange={(value) => {\n const [nextSort, nextDirection] = value.split(':');\n onSortChange(nextSort as ArtifactSort, nextDirection as ArtifactSortDirection);\n }}\n >\n {(Object.keys(SORT_LABELS) as SortKey[]).map((key) => (\n <DropdownMenuRadioItem key={key} value={key}>\n {SORT_LABELS[key]}\n </DropdownMenuRadioItem>\n ))}\n </DropdownMenuRadioGroup>\n </DropdownMenuContent>\n </DropdownMenu>\n <span className=\"flex-1\" />\n <fieldset aria-label=\"Artifact view\" className=\"flex shrink-0 gap-0.5\">\n {(\n [\n ['tree', FolderIcon, 'Tree view'],\n ['grid', GridIcon, 'Preview view'],\n ] as const\n ).map(([value, Icon, label]) => (\n <button\n key={value}\n type=\"button\"\n aria-label={label}\n title={label}\n aria-pressed={layout === value}\n onClick={() => onLayoutChange(value)}\n className={`${tabVariants({ active: layout === value })} focus-visible:ring-2 focus-visible:ring-po-green`}\n >\n <Icon aria-hidden className=\"size-4\" />\n </button>\n ))}\n </fieldset>\n <button\n type=\"button\"\n aria-label=\"Search artifacts\"\n title=\"Search artifacts\"\n aria-expanded={searchOpen}\n onClick={() => onSearchOpenChange(!searchOpen)}\n className={`${tabVariants({ active: searchOpen || query !== '' })} focus-visible:ring-2 focus-visible:ring-po-green`}\n >\n <SearchIcon aria-hidden className=\"size-4\" />\n </button>\n </div>\n {searchOpen ? (\n <div className=\"relative shrink-0 px-3 pb-2\">\n <SearchIcon aria-hidden className=\"absolute top-2 left-5 size-4 text-po-dim\" />\n <Input\n aria-label=\"Search artifacts\"\n // Opened by the Search button, so typing should land here.\n autoFocus\n placeholder=\"Search by name or folder\"\n value={query}\n onChange={(event) => onQueryChange(event.target.value)}\n onKeyDown={(event) => {\n if (event.key !== 'Escape') return;\n event.preventDefault();\n onQueryChange('');\n onSearchOpenChange(false);\n }}\n className=\"w-full pl-8\"\n />\n </div>\n ) : null}\n {statusOf && newCount + editedCount > 0 ? (\n <div className=\"flex shrink-0 items-center gap-1 border-b border-po-border-soft px-3 pb-2\">\n {newCount > 0 ? (\n <Button\n variant=\"ghost\"\n size=\"xs\"\n aria-pressed={filters.status === 'new'}\n onClick={() => toggleStatus('new')}\n className={filters.status === 'new' ? 'bg-po-tint-green text-po-green' : 'text-po-text'}\n >\n {newCount} new\n </Button>\n ) : null}\n {editedCount > 0 ? (\n <Button\n variant=\"ghost\"\n size=\"xs\"\n aria-pressed={filters.status === 'edited'}\n onClick={() => toggleStatus('edited')}\n className={filters.status === 'edited' ? 'bg-po-tint-green text-po-green' : 'text-po-text'}\n >\n {editedCount} edited\n </Button>\n ) : null}\n <span className=\"flex-1\" />\n {onMarkAllViewed ? (\n <Button variant=\"ghost\" size=\"xs\" onClick={onMarkAllViewed} className=\"text-po-dim\">\n Mark all viewed\n </Button>\n ) : null}\n </div>\n ) : (\n <div className=\"shrink-0 border-b border-po-border-soft\" />\n )}\n <div className=\"min-h-0 flex-1 overflow-auto\">\n {error ? (\n <div role=\"alert\" className=\"flex items-center gap-2 px-4 py-3\">\n <p className=\"flex-1 text-sm text-po-red\">{error}</p>\n {onRetry ? (\n <Button variant=\"outline\" size=\"xs\" onClick={onRetry}>\n Try again\n </Button>\n ) : null}\n </div>\n ) : null}\n {loading ? <output className=\"block px-4 py-3 text-sm text-po-dim\">Loading files...</output> : null}\n {!loading && !error && items.length === 0 ? (\n <EmptyState\n title=\"Nothing here yet\"\n description=\"Files Po makes in this session show up here.\"\n className=\"px-4 py-8\"\n />\n ) : null}\n {!loading && items.length > 0 && filtered.length === 0 ? (\n <EmptyState title=\"No files match\" className=\"px-4 py-8\">\n <Button variant=\"ghost\" onClick={clear}>\n Clear filters\n </Button>\n </EmptyState>\n ) : null}\n <div className={layout === 'grid' ? 'grid grid-cols-2 gap-2 p-3' : 'flex flex-col py-1'}>\n {rows.map((row) => {\n if (row.kind === 'dir') {\n const unviewed = unviewedUnder(row.path);\n return (\n <button\n key={row.path}\n type=\"button\"\n data-artifact-row\n aria-expanded={row.open}\n onClick={() => onToggleFolder(row.path)}\n onKeyDown={(event) => {\n moveFocus(event);\n if ((event.key === 'ArrowRight' && !row.open) || (event.key === 'ArrowLeft' && row.open)) {\n event.preventDefault();\n onToggleFolder(row.path);\n }\n }}\n className=\"flex min-h-9 items-center gap-2 px-3 py-1.5 text-left hover:bg-po-panel focus-visible:ring-2 focus-visible:ring-po-green focus-visible:ring-inset\"\n >\n {Array.from({ length: row.depth }, (_, index) => (\n <span key={index} className=\"w-3 shrink-0\" />\n ))}\n {row.open ? (\n <ChevronDownIcon aria-hidden className=\"size-3.5 shrink-0 text-po-dim\" />\n ) : (\n <ChevronRightIcon aria-hidden className=\"size-3.5 shrink-0 text-po-dim\" />\n )}\n <FolderIcon aria-hidden className=\"size-4 shrink-0 text-po-dim\" />\n <span className=\"min-w-0 flex-1 truncate text-base font-medium\">{row.name}</span>\n {unviewed > 0 ? (\n <span className=\"shrink-0 text-sm font-semibold text-po-green\">{unviewed} unviewed</span>\n ) : (\n <span className=\"shrink-0 text-sm text-po-dim\">\n {row.count} {row.count === 1 ? 'file' : 'files'}\n </span>\n )}\n </button>\n );\n }\n const status = statuses.get(row.item.path);\n const unseen = status === 'new' || status === 'edited';\n const open = openPath === row.item.path;\n const Icon = artifactKind(row.item.path) === 'Image' ? ImageIcon : FileIcon;\n return (\n <button\n key={row.item.path}\n type=\"button\"\n data-artifact-row\n data-artifact-path={row.item.path}\n data-status={status}\n aria-current={open ? 'true' : undefined}\n title={row.item.path}\n onClick={() => onOpen(row.item)}\n onKeyDown={moveFocus}\n className={`${\n layout === 'grid'\n ? 'flex min-w-0 flex-col gap-1.5 rounded-md border p-2 text-left'\n : 'flex min-h-9 items-center gap-2 border-l-2 px-3 py-1.5 text-left'\n } ${open ? 'border-po-green bg-po-panel' : layout === 'grid' ? 'border-po-border-soft hover:bg-po-panel' : 'border-transparent hover:bg-po-panel'} focus-visible:ring-2 focus-visible:ring-po-green focus-visible:ring-inset`}\n >\n {layout === 'grid' ? (\n <span className=\"relative flex h-24 w-full items-center justify-center overflow-hidden rounded-sm bg-po-deep text-po-dim\">\n {renderThumbnail?.(row.item) ?? <Icon aria-hidden className=\"size-8\" />}\n <span className=\"absolute top-1 left-1\">\n <StatusMark status={status} />\n </span>\n </span>\n ) : (\n <>\n {Array.from({ length: row.depth }, (_, index) => (\n <span key={index} className=\"w-3 shrink-0\" />\n ))}\n <span className=\"w-3.5 shrink-0\" />\n <Icon aria-hidden className=\"size-4 shrink-0 text-po-dim\" />\n </>\n )}\n <span className=\"flex w-full min-w-0 flex-1 items-center gap-2\">\n <span\n className={`min-w-0 flex-1 truncate text-base ${unseen ? 'font-semibold text-po-hi' : 'text-po-text'}`}\n >\n {row.item.name}\n </span>\n {layout === 'grid' ? (\n <span className=\"sr-only\">\n <StatusMark status={status === 'viewed' ? status : undefined} />\n </span>\n ) : (\n <StatusMark status={status} />\n )}\n <ArtifactAge modifiedAt={row.item.modifiedAt} now={now} />\n </span>\n </button>\n );\n })}\n </div>\n </div>\n <footer\n data-testid=\"artifacts-count\"\n aria-live=\"polite\"\n className=\"shrink-0 border-t border-po-border-soft px-4 py-2 text-sm text-po-dim\"\n >\n {filtering ? `${filtered.length} of ${items.length}` : items.length} {items.length === 1 ? 'file' : 'files'}\n </footer>\n </section>\n );\n}\n\n/** Compact ages update their text node without rendering the inventory. */\nexport function ArtifactAge({ modifiedAt, now }: { modifiedAt: number; now: number }) {\n const ref = useRef<HTMLTimeElement>(null);\n useEffect(() => {\n const timer = setInterval(() => {\n const node = ref.current?.firstChild;\n if (node) node.nodeValue = ageLabel(modifiedAt, Date.now());\n }, 60_000);\n return () => clearInterval(timer);\n }, [modifiedAt]);\n return (\n <time ref={ref} dateTime={new Date(modifiedAt).toISOString()} className=\"shrink-0 text-sm text-po-dim\">\n {ageLabel(modifiedAt, now)}\n </time>\n );\n}\n","import type { WebPluginSlotProps } from '@agimon-ai/po-core/web';\nimport { useStore } from '@tanstack/react-store';\nimport { useEffect, useState } from 'react';\n\nimport { refreshArtifacts } from '../_lib/artifactsApi';\nimport {\n artifactBrowse,\n artifactLayout,\n artifacts,\n artifactSeen,\n DEFAULT_ARTIFACT_BROWSE,\n markAllArtifactsViewed,\n markArtifactViewed,\n setArtifactLayout,\n updateArtifactBrowse,\n} from '../_lib/artifactsStore';\nimport { artifactKind, artifactStatus } from '../_lib/artifactView';\nimport { ArtifactThumbnail, openArtifact, useTemporaryFiles } from './ArtifactsPanel';\nimport { ArtifactsRailView } from './ArtifactsRailView';\n\nconst THUMBNAIL_BYTES = 5 * 1024 * 1024;\n\n/** The right-rail Artifacts face: production data and actions for ArtifactsRailView. */\nexport function ArtifactsFace(props: WebPluginSlotProps) {\n const { sessionId } = props;\n const snapshot = useStore(artifacts.store, (state) => artifacts.select(state, sessionId));\n const seen = useStore(artifactSeen.store, (state) => (sessionId === null ? undefined : state[sessionId]));\n const browse = useStore(artifactBrowse.store, (state) =>\n sessionId === null ? DEFAULT_ARTIFACT_BROWSE : (state[sessionId] ?? DEFAULT_ARTIFACT_BROWSE),\n );\n const stored = useStore(artifactLayout.store);\n const temporaryLocation = browse.filters.location === 'temporary';\n const temporary = useTemporaryFiles(sessionId, temporaryLocation);\n const [now, setNow] = useState(Date.now);\n useEffect(() => {\n const subscription = artifacts.store.subscribe(() => setNow(Date.now()));\n return () => subscription.unsubscribe();\n }, []);\n useEffect(() => {\n if (sessionId === null || snapshot.loaded) return;\n const controller = new AbortController();\n void refreshArtifacts(sessionId, controller.signal);\n return () => controller.abort();\n }, [sessionId, snapshot.loaded]);\n const update = (change: Partial<typeof browse>) => {\n if (sessionId !== null) updateArtifactBrowse(sessionId, (current) => ({ ...current, ...change }));\n };\n const items = temporaryLocation ? (temporary?.items ?? []) : snapshot.items;\n return (\n <ArtifactsRailView\n items={items}\n loading={sessionId !== null && (temporaryLocation ? temporary === undefined : !snapshot.loaded)}\n error={sessionId === null ? 'The session is unavailable.' : temporaryLocation ? temporary?.error : snapshot.error}\n onRetry={\n sessionId === null || temporaryLocation\n ? undefined\n : () => void refreshArtifacts(sessionId, new AbortController().signal)\n }\n now={now}\n // Temporary files are not tracked, so they carry no markers.\n statusOf={temporaryLocation ? undefined : (item) => artifactStatus(item, seen)}\n layout={stored === 'grid' ? 'grid' : 'tree'}\n onLayoutChange={setArtifactLayout}\n query={browse.query}\n onQueryChange={(query) => update({ query })}\n searchOpen={browse.searchOpen}\n onSearchOpenChange={(searchOpen) => update({ searchOpen })}\n filters={browse.filters}\n onFiltersChange={(filters) => {\n update({ filters });\n setNow(Date.now());\n }}\n sort={browse.sort}\n direction={browse.direction}\n onSortChange={(sort, direction) => update({ sort, direction })}\n expanded={new Set(browse.expanded)}\n onToggleFolder={(path) =>\n update({\n expanded: browse.expanded.includes(path)\n ? browse.expanded.filter((entry) => entry !== path)\n : [...browse.expanded, path],\n })\n }\n openPath={browse.openPath}\n onOpen={(item) => {\n if (sessionId === null) return;\n openArtifact(props, item.path, browse.filters.location);\n if (!temporaryLocation) markArtifactViewed(sessionId, item);\n update({ openPath: item.path });\n }}\n onMarkAllViewed={sessionId === null ? undefined : () => markAllArtifactsViewed(sessionId, snapshot.items)}\n renderThumbnail={(item) =>\n sessionId !== null && artifactKind(item.path) === 'Image' && item.size <= THUMBNAIL_BYTES ? (\n <ArtifactThumbnail key={item.path} sessionId={sessionId} item={item} />\n ) : undefined\n }\n />\n );\n}\n","import { defineDockFace } from '@agimon-ai/po-core/web';\nimport { FileIcon } from '@agimon-ai/po-web-components';\n\nimport { ArtifactsFace } from '../_components/ArtifactsFace';\nimport { artifacts, artifactSeen, unviewedArtifactCount } from '../_lib/artifactsStore';\n\nexport default defineDockFace({\n id: 'artifacts',\n label: 'Artifacts',\n icon: FileIcon,\n order: 10,\n panel: ArtifactsFace,\n badge: {\n subscribe(listener: () => void) {\n const files = artifacts.store.subscribe(listener);\n const seen = artifactSeen.store.subscribe(listener);\n return () => {\n files.unsubscribe();\n seen.unsubscribe();\n };\n },\n count: unviewedArtifactCount,\n },\n});\n","/** Matching links is presentation only. The server independently selects and guards the root. */\nexport function temporaryFileReference(reference: string, root: string | undefined): string | undefined {\n const value = reference.trim();\n const prefix = 'temporary:';\n let relative: string;\n if (value.startsWith(prefix)) relative = value.slice(prefix.length);\n else {\n if (!root || !root.startsWith('/')) return undefined;\n const base = root.replace(/\\/+$/u, '');\n if (!value.startsWith(`${base}/`)) return undefined;\n relative = value.slice(base.length + 1);\n }\n if (\n !relative ||\n relative.includes('\\\\') ||\n relative.includes('\\0') ||\n relative.split('/').some((part) => !part || part === '.' || part === '..')\n )\n return undefined;\n return relative;\n}\n","import { defineFileLinks } from '@agimon-ai/po-core/web';\n\nimport { artifactTab } from '../_components/ArtifactPreviewPanel';\nimport { artifacts } from '../_lib/artifactsStore';\nimport { temporaryFileReference } from '../_lib/temporaryFiles';\n\n/** Artifacts offered for one `@`, newest first; the workspace's own files follow them. */\nconst MENTION_LIMIT = 5;\n\n/** Artifact references belong to the session store, never the repository file API. */\nexport default defineFileLinks({\n subscribe(listener) {\n const subscription = artifacts.store.subscribe(listener);\n return () => subscription.unsubscribe();\n },\n fingerprint: (sessionId) => artifacts.select(artifacts.store.state, sessionId).temporaryRoot ?? '',\n resolve(sessionId, path) {\n const reference = path.trim();\n if (sessionId === null) return undefined;\n const temporary = temporaryFileReference(\n reference,\n artifacts.select(artifacts.store.state, sessionId).temporaryRoot,\n );\n if (temporary) return artifactTab(sessionId, temporary, 'temporary');\n if (!reference.startsWith('artifact:')) return undefined;\n const relative = reference.slice('artifact:'.length);\n return relative === '' ? undefined : artifactTab(sessionId, relative);\n },\n mentions(sessionId, query) {\n const needle = query.toLowerCase();\n return artifacts\n .select(artifacts.store.state, sessionId)\n .items.map((item) => `artifact:${item.path}`)\n .filter((reference) => reference.toLowerCase().includes(needle))\n .slice(0, MENTION_LIMIT)\n .map((path) => ({ path, detail: 'Artifact' }));\n },\n});\n","// Generated by @agimon-ai/po-build. Do not edit by hand.\nimport { defineWebPlugin, type WebPluginContributions } from '@agimon-ai/po-core/web';\n\nimport channelArtifacts from '../src/extensions/workspaces/sessions/(frontend)/channel/artifacts.web';\nimport dockArtifacts from '../src/extensions/workspaces/sessions/(frontend)/dock/artifacts.web';\nimport fileLinksArtifacts from '../src/extensions/workspaces/sessions/(frontend)/file-links/artifacts.web';\n\nconst via = <T>(identity: Record<string, unknown>, value: unknown): T =>\n (value === undefined ? undefined : { ...identity, ...(value as object) }) as T;\n\nexport const webPlugin = defineWebPlugin({\n id: 'artifacts',\n session: {\n get channels(): WebPluginContributions['channels'] { return [via({ channel: 'artifacts' }, channelArtifacts)]; },\n get dockFaces(): WebPluginContributions['dockFaces'] { return [via({ id: 'artifacts' }, dockArtifacts)]; },\n get fileLinks(): WebPluginContributions['fileLinks'] { return fileLinksArtifacts; },\n },\n});\n"],"mappings":"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"}
1
+ {"version":3,"file":"web.mjs","names":["channelArtifacts","dockArtifacts","fileLinksArtifacts"],"sources":["../../src/types/artifacts.ts","../../src/constants/artifacts.ts","../../src/extensions/workspaces/sessions/(frontend)/_lib/artifactView.ts","../../src/extensions/workspaces/sessions/(frontend)/_lib/artifactsStore.ts","../../src/extensions/workspaces/sessions/(frontend)/channel/artifacts.web.ts","../../src/types/apiRoutes.ts","../../generated/client.ts","../../src/extensions/workspaces/sessions/(frontend)/_lib/artifactsApi.ts","../../src/extensions/workspaces/sessions/(frontend)/_lib/authorSourceAction.ts","../../src/extensions/workspaces/sessions/(frontend)/_components/ArtifactPreviewView.tsx","../../src/extensions/workspaces/sessions/(frontend)/_components/ArtifactPreviewPanel.tsx","../../src/extensions/workspaces/sessions/(frontend)/_components/ArtifactsPanel.tsx","../../src/extensions/workspaces/sessions/(frontend)/_components/ArtifactsRailView.tsx","../../src/extensions/workspaces/sessions/(frontend)/_components/ArtifactsFace.tsx","../../src/extensions/workspaces/sessions/(frontend)/dock/artifacts.web.tsx","../../src/extensions/workspaces/sessions/(frontend)/_lib/temporaryFiles.ts","../../src/extensions/workspaces/sessions/(frontend)/file-links/artifacts.web.ts","../../generated/web.ts"],"sourcesContent":["export type ArtifactScope = 'artifacts' | 'temporary';\n\n/** Workflow owns the visibility of its reserved artifact subtree. */\nexport type ArtifactWorkflowVisibility = (relativePath: string, kind: 'file' | 'directory') => boolean;\n\nexport interface ArtifactItem {\n /** Relative to the current session's artifact directory. */\n path: string;\n name: string;\n size: number;\n modifiedAt: number;\n}\n\nexport interface ArtifactSnapshot {\n items: ArtifactItem[];\n /** Host-admitted root used only to recognize session temporary-file references. */\n temporaryRoot?: string;\n error?: string;\n}\n\nexport interface ArtifactPreview {\n path: string;\n content: string;\n mimeType: string;\n unavailable?: boolean;\n reason?: string;\n}\n\nexport const artifactsChannelType = 'artifacts';\n","export const ARTIFACT_DIRECTORY = 'po-artifacts';\nexport const ARTIFACTS_SERVICE = 'po/artifacts';\nexport const WORKFLOW_ARTIFACT_DIRECTORY = 'workflow';\n/** Autocompact mirrors compaction history here; the recent-artifacts card leaves it out. */\nexport const COMPACTION_ARTIFACT_DIRECTORY = 'compaction';\nexport const MAX_PREVIEW_BYTES = 1024 * 1024;\nexport const MAX_CONTENT_BYTES = 25 * 1024 * 1024;\n/** Videos up to this size are served, but only through range requests of at most MAX_CONTENT_BYTES. */\nexport const MAX_RANGED_VIDEO_BYTES = 128 * 1024 * 1024;\nexport const ARTIFACT_REFRESH_MS = 2000;\n\nexport const ARTIFACT_CONTENT_TYPES: Readonly<Record<string, string>> = {\n '.avif': 'image/avif',\n '.bmp': 'image/bmp',\n '.gif': 'image/gif',\n '.jpeg': 'image/jpeg',\n '.jpg': 'image/jpeg',\n '.png': 'image/png',\n '.svg': 'image/svg+xml',\n '.webp': 'image/webp',\n '.ico': 'image/vnd.microsoft.icon',\n '.mp3': 'audio/mpeg',\n '.wav': 'audio/wav',\n '.m4a': 'audio/mp4',\n '.ogg': 'audio/ogg',\n '.m4v': 'video/mp4',\n '.mov': 'video/quicktime',\n '.mp4': 'video/mp4',\n '.webm': 'video/webm',\n '.pdf': 'application/pdf',\n '.md': 'text/markdown; charset=utf-8',\n '.markdown': 'text/markdown; charset=utf-8',\n '.txt': 'text/plain; charset=utf-8',\n '.html': 'text/html; charset=utf-8',\n '.htm': 'text/html; charset=utf-8',\n};\n","import { COMPACTION_ARTIFACT_DIRECTORY } from '../../../../../constants/artifacts';\nimport type { ArtifactItem, ArtifactSnapshot } from '../../../../../types/artifacts';\n\nexport type ArtifactLayout = 'tree' | 'list' | 'grid';\nexport type ArtifactKind = 'Markdown' | 'Image' | 'Code' | 'Data' | 'Document' | 'Other';\nexport type ArtifactModified = 'any' | 'today' | '7days' | '30days';\nexport type ArtifactSort = 'name' | 'size' | 'modified';\nexport type ArtifactSortDirection = 'asc' | 'desc';\n\nexport interface ArtifactFilters {\n query?: string;\n type?: ArtifactKind | 'any';\n modified?: ArtifactModified;\n}\n\nexport function isArtifactLayout(value: unknown): value is ArtifactLayout {\n return value === 'tree' || value === 'list' || value === 'grid';\n}\n\nexport function artifactKind(path: string): ArtifactKind {\n if (/\\.(?:md|markdown)$/iu.test(path)) return 'Markdown';\n if (/\\.(?:png|jpe?g|gif|webp|avif|bmp|svg|ico|tiff?)$/iu.test(path)) return 'Image';\n if (/\\.(?:jsonl?|csv|tsv|ya?ml|xml|toml|parquet|sqlite|db)$/iu.test(path)) return 'Data';\n if (\n /\\.(?:[cm]?[jt]sx?|html?|css|scss|sass|less|py|sh|bash|go|rs|rb|java|c|cpp|cc|h|hpp|sql|swift|kt|kts|php|vue|svelte)$/iu.test(\n path,\n )\n )\n return 'Code';\n if (/\\.(?:pdf|txt|rtf|docx?|xlsx?|pptx?|odt|ods|odp)$/iu.test(path)) return 'Document';\n return 'Other';\n}\n\n/** Time is supplied by the caller. Today starts at local midnight; day windows are inclusive. */\nexport function filterArtifacts(items: readonly ArtifactItem[], filters: ArtifactFilters, now: number): ArtifactItem[] {\n const query = (filters.query ?? '').trim().toLowerCase();\n const modified = filters.modified ?? 'any';\n const day = 24 * 60 * 60 * 1000;\n const midnight = new Date(now);\n midnight.setHours(0, 0, 0, 0);\n const since = modified === 'today' ? midnight.getTime() : now - (modified === '7days' ? 7 : 30) * day;\n return items.filter(\n (item) =>\n item.path.toLowerCase().includes(query) &&\n (!filters.type || filters.type === 'any' || artifactKind(item.path) === filters.type) &&\n (modified === 'any' || (item.modifiedAt >= since && item.modifiedAt <= now)),\n );\n}\n\n/** Sort a copy, with an ascending full-path tie breaker in either direction. */\nexport function sortArtifacts(\n items: readonly ArtifactItem[],\n sort: ArtifactSort,\n direction: ArtifactSortDirection,\n): ArtifactItem[] {\n return [...items].sort((left, right) => {\n const order =\n sort === 'name'\n ? comparePaths(left.name.toLowerCase(), right.name.toLowerCase())\n : sort === 'size'\n ? left.size - right.size\n : left.modifiedAt - right.modifiedAt;\n return order * (direction === 'asc' ? 1 : -1) || comparePaths(left.path, right.path);\n });\n}\n\nfunction comparePaths(left: string, right: string): number {\n return left < right ? -1 : left > right ? 1 : 0;\n}\n\ninterface ArtifactDirectory {\n path: string;\n dirs: Map<string, ArtifactDirectory>;\n files: ArtifactItem[];\n count: number;\n}\n\nexport type ArtifactTreeRow =\n | { kind: 'dir'; path: string; name: string; depth: number; open: boolean; count: number }\n | { kind: 'file'; item: ArtifactItem; depth: number };\n\n/** Derive folders from already filtered, sorted files. Folders precede files and compact single-child chains. */\nexport function artifactTree(items: readonly ArtifactItem[], isOpen: (path: string) => boolean): ArtifactTreeRow[] {\n const root: ArtifactDirectory = { path: '', dirs: new Map(), files: [], count: 0 };\n for (const item of items) {\n let dir = root;\n dir.count++;\n for (const segment of item.path.split('/').slice(0, -1)) {\n let next = dir.dirs.get(segment);\n if (!next) {\n next = { path: dir.path ? `${dir.path}/${segment}` : segment, dirs: new Map(), files: [], count: 0 };\n dir.dirs.set(segment, next);\n }\n dir = next;\n dir.count++;\n }\n dir.files.push(item);\n }\n const rows: ArtifactTreeRow[] = [];\n const walk = (dir: ArtifactDirectory, depth: number): void => {\n for (const [segment, child] of [...dir.dirs].sort(([left], [right]) => comparePaths(left, right))) {\n let name = segment;\n let node = child;\n while (node.files.length === 0 && node.dirs.size === 1) {\n const [[nextName, next]] = [...node.dirs] as [[string, ArtifactDirectory]];\n name = `${name}/${nextName}`;\n node = next;\n }\n const open = isOpen(node.path);\n rows.push({ kind: 'dir', path: node.path, name, depth, open, count: node.count });\n if (open) walk(node, depth + 1);\n }\n for (const item of dir.files) rows.push({ kind: 'file', item, depth });\n };\n walk(root, 0);\n return rows;\n}\n\n/** `Modified today` on the same calendar day, otherwise the short date. */\nexport function modifiedLabel(modifiedAt: number, now: number): string {\n const date = new Date(modifiedAt);\n return date.toDateString() === new Date(now).toDateString()\n ? 'Modified today'\n : `Modified ${date.toLocaleDateString('en-US', { month: 'short', day: 'numeric' })}`;\n}\n\n/** What the person has seen: New (never opened), Edited (changed since opened), or Viewed. */\nexport type ArtifactStatus = 'new' | 'edited' | 'viewed';\n\n/** One session's seen record in this browser. */\nexport interface ArtifactSeenRecord {\n /** Newest server mtime when this browser first saw the session; older unopened files count as seen. */\n baseline: number;\n /** The mtime each file had when the person last opened it. */\n seen: Readonly<Record<string, number>>;\n}\n\nexport function artifactStatus(item: ArtifactItem, record: ArtifactSeenRecord | undefined): ArtifactStatus {\n if (record === undefined) return 'viewed';\n const seen = record.seen[item.path];\n if (seen !== undefined) return item.modifiedAt > seen ? 'edited' : 'viewed';\n return item.modifiedAt > record.baseline ? 'new' : 'viewed';\n}\n\n/** The web rail has no List layout; a stored `list` (shared with native) reads as Tree there. */\nexport type ArtifactRailLayout = 'tree' | 'grid';\nexport type ArtifactStatusFilter = 'all' | ArtifactStatus;\nexport type ArtifactLocation = 'artifacts' | 'temporary';\n\nexport interface ArtifactRailFilters {\n status: ArtifactStatusFilter;\n type: ArtifactKind | 'any';\n modified: ArtifactModified;\n location: ArtifactLocation;\n}\n\nexport const DEFAULT_ARTIFACT_RAIL_FILTERS: ArtifactRailFilters = {\n status: 'all',\n type: 'any',\n modified: 'any',\n location: 'artifacts',\n};\n\n/** Compact age for a narrow row: `now`, `5m`, `3h`, `2d`, then the short date. */\nexport function ageLabel(modifiedAt: number, now: number): string {\n const minutes = Math.floor(Math.max(0, now - modifiedAt) / 60000);\n if (minutes < 1) return 'now';\n if (minutes < 60) return `${minutes}m`;\n if (minutes < 60 * 24) return `${Math.floor(minutes / 60)}h`;\n if (minutes < 60 * 24 * 7) return `${Math.floor(minutes / (60 * 24))}d`;\n return new Date(modifiedAt).toLocaleDateString('en-US', { month: 'short', day: 'numeric' });\n}\nexport function sizeLabel(size: number): string {\n return size < 1024\n ? `${size} B`\n : size < 1024 * 1024\n ? `${Math.ceil(size / 1024)} KB`\n : `${(size / (1024 * 1024)).toFixed(1)} MB`;\n}\n\nexport function sortedArtifacts(items: readonly ArtifactItem[]): ArtifactItem[] {\n return [...items].sort(\n (left, right) =>\n right.modifiedAt - left.modifiedAt || (left.path < right.path ? -1 : left.path > right.path ? 1 : 0),\n );\n}\n\n/** The recent card shows the person's documents; compaction history stays in the full grid. */\nexport function recentArtifacts(items: readonly ArtifactItem[]): ArtifactItem[] {\n return sortedArtifacts(items.filter((item) => !item.path.startsWith(`${COMPACTION_ARTIFACT_DIRECTORY}/`))).slice(\n 0,\n 3,\n );\n}\n\nexport function artifactTabId(sessionId: string, path: string): string {\n return `artifact:${encodeURIComponent(sessionId)}:${encodeURIComponent(path)}`;\n}\n\n/** Resolves document assets within the artifact folder, never into another filesystem root. */\nexport function artifactAssetPath(documentPath: string, imagePath: string): string {\n if (!imagePath || imagePath.startsWith('/') || imagePath.includes('\\\\') || /^[a-z][a-z0-9+.-]*:/iu.test(imagePath))\n throw new Error('Artifact images must use a relative path.');\n const segments = documentPath.split('/').slice(0, -1);\n for (const segment of imagePath.split('/')) {\n if (segment === '' || segment === '.') continue;\n if (segment === '..') {\n if (segments.length === 0) throw new Error('The image is outside this artifact folder.');\n segments.pop();\n } else segments.push(segment);\n }\n if (segments.length === 0) throw new Error('The image path is empty.');\n return segments.join('/');\n}\n\nexport function artifactPreviewMode(path: string): 'markdown' | 'html' | 'media' | 'code' | 'text' {\n if (/\\.(?:png|jpe?g|gif|webp|avif|bmp|svg|ico|mp3|wav|m4a|ogg|mp4|mov|webm|pdf)$/iu.test(path)) return 'media';\n if (/\\.(?:md|markdown)$/iu.test(path)) return 'markdown';\n if (/\\.html?$/iu.test(path)) return 'html';\n if (/\\.(?:[cm]?[jt]sx?|json|ya?ml|css|scss|py|sh|bash|go|rs|rb|java|c|cpp|h|sql|xml|toml)$/iu.test(path))\n return 'code';\n return 'text';\n}\n\n/** A malformed channel frame must not replace the current session's known inventory. */\nexport function parseArtifactSnapshot(input: unknown): ArtifactSnapshot | null {\n if (typeof input !== 'object' || input === null || !('items' in input) || !Array.isArray(input.items)) return null;\n if ('error' in input && input.error !== undefined && typeof input.error !== 'string') return null;\n const items: ArtifactItem[] = [];\n for (const item of input.items) {\n if (\n typeof item !== 'object' ||\n item === null ||\n typeof item.path !== 'string' ||\n !item.path ||\n item.path.startsWith('/') ||\n item.path.includes('\\\\') ||\n item.path.split('/').some((part: string) => part === '..' || part === '.') ||\n typeof item.name !== 'string' ||\n !item.name ||\n typeof item.size !== 'number' ||\n !Number.isFinite(item.size) ||\n item.size < 0 ||\n typeof item.modifiedAt !== 'number' ||\n !Number.isFinite(item.modifiedAt) ||\n item.modifiedAt < 0\n )\n return null;\n items.push({ path: item.path, name: item.name, size: item.size, modifiedAt: item.modifiedAt });\n }\n return {\n items: sortedArtifacts(items),\n ...('temporaryRoot' in input && typeof input.temporaryRoot === 'string'\n ? { temporaryRoot: input.temporaryRoot }\n : {}),\n ...('error' in input && typeof input.error === 'string' ? { error: input.error } : {}),\n };\n}\n","import { defineGlobalStore, defineSessionStore } from '@agimon-ai/po-core/web';\n\nimport { artifactsChannelType, type ArtifactItem, type ArtifactSnapshot } from '../../../../../types/artifacts';\nimport {\n artifactStatus,\n DEFAULT_ARTIFACT_RAIL_FILTERS,\n isArtifactLayout,\n parseArtifactSnapshot,\n type ArtifactLayout,\n type ArtifactRailFilters,\n type ArtifactSeenRecord,\n type ArtifactSort,\n type ArtifactSortDirection,\n} from './artifactView';\n\nexport const artifacts = defineSessionStore<ArtifactSnapshot & { loaded: boolean }>({ items: [], loaded: false });\n\nexport const artifactsChannel = artifacts.channel<ArtifactSnapshot>({\n channel: artifactsChannelType,\n parse: parseArtifactSnapshot,\n reduce: (_current, snapshot) => ({ ...snapshot, loaded: true }),\n});\n\nconst LAYOUT_KEY = 'po.artifacts.layout.v1';\n\nexport function readArtifactLayout(): ArtifactLayout {\n try {\n const value = globalThis.localStorage.getItem(LAYOUT_KEY);\n return isArtifactLayout(value) ? value : 'tree';\n } catch {\n return 'tree';\n }\n}\n\nexport const artifactLayout = defineGlobalStore<ArtifactLayout>(readArtifactLayout());\n\nexport function setArtifactLayout(layout: ArtifactLayout): void {\n artifactLayout.update(() => layout);\n try {\n globalThis.localStorage.setItem(LAYOUT_KEY, layout);\n } catch {\n // A blocked or full store only loses the preference after this page closes.\n }\n}\n\n/** Sessions remembered per browser record; the stalest session is forgotten first. */\nconst SESSION_LIMIT = 50;\nconst SEEN_KEY = 'po.artifacts.seen.v1';\nconst BROWSE_KEY = 'po.artifacts.browse.v1';\n/** Files remembered per session; the earliest opened is forgotten first and then reads by the baseline. */\nconst SEEN_PATH_LIMIT = 1000;\nconst EXPANDED_LIMIT = 200;\n\ntype SessionRecords<T> = Readonly<Record<string, T>>;\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n\nfunction readSessions<T>(key: string, parse: (value: unknown) => T | undefined): SessionRecords<T> {\n try {\n const stored: unknown = JSON.parse(globalThis.localStorage.getItem(key) ?? '{}');\n if (!isRecord(stored)) return {};\n return Object.fromEntries(\n Object.entries(stored).flatMap(([sessionId, value]) => {\n const parsed = parse(value);\n return parsed === undefined ? [] : [[sessionId, parsed] as const];\n }),\n );\n } catch {\n return {};\n }\n}\n\n/** Moves the session to the newest end so the cap drops the stalest one. */\nfunction withSession<T>(records: SessionRecords<T>, sessionId: string, value: T): SessionRecords<T> {\n return Object.fromEntries(\n [...Object.entries(records).filter(([id]) => id !== sessionId), [sessionId, value] as const].slice(-SESSION_LIMIT),\n );\n}\n\nfunction save(key: string, records: SessionRecords<unknown>): void {\n try {\n globalThis.localStorage.setItem(key, JSON.stringify(records));\n } catch {\n // A blocked or full store keeps the record for this page only.\n }\n}\n\nfunction parseSeen(value: unknown): ArtifactSeenRecord | undefined {\n if (!isRecord(value) || typeof value.baseline !== 'number' || !isRecord(value.seen)) return undefined;\n const seen = Object.fromEntries(\n Object.entries(value.seen).filter((entry): entry is [string, number] => typeof entry[1] === 'number'),\n );\n return { baseline: value.baseline, seen };\n}\n\n/**\n * What the person has seen, per session, in this browser.\n *\n * ponytail: \"viewed\" means opened from the Artifacts face or from an artifact\n * link that opens Po's own preview. An Author tab opened from a transcript link\n * and returning to an already open tab are not recorded. Add a host \"tab\n * opened\" hook if people notice.\n */\nexport const artifactSeen = defineGlobalStore<SessionRecords<ArtifactSeenRecord>>(readSessions(SEEN_KEY, parseSeen));\n\n/** The baseline for a session seen for the first time: files already listed count as seen. */\nfunction firstRecord(sessionId: string): ArtifactSeenRecord | undefined {\n const snapshot = artifacts.select(artifacts.store.state, sessionId);\n if (!snapshot.loaded || snapshot.error !== undefined) return undefined;\n return { baseline: Math.max(0, ...snapshot.items.map((item) => item.modifiedAt)), seen: {} };\n}\n\nfunction updateSeen(sessionId: string, update: (record: ArtifactSeenRecord) => ArtifactSeenRecord): void {\n const current = artifactSeen.store.state[sessionId] ?? firstRecord(sessionId);\n // Nothing to compare against until the session's list arrives; the seed records the baseline then.\n if (current === undefined) return;\n const next = update(current);\n if (next === current) return;\n artifactSeen.update((records) => withSession(records, sessionId, next));\n save(SEEN_KEY, artifactSeen.store.state);\n}\n\nexport function markArtifactViewed(sessionId: string, item: Pick<ArtifactItem, 'path' | 'modifiedAt'>): void {\n updateSeen(sessionId, (record) => {\n if (record.seen[item.path] === item.modifiedAt) return record;\n const others = Object.entries(record.seen).filter(([path]) => path !== item.path);\n const entries = [...others, [item.path, item.modifiedAt] as const].slice(-SEEN_PATH_LIMIT);\n return { ...record, seen: Object.fromEntries(entries) };\n });\n}\n\n/** Everything listed now counts as seen; anything newer than the newest file reads as New again. */\nexport function markAllArtifactsViewed(sessionId: string, items: readonly ArtifactItem[]): void {\n updateSeen(sessionId, () => ({\n baseline: Math.max(0, ...items.map((item) => item.modifiedAt)),\n seen: {},\n }));\n}\n\n/** Files the person has not opened yet or that changed since: New plus Edited. */\nexport function unviewedArtifactCount(sessionId: string | null): number {\n if (sessionId === null) return 0;\n const record = artifactSeen.store.state[sessionId];\n return artifacts\n .select(artifacts.store.state, sessionId)\n .items.filter((item) => artifactStatus(item, record) !== 'viewed').length;\n}\n\n/**\n * The first list this browser receives for a session sets its baseline: files\n * already there count as seen, so an old session opens calm instead of every\n * file reading New. Runs from the store, not the face, so a batch Po makes\n * before the person opens the Artifacts face still reads New.\n */\nfunction seedBaselines(): void {\n for (const sessionId of Object.keys(artifacts.store.state)) {\n if (artifactSeen.store.state[sessionId] !== undefined) continue;\n const record = firstRecord(sessionId);\n if (record !== undefined) updateSeen(sessionId, () => record);\n }\n}\nartifacts.store.subscribe(seedBaselines);\n\n/** Where the person left the Artifacts face, per session. The search text is not saved across reloads. */\nexport interface ArtifactBrowseState {\n filters: ArtifactRailFilters;\n sort: ArtifactSort;\n direction: ArtifactSortDirection;\n expanded: readonly string[];\n /** The file last opened from the face, kept highlighted. */\n openPath?: string;\n query: string;\n searchOpen: boolean;\n}\n\nexport const DEFAULT_ARTIFACT_BROWSE: ArtifactBrowseState = {\n filters: DEFAULT_ARTIFACT_RAIL_FILTERS,\n sort: 'modified',\n direction: 'desc',\n expanded: [],\n query: '',\n searchOpen: false,\n};\n\nfunction oneOf<T extends string>(value: unknown, options: readonly T[], fallback: T): T {\n return options.includes(value as T) ? (value as T) : fallback;\n}\n\nfunction parseBrowse(value: unknown): ArtifactBrowseState | undefined {\n if (!isRecord(value)) return undefined;\n const filters = isRecord(value.filters) ? value.filters : {};\n return {\n filters: {\n status: oneOf(filters.status, ['all', 'new', 'edited', 'viewed'], 'all'),\n type: oneOf(filters.type, ['any', 'Markdown', 'Image', 'Code', 'Data', 'Document', 'Other'], 'any'),\n modified: oneOf(filters.modified, ['any', 'today', '7days', '30days'], 'any'),\n location: oneOf(filters.location, ['artifacts', 'temporary'], 'artifacts'),\n },\n sort: oneOf(value.sort, ['name', 'size', 'modified'], 'modified'),\n direction: oneOf(value.direction, ['asc', 'desc'], 'desc'),\n expanded: Array.isArray(value.expanded)\n ? value.expanded.filter((path): path is string => typeof path === 'string').slice(0, EXPANDED_LIMIT)\n : [],\n ...(typeof value.openPath === 'string' ? { openPath: value.openPath } : {}),\n query: '',\n searchOpen: false,\n };\n}\n\nexport const artifactBrowse = defineGlobalStore<SessionRecords<ArtifactBrowseState>>(\n readSessions(BROWSE_KEY, parseBrowse),\n);\n\nexport function updateArtifactBrowse(\n sessionId: string,\n update: (state: ArtifactBrowseState) => ArtifactBrowseState,\n): void {\n const next = update(artifactBrowse.store.state[sessionId] ?? DEFAULT_ARTIFACT_BROWSE);\n artifactBrowse.update((records) => withSession(records, sessionId, next));\n // The query lives for the page only: a search that hides files after a reload reads as missing files.\n save(\n BROWSE_KEY,\n Object.fromEntries(\n Object.entries(artifactBrowse.store.state).map(([id, state]) => [\n id,\n { ...state, query: '', searchOpen: false, expanded: state.expanded.slice(0, EXPANDED_LIMIT) },\n ]),\n ),\n );\n}\n","import { defineChannelFile } from '@agimon-ai/po-core/web';\n\nimport { artifactsChannel } from '../_lib/artifactsStore';\nexport default defineChannelFile(artifactsChannel);\n","import type { ApiResponseOf, ApiRoutes } from '@agimon-ai/po-core/web';\n\nimport type { ArtifactPreview, ArtifactSnapshot } from './artifacts';\n\nconst routes = {\n list: {\n method: 'GET',\n path: '/',\n query: ['scope'],\n response: undefined as unknown as ApiResponseOf<ArtifactSnapshot>,\n },\n preview: {\n method: 'GET',\n path: '/preview',\n query: ['path', 'scope'],\n response: undefined as unknown as ApiResponseOf<ArtifactPreview>,\n },\n content: {\n method: 'GET',\n path: '/content',\n query: ['path', 'scope'],\n raw: true,\n },\n} as const satisfies ApiRoutes;\n\nexport default routes;\n","// Generated by @agimon-ai/po-build. Do not edit by hand.\nimport { createApiClient, sessionApiAddress } from '@agimon-ai/po-core/web';\nimport { browserTransport } from '@agimon-ai/po-web-security/browser';\n\nimport routes from '../src/types/apiRoutes';\n\n/** Scopes the tree mounts 'artifacts' at. */\nexport const apiScopes = ['session'] as const;\n\nexport const api = createApiClient(routes, {\n scopes: apiScopes,\n basePath: 'artifacts',\n transport: (input, init) => browserTransport.fetch(input, init),\n sessionAddress: sessionApiAddress,\n});\n","import { api } from '../../../../../../generated/client';\nimport { MAX_CONTENT_BYTES, MAX_RANGED_VIDEO_BYTES } from '../../../../../constants/artifacts';\nimport type { ArtifactPreview, ArtifactScope, ArtifactSnapshot } from '../../../../../types/artifacts';\nimport { artifacts } from './artifactsStore';\nimport { artifactAssetPath, parseArtifactSnapshot } from './artifactView';\n\nexport async function refreshArtifacts(sessionId: string, signal: AbortSignal): Promise<void> {\n const before = artifacts.select(artifacts.store.state, sessionId);\n try {\n const result = await api.session(sessionId).list({ signal });\n if (signal.aborted || artifacts.select(artifacts.store.state, sessionId) !== before) return;\n const snapshot = result.ok ? parseArtifactSnapshot(result.data) : null;\n artifacts.update(sessionId, () =>\n snapshot\n ? { ...snapshot, loaded: true }\n : {\n ...before,\n loaded: true,\n error: result.ok\n ? 'The session answered with no artifact list.'\n : result.error || 'Artifacts could not be loaded.',\n },\n );\n } catch (error) {\n if (!signal.aborted && artifacts.select(artifacts.store.state, sessionId) === before)\n artifacts.update(sessionId, () => ({\n ...before,\n loaded: true,\n error: error instanceof Error ? error.message : String(error),\n }));\n }\n}\n\nexport async function fetchArtifacts(\n sessionId: string,\n signal: AbortSignal,\n scope: ArtifactScope = 'artifacts',\n): Promise<ArtifactSnapshot> {\n const result = await api.session(sessionId).list({ ...(scope === 'temporary' ? { query: { scope } } : {}), signal });\n if (!result.ok) throw new Error(result.error || 'Files could not be loaded.');\n const snapshot = parseArtifactSnapshot(result.data);\n if (!snapshot) throw new Error('The session returned an invalid file list.');\n return snapshot;\n}\n\nexport async function fetchArtifactPreview(\n sessionId: string,\n path: string,\n signal: AbortSignal,\n scope: ArtifactScope = 'artifacts',\n): Promise<ArtifactPreview> {\n const result = await api\n .session(sessionId)\n .preview({ query: { path, ...(scope === 'temporary' ? { scope } : {}) }, signal });\n if (!result.ok) throw new Error(result.error || 'This artifact could not be read.');\n const preview = result.data;\n if (\n !preview ||\n typeof preview.path !== 'string' ||\n typeof preview.content !== 'string' ||\n typeof preview.mimeType !== 'string'\n )\n throw new Error('The session answered with no artifact.');\n return preview;\n}\n\n/** Generated raw calls keep media and Markdown asset reads on the sealed artifact transport. */\nexport async function artifactBlob(\n sessionId: string,\n path: string,\n signal?: AbortSignal,\n scope: ArtifactScope = 'artifacts',\n): Promise<Blob> {\n const session = api.session(sessionId);\n const query = { path, ...(scope === 'temporary' ? { scope } : {}) };\n const result = await session.content({ query, ...(signal ? { signal } : {}) });\n if (result.ok) return result.response.blob();\n if (result.status !== 413) throw new Error(result.error || 'This artifact could not be loaded.');\n // Videos past the download cap are served only in bounded ranges of one version of the file.\n const parts: Blob[] = [];\n let offset = 0;\n let size = 1;\n let version: string | undefined;\n let type = '';\n while (offset < size) {\n const part = await session.content({\n query,\n headers: {\n range: `bytes=${offset}-${offset + MAX_CONTENT_BYTES - 1}`,\n ...(version ? { 'if-match': version } : {}),\n },\n ...(signal ? { signal } : {}),\n });\n const match = part.ok ? /^bytes (\\d+)-(\\d+)\\/(\\d+)$/u.exec(part.response.headers.get('content-range') ?? '') : null;\n if (!part.ok || part.status !== 206 || !match || Number(match[1]) !== offset)\n throw new Error(\n part.ok ? 'This artifact changed while loading.' : part.error || 'This artifact could not be loaded.',\n );\n size = Number(match[3]);\n if (size > MAX_RANGED_VIDEO_BYTES) throw new Error('This artifact is too large to load.');\n version ??= part.response.headers.get('etag') ?? undefined;\n type ||= part.response.headers.get('content-type') ?? '';\n const blob = await part.response.blob();\n if (blob.size !== Number(match[2]) - offset + 1) throw new Error('This artifact changed while loading.');\n parts.push(blob);\n offset += blob.size;\n }\n return new Blob(parts, { type });\n}\n\nexport async function loadArtifactImage(\n sessionId: string,\n documentPath: string,\n imagePath: string,\n scope: ArtifactScope = 'artifacts',\n) {\n const path = artifactAssetPath(documentPath, imagePath);\n const blob = await artifactBlob(sessionId, path, undefined, scope);\n if (!blob.type.startsWith('image/')) throw new Error('This artifact asset is not an image.');\n const url = URL.createObjectURL(blob);\n return { url, dispose: () => URL.revokeObjectURL(url), path };\n}\n","import type { SlotDeclaration, TransientTab, WebPluginSlotProps } from '@agimon-ai/po-core/web';\n\n/**\n * Author's `author.open-source` slot, declared by duck type. A web plugin can't\n * import another feature package, so this mirrors po-browse's local copy.\n */\ninterface AuthorSourceAction {\n version: 1;\n createTab(input: { sessionId: string; path: string }): TransientTab;\n}\n\nexport const authorSourceActionSlot: SlotDeclaration<AuthorSourceAction> = {\n slot: 'author.open-source',\n parse(input) {\n if (typeof input !== 'object' || input === null) return null;\n const action = input as Partial<AuthorSourceAction>;\n return action.version === 1 && typeof action.createTab === 'function' ? (action as AuthorSourceAction) : null;\n },\n};\n\n/** Author's open action when the installed plugin contributes it. */\nexport function authorSourceAction(props: WebPluginSlotProps): AuthorSourceAction | undefined {\n return props.sessionId !== null ? props.slotData?.(authorSourceActionSlot)?.[0]?.data : undefined;\n}\n","import { Breadcrumb, CodeEditor, Markdown, type MarkdownMediaReview } from '@agimon-ai/po-web-components';\nimport type { ReactNode } from 'react';\n\nimport type { ArtifactPreview } from '../../../../../types/artifacts';\nimport { artifactPreviewMode } from '../_lib/artifactView';\n\ninterface ArtifactPreviewViewProps {\n path: string;\n preview?: ArtifactPreview;\n error?: string;\n media?: ReactNode;\n loadImage?: (path: string) => Promise<{ url: string; dispose: () => void; path?: string }>;\n /** How the opened picture's provenance names this document to a reviewer. */\n documentPath?: string;\n renderMediaReview?: MarkdownMediaReview;\n}\n\nexport function ArtifactPreviewView({\n path,\n preview,\n error,\n media,\n loadImage,\n documentPath,\n renderMediaReview,\n}: ArtifactPreviewViewProps) {\n const mode = artifactPreviewMode(path);\n return (\n <div\n data-testid=\"artifact-preview\"\n data-artifact-path={path}\n className=\"flex min-h-0 flex-1 flex-col bg-po-bg text-po-text\"\n >\n <header className=\"flex shrink-0 items-center gap-2 border-b border-po-border px-4 py-3\">\n <Breadcrumb path={path} className=\"min-w-0 flex-1\" />\n <span className=\"text-sm text-po-dim\">Artifact</span>\n </header>\n <div className=\"min-h-0 flex-1 overflow-auto p-4\">\n {error ? (\n <p role=\"alert\" className=\"text-sm text-po-red\">\n {error}\n </p>\n ) : !preview ? (\n <p role=\"status\" className=\"text-sm text-po-dim\">\n Reading this artifact...\n </p>\n ) : mode === 'media' ? (\n media\n ) : preview.unavailable ? (\n <p className=\"text-sm text-po-dim\">{preview.reason ?? 'This artifact cannot be previewed.'}</p>\n ) : mode === 'markdown' ? (\n <Markdown\n text={preview.content}\n loadImage={loadImage}\n documentPath={documentPath}\n renderMediaReview={renderMediaReview}\n />\n ) : mode === 'html' ? (\n <iframe\n title={path}\n sandbox=\"\"\n srcDoc={preview.content}\n className=\"h-96 w-full rounded-md border border-po-border bg-po-deep\"\n />\n ) : mode === 'code' ? (\n <CodeEditor\n value={preview.content}\n path={path}\n readOnly\n className=\"min-h-64 rounded-md border border-po-border\"\n />\n ) : (\n <pre className=\"whitespace-pre-wrap break-words font-mono text-sm text-po-text\">{preview.content}</pre>\n )}\n </div>\n </div>\n );\n}\n","import type { TransientTab, WebPluginSlotProps } from '@agimon-ai/po-core/web';\nimport { MediaPreview, markdownMediaReview } from '@agimon-ai/po-web-components';\nimport { useStore } from '@tanstack/react-store';\nimport { useCallback, useEffect, useState } from 'react';\n\nimport type { ArtifactPreview, ArtifactScope } from '../../../../../types/artifacts';\nimport { artifactBlob, fetchArtifactPreview, loadArtifactImage } from '../_lib/artifactsApi';\nimport { artifacts, markArtifactViewed } from '../_lib/artifactsStore';\nimport { artifactTabId } from '../_lib/artifactView';\nimport { ArtifactPreviewView } from './ArtifactPreviewView';\n\nfunction ArtifactMedia({\n sessionId,\n path,\n revision,\n scope,\n}: {\n sessionId: string;\n path: string;\n revision: string;\n scope: ArtifactScope;\n}) {\n const [loaded, setLoaded] = useState<{ source: string; url?: string; mimeType?: string; error?: string }>();\n const source = `${scope}:${sessionId}:${path}:${revision}`;\n useEffect(() => {\n const controller = new AbortController();\n let url: string | undefined;\n void artifactBlob(sessionId, path, controller.signal, scope)\n .then((blob) => {\n if (controller.signal.aborted) return;\n url = URL.createObjectURL(blob);\n setLoaded({ source, url, mimeType: blob.type });\n })\n .catch((error: unknown) => {\n if (!controller.signal.aborted)\n setLoaded({ source, error: error instanceof Error ? error.message : String(error) });\n });\n return () => {\n controller.abort();\n if (url !== undefined) URL.revokeObjectURL(url);\n };\n }, [sessionId, path, source, scope]);\n const current = loaded?.source === source ? loaded : undefined;\n return current?.url ? (\n <MediaPreview src={current.url} path={path} contentType={current.mimeType} />\n ) : (\n <p\n role={current?.error ? 'alert' : 'status'}\n className={current?.error ? 'text-sm text-po-red' : 'text-sm text-po-dim'}\n >\n {current?.error ?? 'Loading artifact media...'}\n </p>\n );\n}\n\n/** Review provenance names artifacts the way Author opens them; a temporary file keeps its plain path. */\nfunction provenance(scope: ArtifactScope, relative: string): string {\n return scope === 'artifacts' ? `artifact:${relative}` : relative;\n}\n\nexport function ArtifactPreviewPanel(props: WebPluginSlotProps & { path: string; scope?: ArtifactScope }) {\n const { path, sessionId, scope = 'artifacts' } = props;\n const snapshot = useStore(artifacts.store, (state) => artifacts.select(state, sessionId));\n const item = snapshot.items.find((candidate) => candidate.path === path);\n const revision =\n scope === 'temporary'\n ? 'temporary'\n : item\n ? `${item.modifiedAt}:${item.size}`\n : snapshot.loaded\n ? 'missing'\n : 'initial';\n const [loaded, setLoaded] = useState<{\n sessionId: string;\n path: string;\n revision: string;\n preview?: ArtifactPreview;\n error?: string;\n }>();\n useEffect(() => {\n if (sessionId === null || revision === 'missing') return;\n const controller = new AbortController();\n void fetchArtifactPreview(sessionId, path, controller.signal, scope)\n .then((preview) => {\n if (!controller.signal.aborted) setLoaded({ sessionId, path, revision, preview });\n })\n .catch((error: unknown) => {\n if (!controller.signal.aborted)\n setLoaded({ sessionId, path, revision, error: error instanceof Error ? error.message : String(error) });\n });\n return () => controller.abort();\n }, [sessionId, path, revision, scope]);\n const current =\n loaded?.sessionId === sessionId && loaded.path === path && loaded.revision === revision ? loaded : undefined;\n const loadImage = useCallback(\n (imagePath: string) => {\n if (sessionId === null) return Promise.reject(new Error('The session is unavailable.'));\n return loadArtifactImage(sessionId, path, imagePath, scope).then((image) => ({\n ...image,\n path: provenance(scope, image.path),\n }));\n },\n [sessionId, path, scope],\n );\n return (\n <ArtifactPreviewView\n path={path}\n preview={current?.preview}\n error={\n sessionId === null\n ? 'The session is unavailable.'\n : revision === 'missing'\n ? 'This artifact no longer exists.'\n : current?.error\n }\n loadImage={loadImage}\n documentPath={provenance(scope, path)}\n renderMediaReview={markdownMediaReview(props)}\n media={\n sessionId === null ? undefined : (\n <ArtifactMedia sessionId={sessionId} path={path} revision={revision} scope={scope} />\n )\n }\n />\n );\n}\n\nexport function artifactTab(sessionId: string, path: string, scope: ArtifactScope = 'artifacts'): TransientTab {\n return {\n id: `${scope === 'temporary' ? 'temporary:' : ''}${artifactTabId(sessionId, path)}`,\n label: path.split('/').at(-1) ?? path,\n panel: (props) => <ArtifactPreviewPanel {...props} sessionId={sessionId} path={path} scope={scope} />,\n // A transcript link to an artifact counts as viewing it; temporary files are not tracked.\n ...(scope === 'artifacts'\n ? {\n onOpen: (owner: string) => {\n const item = artifacts.select(artifacts.store.state, owner).items.find((entry) => entry.path === path);\n if (item !== undefined) markArtifactViewed(owner, item);\n },\n }\n : {}),\n };\n}\n","import type { WebPluginSlotProps } from '@agimon-ai/po-core/web';\nimport { ImageIcon } from '@agimon-ai/po-web-components';\nimport { useStore } from '@tanstack/react-store';\nimport { useEffect, useRef, useState } from 'react';\n\nimport type { ArtifactItem, ArtifactScope, ArtifactSnapshot } from '../../../../../types/artifacts';\nimport { artifactBlob, fetchArtifacts } from '../_lib/artifactsApi';\nimport { artifacts } from '../_lib/artifactsStore';\nimport { authorSourceAction } from '../_lib/authorSourceAction';\nimport { artifactTab } from './ArtifactPreviewPanel';\n\n/** With Author installed, an artifact opens straight in Author's own (read-only) canvas tab. */\nexport function openArtifact(props: WebPluginSlotProps, path: string, scope: ArtifactScope = 'artifacts'): void {\n if (props.sessionId === null) return;\n if (scope === 'temporary') {\n props.openTransientTab(artifactTab(props.sessionId, path, scope));\n return;\n }\n const author = authorSourceAction(props);\n props.openTransientTab(\n author?.createTab({ sessionId: props.sessionId, path: `artifact:${path}` }) ?? artifactTab(props.sessionId, path),\n );\n}\n\n/** Temporary files fetch on open and whenever the artifact channel pushes a snapshot. */\nexport function useTemporaryFiles(sessionId: string | null, enabled: boolean): ArtifactSnapshot | undefined {\n const snapshot = useStore(artifacts.store, (state) => artifacts.select(state, sessionId));\n const [temporary, setTemporary] = useState<ArtifactSnapshot & { sessionId: string }>();\n useEffect(() => {\n if (sessionId === null || !enabled) return;\n const controller = new AbortController();\n const load = async (): Promise<void> => {\n try {\n const result = await fetchArtifacts(sessionId, controller.signal, 'temporary');\n if (!controller.signal.aborted) setTemporary({ ...result, sessionId });\n } catch (error) {\n if (!controller.signal.aborted)\n setTemporary((before) => ({\n sessionId,\n items: before?.sessionId === sessionId ? before.items : [],\n error: error instanceof Error ? error.message : String(error),\n }));\n }\n };\n void load();\n return () => {\n controller.abort();\n };\n }, [sessionId, enabled, snapshot]);\n return temporary?.sessionId === sessionId ? temporary : undefined;\n}\n\n/** No thumbnail request until its image cell intersects the scrolling inventory. */\nexport function ArtifactThumbnail({ sessionId, item }: { sessionId: string; item: ArtifactItem }) {\n const cell = useRef<HTMLSpanElement>(null);\n const [loaded, setLoaded] = useState<{ revision: string; url: string }>();\n const revision = `${sessionId}:${item.path}:${item.modifiedAt}:${item.size}`;\n useEffect(() => {\n const element = cell.current;\n if (!element) return;\n const controller = new AbortController();\n let url: string | undefined;\n const load = () => {\n void artifactBlob(sessionId, item.path, controller.signal)\n .then((blob) => {\n if (controller.signal.aborted || blob.size > 5 * 1024 * 1024 || !blob.type.startsWith('image/')) return;\n url = URL.createObjectURL(blob);\n setLoaded({ revision, url });\n })\n .catch(() => {\n /* The kind icon is the thumbnail fallback. */\n });\n };\n const observer =\n typeof IntersectionObserver === 'undefined'\n ? undefined\n : new IntersectionObserver((entries) => {\n if (entries.some((entry) => entry.isIntersecting)) {\n observer?.disconnect();\n load();\n }\n });\n if (observer) observer.observe(element);\n else load();\n return () => {\n observer?.disconnect();\n controller.abort();\n if (url) URL.revokeObjectURL(url);\n };\n }, [sessionId, item.path, revision]);\n return (\n <span ref={cell} className=\"flex h-full w-full items-center justify-center\">\n {loaded?.revision === revision ? (\n <img src={loaded.url} alt=\"\" className=\"h-full w-full object-cover\" />\n ) : (\n <ImageIcon aria-hidden className=\"size-8\" />\n )}\n </span>\n );\n}\n","import {\n Badge,\n Button,\n ChevronDownIcon,\n ChevronRightIcon,\n Dot,\n DropdownMenu,\n DropdownMenuContent,\n DropdownMenuItem,\n DropdownMenuLabel,\n DropdownMenuRadioGroup,\n DropdownMenuRadioItem,\n DropdownMenuSeparator,\n DropdownMenuShortcut,\n DropdownMenuTrigger,\n EmptyState,\n FileIcon,\n FolderIcon,\n GridIcon,\n ImageIcon,\n Input,\n SearchIcon,\n SlidersIcon,\n tabVariants,\n} from '@agimon-ai/po-web-components';\nimport { useEffect, useRef, type KeyboardEvent, type ReactNode } from 'react';\n\nimport type { ArtifactItem } from '../../../../../types/artifacts';\nimport {\n ageLabel,\n artifactKind,\n artifactTree,\n filterArtifacts,\n sortArtifacts,\n type ArtifactKind,\n type ArtifactModified,\n type ArtifactSort,\n type ArtifactSortDirection,\n type ArtifactLocation,\n type ArtifactRailFilters,\n type ArtifactRailLayout,\n type ArtifactStatus,\n type ArtifactStatusFilter,\n DEFAULT_ARTIFACT_RAIL_FILTERS,\n} from '../_lib/artifactView';\n\nexport interface ArtifactsRailViewProps {\n items: readonly ArtifactItem[];\n loading?: boolean;\n error?: string;\n onRetry?: () => void;\n /** Caller-supplied initial clock, so ages and Modified windows render deterministically. */\n now: number;\n /** New, Edited or Viewed per file. Absent for locations that are not tracked, such as temporary files. */\n statusOf?: (item: ArtifactItem) => ArtifactStatus;\n layout: ArtifactRailLayout;\n onLayoutChange: (layout: ArtifactRailLayout) => void;\n query: string;\n onQueryChange: (query: string) => void;\n searchOpen: boolean;\n onSearchOpenChange: (open: boolean) => void;\n filters: ArtifactRailFilters;\n onFiltersChange: (filters: ArtifactRailFilters) => void;\n sort: ArtifactSort;\n direction: ArtifactSortDirection;\n onSortChange: (sort: ArtifactSort, direction: ArtifactSortDirection) => void;\n expanded: ReadonlySet<string>;\n onToggleFolder: (path: string) => void;\n /** The file showing in the main area, highlighted so the person keeps their place. */\n openPath?: string;\n onOpen: (item: ArtifactItem) => void;\n onMarkAllViewed?: () => void;\n renderThumbnail?: (item: ArtifactItem) => ReactNode;\n /** Story and test seam: render one menu already open. */\n defaultMenuOpen?: 'filter' | 'sort';\n}\n\nconst STATUS_LABELS: Record<ArtifactStatusFilter, string> = {\n all: 'All',\n new: 'New',\n edited: 'Edited',\n viewed: 'Viewed',\n};\nconst TYPE_OPTIONS: readonly (ArtifactKind | 'any')[] = [\n 'any',\n 'Markdown',\n 'Image',\n 'Code',\n 'Data',\n 'Document',\n 'Other',\n];\nconst MODIFIED_LABELS: Record<ArtifactModified, string> = {\n any: 'Any time',\n today: 'Today',\n '7days': 'Past 7 days',\n '30days': 'Past 30 days',\n};\nconst LOCATION_LABELS: Record<ArtifactLocation, string> = { artifacts: 'Artifacts', temporary: 'Temporary files' };\nconst SORT_LABELS = {\n 'modified:desc': 'Recently changed',\n 'modified:asc': 'Oldest first',\n 'name:asc': 'Name A to Z',\n 'name:desc': 'Name Z to A',\n 'size:desc': 'Largest first',\n 'size:asc': 'Smallest first',\n} as const;\ntype SortKey = keyof typeof SORT_LABELS;\n\nfunction StatusMark({ status }: { status: ArtifactStatus | undefined }) {\n if (status === 'new')\n return (\n <Badge tone=\"green\" size=\"xs\" className=\"shrink-0 bg-po-tint-green\">\n New\n </Badge>\n );\n if (status === 'edited')\n return (\n <Badge tone=\"green\" size=\"xs\" className=\"shrink-0\">\n Edited\n </Badge>\n );\n return status === 'viewed' ? <span className=\"sr-only\">, viewed</span> : null;\n}\n\n/** The right-rail Artifacts face: every file, newest first, with what the person has not seen yet. */\nexport function ArtifactsRailView(props: ArtifactsRailViewProps) {\n const {\n items,\n loading,\n error,\n onRetry,\n now,\n statusOf,\n layout,\n onLayoutChange,\n query,\n onQueryChange,\n searchOpen,\n onSearchOpenChange,\n filters,\n onFiltersChange,\n sort,\n direction,\n onSortChange,\n expanded,\n onToggleFolder,\n openPath,\n onOpen,\n onMarkAllViewed,\n renderThumbnail,\n defaultMenuOpen,\n } = props;\n const statuses = new Map(items.map((item) => [item.path, statusOf?.(item)]));\n const newCount = items.filter((item) => statuses.get(item.path) === 'new').length;\n const editedCount = items.filter((item) => statuses.get(item.path) === 'edited').length;\n // The files a set of filters keeps; each filter option counts with the other groups as they are.\n const matching = (choice: ArtifactRailFilters) =>\n filterArtifacts(items, { query, type: choice.type, modified: choice.modified }, now).filter(\n (item) => choice.status === 'all' || statuses.get(item.path) === choice.status,\n );\n const countWith = (change: Partial<ArtifactRailFilters>) => (\n <DropdownMenuShortcut className=\"pl-4 tabular-nums\">\n {matching({ ...filters, ...change }).length}\n </DropdownMenuShortcut>\n );\n const filtered = sortArtifacts(matching(filters), sort, direction);\n const filtering = query !== '' || filters.status !== 'all' || filters.type !== 'any' || filters.modified !== 'any';\n const rows =\n layout === 'tree'\n ? artifactTree(filtered, (path) => filtering || expanded.has(path))\n : filtered.map((item) => ({ kind: 'file' as const, item, depth: 0 }));\n const unviewedUnder = (folder: string) =>\n filtered.filter((item) => item.path.startsWith(`${folder}/`) && statuses.get(item.path) !== 'viewed' && statusOf)\n .length;\n const sortValue = `${sort}:${direction}` as SortKey;\n const clear = () => {\n onQueryChange('');\n onFiltersChange({ ...DEFAULT_ARTIFACT_RAIL_FILTERS, location: filters.location });\n };\n const toggleStatus = (status: ArtifactStatus) =>\n onFiltersChange({ ...filters, status: filters.status === status ? 'all' : status });\n const moveFocus = (event: KeyboardEvent<HTMLButtonElement>) => {\n if (event.key !== 'ArrowDown' && event.key !== 'ArrowUp') return;\n const inventory = event.currentTarget.closest('[data-testid=\"artifacts-grid\"]');\n const buttons = [...(inventory?.querySelectorAll<HTMLButtonElement>('[data-artifact-row]') ?? [])];\n const index = buttons.indexOf(event.currentTarget);\n if (index < 0) return;\n event.preventDefault();\n buttons[Math.max(0, Math.min(buttons.length - 1, index + (event.key === 'ArrowDown' ? 1 : -1)))]?.focus();\n };\n\n return (\n <section\n data-testid=\"artifacts-grid\"\n aria-label=\"Artifacts\"\n className=\"flex min-h-0 flex-1 flex-col bg-po-rail text-po-text\"\n >\n <div role=\"toolbar\" aria-label=\"Artifact view\" className=\"flex shrink-0 items-center gap-1 px-3 pt-3 pb-2\">\n <DropdownMenu defaultOpen={defaultMenuOpen === 'filter'}>\n <DropdownMenuTrigger asChild>\n <Button variant=\"ghost\" size=\"sm\" className=\"text-po-text\">\n <SlidersIcon aria-hidden className=\"size-3.5\" />\n Filter\n {filters.status !== 'all' ||\n filters.type !== 'any' ||\n filters.modified !== 'any' ||\n filters.location !== 'artifacts' ? (\n <Dot tone=\"green\" aria-label=\"Filters on\" />\n ) : null}\n </Button>\n </DropdownMenuTrigger>\n <DropdownMenuContent align=\"start\" className=\"w-56\">\n {statusOf ? (\n <>\n <DropdownMenuLabel>Status</DropdownMenuLabel>\n <DropdownMenuRadioGroup\n value={filters.status}\n onValueChange={(status) => onFiltersChange({ ...filters, status: status as ArtifactStatusFilter })}\n >\n {(Object.keys(STATUS_LABELS) as ArtifactStatusFilter[]).map((status) => (\n <DropdownMenuRadioItem key={status} value={status}>\n {STATUS_LABELS[status]}\n {countWith({ status })}\n </DropdownMenuRadioItem>\n ))}\n </DropdownMenuRadioGroup>\n <DropdownMenuSeparator />\n </>\n ) : null}\n <DropdownMenuLabel>Type</DropdownMenuLabel>\n <DropdownMenuRadioGroup\n value={filters.type}\n onValueChange={(type) => onFiltersChange({ ...filters, type: type as ArtifactKind | 'any' })}\n >\n {TYPE_OPTIONS.map((type) => (\n <DropdownMenuRadioItem key={type} value={type}>\n {type === 'any' ? 'All types' : type}\n {countWith({ type })}\n </DropdownMenuRadioItem>\n ))}\n </DropdownMenuRadioGroup>\n <DropdownMenuSeparator />\n <DropdownMenuLabel>Modified</DropdownMenuLabel>\n <DropdownMenuRadioGroup\n value={filters.modified}\n onValueChange={(modified) => onFiltersChange({ ...filters, modified: modified as ArtifactModified })}\n >\n {(Object.keys(MODIFIED_LABELS) as ArtifactModified[]).map((modified) => (\n <DropdownMenuRadioItem key={modified} value={modified}>\n {MODIFIED_LABELS[modified]}\n {countWith({ modified })}\n </DropdownMenuRadioItem>\n ))}\n </DropdownMenuRadioGroup>\n <DropdownMenuSeparator />\n <DropdownMenuLabel>Location</DropdownMenuLabel>\n <DropdownMenuRadioGroup\n value={filters.location}\n onValueChange={(location) => onFiltersChange({ ...filters, location: location as ArtifactLocation })}\n >\n {(Object.keys(LOCATION_LABELS) as ArtifactLocation[]).map((location) => (\n <DropdownMenuRadioItem key={location} value={location}>\n {LOCATION_LABELS[location]}\n </DropdownMenuRadioItem>\n ))}\n </DropdownMenuRadioGroup>\n {filtering ? (\n <>\n <DropdownMenuSeparator />\n <DropdownMenuItem onSelect={clear}>Reset filters</DropdownMenuItem>\n </>\n ) : null}\n </DropdownMenuContent>\n </DropdownMenu>\n <DropdownMenu defaultOpen={defaultMenuOpen === 'sort'}>\n <DropdownMenuTrigger asChild>\n <Button variant=\"ghost\" size=\"sm\" className=\"text-po-text\">\n Sort\n <ChevronDownIcon aria-hidden className=\"size-3\" />\n </Button>\n </DropdownMenuTrigger>\n <DropdownMenuContent align=\"start\" className=\"w-48\">\n <DropdownMenuRadioGroup\n value={sortValue}\n onValueChange={(value) => {\n const [nextSort, nextDirection] = value.split(':');\n onSortChange(nextSort as ArtifactSort, nextDirection as ArtifactSortDirection);\n }}\n >\n {(Object.keys(SORT_LABELS) as SortKey[]).map((key) => (\n <DropdownMenuRadioItem key={key} value={key}>\n {SORT_LABELS[key]}\n </DropdownMenuRadioItem>\n ))}\n </DropdownMenuRadioGroup>\n </DropdownMenuContent>\n </DropdownMenu>\n <span className=\"flex-1\" />\n <fieldset aria-label=\"Artifact view\" className=\"flex shrink-0 gap-0.5\">\n {(\n [\n ['tree', FolderIcon, 'Tree view'],\n ['grid', GridIcon, 'Preview view'],\n ] as const\n ).map(([value, Icon, label]) => (\n <button\n key={value}\n type=\"button\"\n aria-label={label}\n title={label}\n aria-pressed={layout === value}\n onClick={() => onLayoutChange(value)}\n className={`${tabVariants({ active: layout === value })} focus-visible:ring-2 focus-visible:ring-po-green`}\n >\n <Icon aria-hidden className=\"size-4\" />\n </button>\n ))}\n </fieldset>\n <button\n type=\"button\"\n aria-label=\"Search artifacts\"\n title=\"Search artifacts\"\n aria-expanded={searchOpen}\n onClick={() => onSearchOpenChange(!searchOpen)}\n className={`${tabVariants({ active: searchOpen || query !== '' })} focus-visible:ring-2 focus-visible:ring-po-green`}\n >\n <SearchIcon aria-hidden className=\"size-4\" />\n </button>\n </div>\n {searchOpen ? (\n <div className=\"relative shrink-0 px-3 pb-2\">\n <SearchIcon aria-hidden className=\"absolute top-2 left-5 size-4 text-po-dim\" />\n <Input\n aria-label=\"Search artifacts\"\n // Opened by the Search button, so typing should land here.\n autoFocus\n placeholder=\"Search by name or folder\"\n value={query}\n onChange={(event) => onQueryChange(event.target.value)}\n onKeyDown={(event) => {\n if (event.key !== 'Escape') return;\n event.preventDefault();\n onQueryChange('');\n onSearchOpenChange(false);\n }}\n className=\"w-full pl-8\"\n />\n </div>\n ) : null}\n {statusOf && newCount + editedCount > 0 ? (\n <div className=\"flex shrink-0 items-center gap-1 border-b border-po-border-soft px-3 pb-2\">\n {newCount > 0 ? (\n <Button\n variant=\"ghost\"\n size=\"xs\"\n aria-pressed={filters.status === 'new'}\n onClick={() => toggleStatus('new')}\n className={filters.status === 'new' ? 'bg-po-tint-green text-po-green' : 'text-po-text'}\n >\n {newCount} new\n </Button>\n ) : null}\n {editedCount > 0 ? (\n <Button\n variant=\"ghost\"\n size=\"xs\"\n aria-pressed={filters.status === 'edited'}\n onClick={() => toggleStatus('edited')}\n className={filters.status === 'edited' ? 'bg-po-tint-green text-po-green' : 'text-po-text'}\n >\n {editedCount} edited\n </Button>\n ) : null}\n <span className=\"flex-1\" />\n {onMarkAllViewed ? (\n <Button variant=\"ghost\" size=\"xs\" onClick={onMarkAllViewed} className=\"text-po-dim\">\n Mark all viewed\n </Button>\n ) : null}\n </div>\n ) : (\n <div className=\"shrink-0 border-b border-po-border-soft\" />\n )}\n <div className=\"min-h-0 flex-1 overflow-auto\">\n {error ? (\n <div role=\"alert\" className=\"flex items-center gap-2 px-4 py-3\">\n <p className=\"flex-1 text-sm text-po-red\">{error}</p>\n {onRetry ? (\n <Button variant=\"outline\" size=\"xs\" onClick={onRetry}>\n Try again\n </Button>\n ) : null}\n </div>\n ) : null}\n {loading ? <output className=\"block px-4 py-3 text-sm text-po-dim\">Loading files...</output> : null}\n {!loading && !error && items.length === 0 ? (\n <EmptyState\n title=\"Nothing here yet\"\n description=\"Files Po makes in this session show up here.\"\n className=\"px-4 py-8\"\n />\n ) : null}\n {!loading && items.length > 0 && filtered.length === 0 ? (\n <EmptyState title=\"No files match\" className=\"px-4 py-8\">\n <Button variant=\"ghost\" onClick={clear}>\n Clear filters\n </Button>\n </EmptyState>\n ) : null}\n <div className={layout === 'grid' ? 'grid grid-cols-2 gap-2 p-3' : 'flex flex-col py-1'}>\n {rows.map((row) => {\n if (row.kind === 'dir') {\n const unviewed = unviewedUnder(row.path);\n return (\n <button\n key={row.path}\n type=\"button\"\n data-artifact-row\n aria-expanded={row.open}\n onClick={() => onToggleFolder(row.path)}\n onKeyDown={(event) => {\n moveFocus(event);\n if ((event.key === 'ArrowRight' && !row.open) || (event.key === 'ArrowLeft' && row.open)) {\n event.preventDefault();\n onToggleFolder(row.path);\n }\n }}\n className=\"flex min-h-9 items-center gap-2 px-3 py-1.5 text-left hover:bg-po-panel focus-visible:ring-2 focus-visible:ring-po-green focus-visible:ring-inset\"\n >\n {Array.from({ length: row.depth }, (_, index) => (\n <span key={index} className=\"w-3 shrink-0\" />\n ))}\n {row.open ? (\n <ChevronDownIcon aria-hidden className=\"size-3.5 shrink-0 text-po-dim\" />\n ) : (\n <ChevronRightIcon aria-hidden className=\"size-3.5 shrink-0 text-po-dim\" />\n )}\n <FolderIcon aria-hidden className=\"size-4 shrink-0 text-po-dim\" />\n <span className=\"min-w-0 flex-1 truncate text-base font-medium\">{row.name}</span>\n {unviewed > 0 ? (\n <span className=\"shrink-0 text-sm font-semibold text-po-green\">{unviewed} unviewed</span>\n ) : (\n <span className=\"shrink-0 text-sm text-po-dim\">\n {row.count} {row.count === 1 ? 'file' : 'files'}\n </span>\n )}\n </button>\n );\n }\n const status = statuses.get(row.item.path);\n const unseen = status === 'new' || status === 'edited';\n const open = openPath === row.item.path;\n const Icon = artifactKind(row.item.path) === 'Image' ? ImageIcon : FileIcon;\n return (\n <button\n key={row.item.path}\n type=\"button\"\n data-artifact-row\n data-artifact-path={row.item.path}\n data-status={status}\n aria-current={open ? 'true' : undefined}\n title={row.item.path}\n onClick={() => onOpen(row.item)}\n onKeyDown={moveFocus}\n className={`${\n layout === 'grid'\n ? 'flex min-w-0 flex-col gap-1.5 rounded-md border p-2 text-left'\n : 'flex min-h-9 items-center gap-2 border-l-2 px-3 py-1.5 text-left'\n } ${open ? 'border-po-green bg-po-panel' : layout === 'grid' ? 'border-po-border-soft hover:bg-po-panel' : 'border-transparent hover:bg-po-panel'} focus-visible:ring-2 focus-visible:ring-po-green focus-visible:ring-inset`}\n >\n {layout === 'grid' ? (\n <span className=\"relative flex h-24 w-full items-center justify-center overflow-hidden rounded-sm bg-po-deep text-po-dim\">\n {renderThumbnail?.(row.item) ?? <Icon aria-hidden className=\"size-8\" />}\n <span className=\"absolute top-1 left-1\">\n <StatusMark status={status} />\n </span>\n </span>\n ) : (\n <>\n {Array.from({ length: row.depth }, (_, index) => (\n <span key={index} className=\"w-3 shrink-0\" />\n ))}\n <span className=\"w-3.5 shrink-0\" />\n <Icon aria-hidden className=\"size-4 shrink-0 text-po-dim\" />\n </>\n )}\n <span className=\"flex w-full min-w-0 flex-1 items-center gap-2\">\n <span\n className={`min-w-0 flex-1 truncate text-base ${unseen ? 'font-semibold text-po-hi' : 'text-po-text'}`}\n >\n {row.item.name}\n </span>\n {layout === 'grid' ? (\n <span className=\"sr-only\">\n <StatusMark status={status === 'viewed' ? status : undefined} />\n </span>\n ) : (\n <StatusMark status={status} />\n )}\n <ArtifactAge modifiedAt={row.item.modifiedAt} now={now} />\n </span>\n </button>\n );\n })}\n </div>\n </div>\n <footer\n data-testid=\"artifacts-count\"\n aria-live=\"polite\"\n className=\"shrink-0 border-t border-po-border-soft px-4 py-2 text-sm text-po-dim\"\n >\n {filtering ? `${filtered.length} of ${items.length}` : items.length} {items.length === 1 ? 'file' : 'files'}\n </footer>\n </section>\n );\n}\n\n/** Compact ages update their text node without rendering the inventory. */\nexport function ArtifactAge({ modifiedAt, now }: { modifiedAt: number; now: number }) {\n const ref = useRef<HTMLTimeElement>(null);\n useEffect(() => {\n const timer = setInterval(() => {\n const node = ref.current?.firstChild;\n if (node) node.nodeValue = ageLabel(modifiedAt, Date.now());\n }, 60_000);\n return () => clearInterval(timer);\n }, [modifiedAt]);\n return (\n <time ref={ref} dateTime={new Date(modifiedAt).toISOString()} className=\"shrink-0 text-sm text-po-dim\">\n {ageLabel(modifiedAt, now)}\n </time>\n );\n}\n","import type { WebPluginSlotProps } from '@agimon-ai/po-core/web';\nimport { useStore } from '@tanstack/react-store';\nimport { useEffect, useState } from 'react';\n\nimport { refreshArtifacts } from '../_lib/artifactsApi';\nimport {\n artifactBrowse,\n artifactLayout,\n artifacts,\n artifactSeen,\n DEFAULT_ARTIFACT_BROWSE,\n markAllArtifactsViewed,\n markArtifactViewed,\n setArtifactLayout,\n updateArtifactBrowse,\n} from '../_lib/artifactsStore';\nimport { artifactKind, artifactStatus } from '../_lib/artifactView';\nimport { ArtifactThumbnail, openArtifact, useTemporaryFiles } from './ArtifactsPanel';\nimport { ArtifactsRailView } from './ArtifactsRailView';\n\nconst THUMBNAIL_BYTES = 5 * 1024 * 1024;\n\n/** The right-rail Artifacts face: production data and actions for ArtifactsRailView. */\nexport function ArtifactsFace(props: WebPluginSlotProps) {\n const { sessionId } = props;\n const snapshot = useStore(artifacts.store, (state) => artifacts.select(state, sessionId));\n const seen = useStore(artifactSeen.store, (state) => (sessionId === null ? undefined : state[sessionId]));\n const browse = useStore(artifactBrowse.store, (state) =>\n sessionId === null ? DEFAULT_ARTIFACT_BROWSE : (state[sessionId] ?? DEFAULT_ARTIFACT_BROWSE),\n );\n const stored = useStore(artifactLayout.store);\n const temporaryLocation = browse.filters.location === 'temporary';\n const temporary = useTemporaryFiles(sessionId, temporaryLocation);\n const [now, setNow] = useState(Date.now);\n useEffect(() => {\n const subscription = artifacts.store.subscribe(() => setNow(Date.now()));\n return () => subscription.unsubscribe();\n }, []);\n useEffect(() => {\n if (sessionId === null || snapshot.loaded) return;\n const controller = new AbortController();\n void refreshArtifacts(sessionId, controller.signal);\n return () => controller.abort();\n }, [sessionId, snapshot.loaded]);\n const update = (change: Partial<typeof browse>) => {\n if (sessionId !== null) updateArtifactBrowse(sessionId, (current) => ({ ...current, ...change }));\n };\n const items = temporaryLocation ? (temporary?.items ?? []) : snapshot.items;\n return (\n <ArtifactsRailView\n items={items}\n loading={sessionId !== null && (temporaryLocation ? temporary === undefined : !snapshot.loaded)}\n error={sessionId === null ? 'The session is unavailable.' : temporaryLocation ? temporary?.error : snapshot.error}\n onRetry={\n sessionId === null || temporaryLocation\n ? undefined\n : () => void refreshArtifacts(sessionId, new AbortController().signal)\n }\n now={now}\n // Temporary files are not tracked, so they carry no markers.\n statusOf={temporaryLocation ? undefined : (item) => artifactStatus(item, seen)}\n layout={stored === 'grid' ? 'grid' : 'tree'}\n onLayoutChange={setArtifactLayout}\n query={browse.query}\n onQueryChange={(query) => update({ query })}\n searchOpen={browse.searchOpen}\n onSearchOpenChange={(searchOpen) => update({ searchOpen })}\n filters={browse.filters}\n onFiltersChange={(filters) => {\n update({ filters });\n setNow(Date.now());\n }}\n sort={browse.sort}\n direction={browse.direction}\n onSortChange={(sort, direction) => update({ sort, direction })}\n expanded={new Set(browse.expanded)}\n onToggleFolder={(path) =>\n update({\n expanded: browse.expanded.includes(path)\n ? browse.expanded.filter((entry) => entry !== path)\n : [...browse.expanded, path],\n })\n }\n openPath={browse.openPath}\n onOpen={(item) => {\n if (sessionId === null) return;\n openArtifact(props, item.path, browse.filters.location);\n if (!temporaryLocation) markArtifactViewed(sessionId, item);\n // Expand the folders holding the opened file, so the person keeps their place once filters clear;\n // the person can still collapse them afterwards.\n const parents = item.path\n .split('/')\n .slice(0, -1)\n .map((_, index, segments) => segments.slice(0, index + 1).join('/'));\n update({\n openPath: item.path,\n expanded: [...browse.expanded, ...parents.filter((path) => !browse.expanded.includes(path))],\n });\n }}\n onMarkAllViewed={sessionId === null ? undefined : () => markAllArtifactsViewed(sessionId, snapshot.items)}\n renderThumbnail={(item) =>\n sessionId !== null && artifactKind(item.path) === 'Image' && item.size <= THUMBNAIL_BYTES ? (\n <ArtifactThumbnail key={item.path} sessionId={sessionId} item={item} />\n ) : undefined\n }\n />\n );\n}\n","import { defineDockFace } from '@agimon-ai/po-core/web';\nimport { FileIcon } from '@agimon-ai/po-web-components';\n\nimport { ArtifactsFace } from '../_components/ArtifactsFace';\nimport { artifacts, artifactSeen, unviewedArtifactCount } from '../_lib/artifactsStore';\n\nexport default defineDockFace({\n id: 'artifacts',\n label: 'Artifacts',\n icon: FileIcon,\n order: 10,\n panel: ArtifactsFace,\n badge: {\n subscribe(listener: () => void) {\n const files = artifacts.store.subscribe(listener);\n const seen = artifactSeen.store.subscribe(listener);\n return () => {\n files.unsubscribe();\n seen.unsubscribe();\n };\n },\n count: unviewedArtifactCount,\n },\n});\n","/** Matching links is presentation only. The server independently selects and guards the root. */\nexport function temporaryFileReference(reference: string, root: string | undefined): string | undefined {\n const value = reference.trim();\n const prefix = 'temporary:';\n let relative: string;\n if (value.startsWith(prefix)) relative = value.slice(prefix.length);\n else {\n if (!root || !root.startsWith('/')) return undefined;\n const base = root.replace(/\\/+$/u, '');\n if (!value.startsWith(`${base}/`)) return undefined;\n relative = value.slice(base.length + 1);\n }\n if (\n !relative ||\n relative.includes('\\\\') ||\n relative.includes('\\0') ||\n relative.split('/').some((part) => !part || part === '.' || part === '..')\n )\n return undefined;\n return relative;\n}\n","import { defineFileLinks } from '@agimon-ai/po-core/web';\n\nimport { artifactTab } from '../_components/ArtifactPreviewPanel';\nimport { artifacts } from '../_lib/artifactsStore';\nimport { temporaryFileReference } from '../_lib/temporaryFiles';\n\n/** Artifacts offered for one `@`, newest first; the workspace's own files follow them. */\nconst MENTION_LIMIT = 5;\n\n/** Artifact references belong to the session store, never the repository file API. */\nexport default defineFileLinks({\n subscribe(listener) {\n const subscription = artifacts.store.subscribe(listener);\n return () => subscription.unsubscribe();\n },\n fingerprint: (sessionId) => artifacts.select(artifacts.store.state, sessionId).temporaryRoot ?? '',\n resolve(sessionId, path) {\n const reference = path.trim();\n if (sessionId === null) return undefined;\n const temporary = temporaryFileReference(\n reference,\n artifacts.select(artifacts.store.state, sessionId).temporaryRoot,\n );\n if (temporary) return artifactTab(sessionId, temporary, 'temporary');\n if (!reference.startsWith('artifact:')) return undefined;\n const relative = reference.slice('artifact:'.length);\n return relative === '' ? undefined : artifactTab(sessionId, relative);\n },\n mentions(sessionId, query) {\n const needle = query.toLowerCase();\n return artifacts\n .select(artifacts.store.state, sessionId)\n .items.map((item) => `artifact:${item.path}`)\n .filter((reference) => reference.toLowerCase().includes(needle))\n .slice(0, MENTION_LIMIT)\n .map((path) => ({ path, detail: 'Artifact' }));\n },\n});\n","// Generated by @agimon-ai/po-build. Do not edit by hand.\nimport { defineWebPlugin, type WebPluginContributions } from '@agimon-ai/po-core/web';\n\nimport channelArtifacts from '../src/extensions/workspaces/sessions/(frontend)/channel/artifacts.web';\nimport dockArtifacts from '../src/extensions/workspaces/sessions/(frontend)/dock/artifacts.web';\nimport fileLinksArtifacts from '../src/extensions/workspaces/sessions/(frontend)/file-links/artifacts.web';\n\nconst via = <T>(identity: Record<string, unknown>, value: unknown): T =>\n (value === undefined ? undefined : { ...identity, ...(value as object) }) as T;\n\nexport const webPlugin = defineWebPlugin({\n id: 'artifacts',\n session: {\n get channels(): WebPluginContributions['channels'] { return [via({ channel: 'artifacts' }, channelArtifacts)]; },\n get dockFaces(): WebPluginContributions['dockFaces'] { return [via({ id: 'artifacts' }, dockArtifacts)]; },\n get fileLinks(): WebPluginContributions['fileLinks'] { return fileLinksArtifacts; },\n },\n});\n"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agimon-ai/po-artifact",
3
- "version": "0.0.0-alpha.63",
3
+ "version": "0.0.0-alpha.65",
4
4
  "description": "Durable session artifacts, prompt guidance, and web/native artifact views.",
5
5
  "keywords": [
6
6
  "ai",
@@ -65,17 +65,17 @@
65
65
  "registry": "https://registry.npmjs.org/"
66
66
  },
67
67
  "dependencies": {
68
- "@agimon-ai/po-core": "0.0.0-alpha.64",
69
- "@agimon-ai/po-web-components": "0.0.0-alpha.64",
70
- "@agimon-ai/po-web-security": "0.0.0-alpha.64",
68
+ "@agimon-ai/po-core": "0.0.0-alpha.66",
69
+ "@agimon-ai/po-web-components": "0.0.0-alpha.66",
70
+ "@agimon-ai/po-web-security": "0.0.0-alpha.66",
71
71
  "@deepseek-ai/cordis": "4.0.5",
72
72
  "hono": "4.13.13",
73
73
  "typebox": "1.4.2"
74
74
  },
75
75
  "devDependencies": {
76
- "@agimon-ai/po-build": "0.0.0-alpha.64",
77
- "@agimon-ai/po-native-components": "0.0.0-alpha.64",
78
- "@agimon-ai/vibe-lint-plugin-po-extension": "0.0.0-alpha.64",
76
+ "@agimon-ai/po-build": "0.0.0-alpha.66",
77
+ "@agimon-ai/po-native-components": "0.0.0-alpha.66",
78
+ "@agimon-ai/vibe-lint-plugin-po-extension": "0.0.0-alpha.66",
79
79
  "@earendil-works/pi-coding-agent": "1.4.0",
80
80
  "@tanstack/react-store": "0.11.2",
81
81
  "@tanstack/store": "0.11.2",
@@ -92,7 +92,7 @@
92
92
  "vitest": "5.0.4"
93
93
  },
94
94
  "peerDependencies": {
95
- "@agimon-ai/po-native-components": "0.0.0-alpha.64",
95
+ "@agimon-ai/po-native-components": "0.0.0-alpha.66",
96
96
  "@earendil-works/pi-coding-agent": "1.4.0",
97
97
  "react-native": "0.88.0",
98
98
  "react-native-unistyles": "^3.5.3"