@agimon-ai/po-file-edit 0.0.0-alpha.2 → 0.0.0-alpha.21

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.
@@ -1 +1 @@
1
- {"version":3,"file":"native.mjs","names":["isRecord","WebPluginSlotProps","CodeBlock","Markdown","PoNativeTheme","useEffect","useState","StyleSheet","api","FileEditsWorkingView","MEDIA","MAX_MEDIA_BYTES","base64","bytes","Uint8Array","alphabet","parts","chunk","offset","length","first","second","third","undefined","push","join","SessionMedia","sessionId","path","renderMediaPreview","Pick","loaded","setLoaded","data","type","error","controller","AbortController","result","session","file","query","signal","ok","Error","status","size","Number","response","headers","get","arrayBuffer","split","trim","toLowerCase","test","aborted","catch","failure","message","String","abort","current","styles","meta","key","mimeType","title","FilePreview","working","props","unavailable","reason","renderFilePreview","html","content","tab","fileTabFor","openTransientTab","at","create","theme","minHeight","spacing","uni__dependencies","fontSize","sm","color","colors","dim","red","styles","WebPluginSlotProps","Button","DropdownMenu","DropdownMenuContent","DropdownMenuItem","DropdownMenuTrigger","KebabIcon","Label","SegmentedControl","Sheet","SheetBody","SheetContent","SheetHeader","SheetTitle","Textarea","fontOf","ReviewComment","PoNativeTheme","useCallback","useEffect","useRef","useState","useSyncExternalStore","StyleSheet","FileEditsDiffHunk","fileTabId","deleteFile","fetchFileDetail","prepareFileSave","saveFileContent","addComment","clearComments","files","markLoading","removeComment","storeDetail","storeError","FilePreview","Selection","Pick","Diff","hunks","comment","selection","styles","diff","map","hunk","index","start","meta","rows","row","position","line","marker","snippet","content","side","startLine","endLine","added","removed","code","ReviewSheet","close","submit","body","setBody","setSnippet","open","actions","trim","FilePanel","filePath","relPath","props","sessionId","sendSessionFrame","closeTransientTab","subscribe","listener","subscription","store","unsubscribe","session","select","state","detail","working","comments","filter","path","view","setView","source","setSource","expanded","setExpanded","setSelection","draft","setDraft","confirmingDelete","setConfirmingDelete","busy","setBusy","note","setNote","reviewError","setReviewError","outside","startsWith","test","writable","undefined","unavailable","revision","items","find","item","count","cancelled","then","result","ok","error","catch","failure","Error","message","String","downloadController","AbortController","current","abort","download","nativeSaveFile","controller","signal","aborted","save","hash","refreshed","remove","sendReview","length","anchor","split","slice","join","type","panel","header","success","value","label","loading","includes","errors","cumulative","additions","removals","title","versions","version","tool","origin","event","end","nativeEvent","reason","id","fileTab","Parameters","at","create","theme","padding","spacing","gap","uni__dependencies","flexDirection","alignItems","flexWrap","fontSize","base","fontWeight","color","colors","hi","flex","fontFamily","mono","sm","text","green","red","dim","WebPluginSlotProps","Button","Input","ListRow","Sheet","SheetContent","SheetHeader","SheetTitle","SheetBody","useCallback","useState","useSyncExternalStore","FilesItemView","fileTab","files","FilesActivitySection","sessionId","openTransientTab","subscribe","listener","subscription","store","unsubscribe","items","select","state","open","setOpen","query","setQuery","choose","item","path","relPath","row","tool","count","diffable","length","slice","map","filter","toLocaleLowerCase","includes","trim","activityGroupFiles","channelFileEdits","fillFiles"],"sources":["../../src/types/webFiles.ts","../../src/extensions/workspaces/sessions/(frontend)/activity-group/files.native.ts","../../src/extensions/workspaces/sessions/(frontend)/_lib/filesModel.ts","../../src/extensions/workspaces/sessions/(frontend)/_lib/filesStore.native.ts","../../src/extensions/workspaces/sessions/(frontend)/channel/file-edits.native.ts","../../src/extensions/workspaces/sessions/(frontend)/_lib/fileIdentity.ts","../../src/types/apiRoutes.ts","../../generated/client.native.ts","../../src/types/fileEditsApi.ts","../../src/extensions/workspaces/sessions/(frontend)/_lib/filesApi.native.ts","../../src/extensions/workspaces/sessions/(frontend)/_components/FilePreview.native.tsx","../../src/extensions/workspaces/sessions/(frontend)/_components/FilePanel.native.tsx","../../src/extensions/workspaces/sessions/(frontend)/fill/_components/FilesActivitySection.native.tsx","../../src/extensions/workspaces/sessions/(frontend)/fill/Files.activity.files.native.tsx","../../generated/native.ts"],"sourcesContent":["import type { FileEditTool } from './domain';\n\n/**\n * View types shared by this package's hub channel and its web plugin. Wire\n * JSON only, no node types, so the cockpit bundle can carry them; the\n * cockpit receives them as 'file_edits' channel payloads.\n *\n * The channel carries the list alone. One file's diffs and content are large\n * and only wanted once a reader opens the file, so those come from the session\n * API instead (see fileEditsApi.ts).\n */\n\n/** One file this session changed, as the activity dock lists it. */\nexport interface FilesItemView {\n /** Absolute path, and the identity every API route takes back. */\n path: string;\n /** Path relative to the session's working directory, which is what a row shows. */\n relPath: string;\n /** The tool behind the most recent change. */\n tool: FileEditTool;\n /** When that change happened, epoch milliseconds. */\n at: number;\n /** How many changes this session recorded for the file. */\n count: number;\n /**\n * Whether any change captured a baseline, so a diff can be shown at all. A\n * file found by comparing the tree around a bash call has no \"before\", so it\n * is listed and readable but never diffed.\n */\n diffable: boolean;\n}\n\n/** The frame type the hub publishes and the web plugin claims; declared in the poWeb block too. */\nexport const filesChannelType = 'file_edits';\n\n/** Footer status key whose presence shows the activity group; the extension publishes it. */\nexport const filesStatusKey = 'doom-file-edit-files';\n","import { defineActivityGroup } from '@agimon-ai/po-core/native';\n\nimport { filesStatusKey } from '../../../../../types/webFiles';\nexport default defineActivityGroup({\n keys: 'e f',\n statusKey: filesStatusKey,\n hideWhenEmpty: true,\n marksBackgroundWork: false,\n order: 15,\n});\n","import type { FilesItemView } from '../../../../../types/webFiles';\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n\nfunction isItem(value: unknown): value is FilesItemView {\n return (\n isRecord(value) &&\n typeof value.path === 'string' &&\n typeof value.relPath === 'string' &&\n typeof value.tool === 'string' &&\n typeof value.at === 'number' &&\n typeof value.count === 'number'\n );\n}\n\nexport interface FilesPayload {\n items: FilesItemView[];\n}\n\n/** The shared wire gate for browser and native stores. */\nexport function parseFilesPayload(input: unknown): FilesPayload | null {\n if (!isRecord(input) || !Array.isArray(input.items)) return null;\n return { items: input.items.filter(isItem) };\n}\n","import { defineSessionStore } from '@agimon-ai/po-core/native';\nimport type { ReviewComment } from '@agimon-ai/po-web-components';\n\nimport type { FileEditsDetailView } from '../../../../../types/fileEditsApi';\nimport { filesChannelType, type FilesItemView } from '../../../../../types/webFiles';\nimport { parseFilesPayload, type FilesPayload } from './filesModel';\nexport type { FilesPayload } from './filesModel';\n\n/**\n * One session's record: the hub's last report plus whatever this page does with\n * it. Records are immutable values; the reducer and every action return a new one.\n *\n * Detail is cached per file rather than per open tab, because a reader closes a\n * file and comes back to it, and refetching the same history for the same click\n * is work the session already did.\n */\nexport interface FilesSession {\n items: FilesItemView[];\n /** One file's fetched history, keyed by absolute path. */\n detail: Readonly<Record<string, FileEditsDetailView>>;\n /** Paths with a detail request in flight, so a panel can say it is loading. */\n loading: readonly string[];\n /** What a failed fetch or a refused save reported, keyed by absolute path. */\n errors: Readonly<Record<string, string>>;\n /** Review notes waiting to be sent, in the order they were written. */\n comments: readonly ReviewComment[];\n}\n\nconst empty: FilesSession = { items: [], detail: {}, loading: [], errors: {}, comments: [] };\n\nexport const files = defineSessionStore<FilesSession>(empty);\n\n/** The plugin's session data channel: 'file_edits' payloads into the store. */\nexport const filesChannel = files.channel<FilesPayload>({\n channel: filesChannelType,\n parse: parseFilesPayload,\n // Only the list is replaced. The cached detail and the pending notes belong\n // to files a reader opened, not to the list: a file the session deletes stops\n // being listed, and pruning here would blank the tab still open on it and\n // then refetch it on the next frame.\n reduce: (current, { items }) => ({ ...current, items }),\n});\n\nexport function markLoading(sessionId: string, filePath: string): void {\n files.update(sessionId, (current) =>\n current.loading.includes(filePath)\n ? current\n : { ...current, loading: [...current.loading, filePath], errors: withoutKey(current.errors, filePath) },\n );\n}\n\nexport function storeDetail(sessionId: string, detail: FileEditsDetailView): void {\n files.update(sessionId, (current) => ({\n ...current,\n detail: { ...current.detail, [detail.path]: detail },\n loading: current.loading.filter((path) => path !== detail.path),\n errors: withoutKey(current.errors, detail.path),\n }));\n}\n\nexport function storeError(sessionId: string, filePath: string, message: string): void {\n files.update(sessionId, (current) => ({\n ...current,\n loading: current.loading.filter((path) => path !== filePath),\n errors: { ...current.errors, [filePath]: message },\n }));\n}\n\nexport function addComment(sessionId: string, comment: ReviewComment): void {\n files.update(sessionId, (current) => ({ ...current, comments: [...current.comments, comment] }));\n}\n\nexport function removeComment(sessionId: string, id: string): void {\n files.update(sessionId, (current) => ({\n ...current,\n comments: current.comments.filter((comment) => comment.id !== id),\n }));\n}\n\nexport function clearComments(sessionId: string, filePath: string): void {\n files.update(sessionId, (current) => ({\n ...current,\n comments: current.comments.filter((comment) => comment.path !== filePath),\n }));\n}\n\nfunction withoutKey(source: Readonly<Record<string, string>>, key: string): Record<string, string> {\n return Object.fromEntries(Object.entries(source).filter(([entry]) => entry !== key));\n}\n","import { defineChannelFile } from '@agimon-ai/po-core/native';\n\nimport { filesChannel } from '../_lib/filesStore.native';\nexport default defineChannelFile(filesChannel);\n","/** A short, stable fingerprint of a string; enough to separate two paths in an id. */\nfunction fingerprint(value: string): string {\n let hash = 2166136261;\n for (let index = 0; index < value.length; index += 1) {\n hash ^= value.charCodeAt(index);\n hash = Math.imul(hash, 16777619);\n }\n return (hash >>> 0).toString(36);\n}\n\n/** The transient tab id for one file; stable, so reopening focuses rather than duplicates. */\nexport function fileTabId(filePath: string): string {\n // The id reaches a URL, so anything outside the safe set becomes a dash, and\n // the path's own fingerprint keeps two similarly-named files apart.\n const slug = filePath.replaceAll(/[^a-zA-Z0-9]+/gu, '-').replace(/^-|-$/gu, '');\n return `files-file-${fingerprint(filePath)}-${slug.slice(-40)}`;\n}\n","import type { ApiResponseOf, ApiRoutes } from '@agimon-ai/po-core/web';\n\nimport type { FileEditsDetailView, FileEditsPreviewView, FileEditsSaveView } from './fileEditsApi';\n\n/**\n * This package's routes, as data.\n *\n * No scope and no base path. The build reads both off\n * `src/extensions/workspaces/sessions/(backend)/api/file-edits/`, so the mount\n * is stated once, by the folder that creates it. They used to be written here,\n * in the contract and again inside every URL the page built, and the copies\n * were free to disagree.\n *\n * This is the one file the routes, the Hono app and the browser all read, so a\n * path cannot move on one side alone.\n */\nconst routes = {\n detail: {\n method: 'GET',\n path: '/detail',\n query: ['path'],\n response: undefined as unknown as ApiResponseOf<FileEditsDetailView>,\n },\n preview: {\n method: 'GET',\n path: '/preview',\n query: ['path'],\n response: undefined as unknown as ApiResponseOf<FileEditsPreviewView>,\n },\n save: {\n method: 'PUT',\n path: '/content',\n response: undefined as unknown as ApiResponseOf<FileEditsSaveView>,\n },\n /** The same path as `save`; the method is the whole of the difference. */\n remove: {\n method: 'DELETE',\n path: '/content',\n query: ['path'],\n },\n /**\n * The host's own bytes route, not this package's.\n *\n * `host: true` hangs it off the session root rather than under `/plugins`,\n * which is how the cockpit already serves it. Declaring it here is the first\n * time anything records that this package's previews depend on it.\n */\n file: {\n method: 'GET',\n path: '/file',\n raw: true,\n query: ['path'],\n host: 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, nativeApiTransport, sessionApiAddress } from '@agimon-ai/po-core/native';\n\nimport routes from '../src/types/apiRoutes';\n\n/** Scopes the tree mounts 'file-edits' at. */\nexport const apiScopes = ['session'] as const;\n\nexport const api = createApiClient(routes, {\n scopes: apiScopes,\n basePath: 'file-edits',\n transport: nativeApiTransport,\n sessionAddress: sessionApiAddress,\n});\n","import type { FileEditOrigin, FileEditTool } from './domain';\n\n/**\n * The wire vocabulary this package's API shares with whatever calls it.\n *\n * It lives under src/types because that is the one server root a browser\n * bundle may read: the cockpit plugin builds its URLs from these and the\n * routes answer them, so neither half can drift from the other.\n *\n * Routes live in `./apiRoutes`, which the contract, the Hono app and the\n * generated client all read. This file holds the shapes that travel over them.\n *\n * Opening a changed file wants its whole history at once, so `detail` answers\n * in one round trip rather than making the page stitch three reads together;\n * `content` takes the manual save back; `preview` reads a file the session\n * never changed, which has no history to answer with.\n */\n\n/** Where a host mounts this package's API; the segment after /api/plugins/. */\nexport const API_BASE_PATH = 'file-edits';\n\n/** Query parameter naming the file a request is about. */\nexport const PATH_QUERY_PARAM = 'path';\n\n/**\n * One line of a diff. The number is the new file's for context and additions\n * and the old file's for removals, so it always says where the line lives.\n */\nexport interface FileEditsDiffRow {\n marker: '+' | '-' | ' ';\n line: number;\n content: string;\n}\n\n/**\n * A run of changed lines with its surrounding context. Hunks are sent apart\n * rather than joined by an elision marker, so the page draws the gap between\n * them instead of parsing one out of a string.\n */\nexport interface FileEditsDiffHunk {\n /** The line number the hunk opens at. */\n start: number;\n rows: FileEditsDiffRow[];\n}\n\n/**\n * One change in a file's history, each rendered on its own so a file edited\n * four times shows four distinct diffs rather than one merged blur.\n */\nexport interface FileEditsVersionView {\n /** Position in the file's history, oldest first, starting at 1. */\n index: number;\n tool: FileEditTool;\n at: number;\n origin: FileEditOrigin;\n additions: number;\n removals: number;\n /** The changed lines of this one change; absent when no baseline was captured. */\n hunks?: FileEditsDiffHunk[];\n /** Why there is no diff, shown in its place. */\n note?: string;\n}\n\n/** Everything this session did to the file: its first baseline against what is on disk now. */\nexport interface FileEditsCumulativeView {\n additions: number;\n removals: number;\n hunks?: FileEditsDiffHunk[];\n note?: string;\n}\n\n/** The file as it stands on disk right now, which is what the source view edits. */\nexport interface FileEditsWorkingView {\n content: string;\n /** sha256 of the content; the token a save hands back to prove it is not stale. */\n hash: string;\n /** True when the file is binary, missing, or past the size cap, so `content` is empty. */\n unavailable: boolean;\n reason?: string;\n}\n\n/** What the detail route answers with. */\nexport interface FileEditsDetailView {\n path: string;\n relPath: string;\n versions: FileEditsVersionView[];\n cumulative: FileEditsCumulativeView;\n working: FileEditsWorkingView;\n}\n\n/**\n * What the preview route answers with: the file as it stands, and nothing\n * about how it got there. A file this session never touched has no history and\n * no baseline, so there is no diff to send and no save to take back.\n */\nexport interface FileEditsPreviewView {\n path: string;\n relPath: string;\n working: FileEditsWorkingView;\n}\n\n/** What the save route takes. */\nexport interface FileEditsSaveRequest {\n path: string;\n /** The hash the reader loaded; a mismatch means the file moved underneath them. */\n expectedHash: string;\n content: string;\n}\n\n/** What the save route answers with. */\nexport interface FileEditsSaveView {\n hash: string;\n}\n\n/** What a route reports when it refuses; the page shows `error` verbatim. */\nexport interface FileEditsErrorView {\n error: string;\n /** On a stale save, the hash the file actually has now. */\n hash?: string;\n}\n","import type { WebPluginSlotProps } from '@agimon-ai/po-core/native';\n\nimport { api } from '../../../../../../generated/client.native';\nimport {\n type FileEditsDetailView,\n type FileEditsPreviewView,\n PATH_QUERY_PARAM,\n} from '../../../../../types/fileEditsApi';\n\n/**\n * The page's half of this package's session API: one file's history, the\n * manual save, and the deletion.\n *\n * These are adapters now, not a transport. The generated client owns the URL\n * and the sealed transport with it, so nothing here spells a route or reaches\n * for `fetch`. What stays is this package's own vocabulary: which refusals the\n * reader is shown, and the stale-save contract the editor depends on.\n *\n * Sealing still matters and still happens, one layer down. What travels here is\n * file contents in both directions, which is the worst thing in the cockpit to\n * hand a tunnel's relay in the clear.\n */\n\nconst UNREACHABLE = 'The session is unreachable.';\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n\n/**\n * Where a file's raw bytes are served from, for the ones the page shows rather\n * than edits.\n *\n * This is the host's route, not this package's, which is why the route table\n * marks it `host: true` and it lands beside the session rather than under\n * `/plugins`. The cockpit already serves any file under a session's working\n * directory, and that route carries the traversal guard, the size cap and the\n * content-type mapping. A second one here would duplicate a security boundary\n * to avoid duplicating a URL, which is the wrong way round.\n */\nexport function sessionFileUrl(sessionId: string, relPath: string): string {\n return api.session(sessionId).file.url({ query: { [PATH_QUERY_PARAM]: relPath } });\n}\n\n/** The message a reader is shown: the route's own words, or why there were none. */\nfunction messageOf(result: { status: number; error: string }): string {\n if (result.status === 0) return UNREACHABLE;\n return result.error === '' ? `The session answered ${result.status}.` : result.error;\n}\n\nexport type FetchDetailResult = { ok: true; detail: FileEditsDetailView } | { ok: false; error: string };\n\nexport async function fetchFileDetail(sessionId: string, filePath: string): Promise<FetchDetailResult> {\n const result = await api.session(sessionId).detail({ query: { [PATH_QUERY_PARAM]: filePath } });\n if (!result.ok) return { ok: false, error: messageOf(result) };\n if (!isRecord(result.data)) return { ok: false, error: 'The session answered with no detail.' };\n return { ok: true, detail: result.data };\n}\n\nexport type FetchPreviewResult = { ok: true; preview: FileEditsPreviewView } | { ok: false; error: string };\n\n/** One file the session never changed, read only; the route bounds it to the working directory. */\nexport async function fetchFilePreview(sessionId: string, filePath: string): Promise<FetchPreviewResult> {\n const result = await api.session(sessionId).preview({ query: { [PATH_QUERY_PARAM]: filePath } });\n if (!result.ok) return { ok: false, error: messageOf(result) };\n if (!isRecord(result.data)) return { ok: false, error: 'The session answered with no file.' };\n return { ok: true, preview: result.data };\n}\n\nexport type SaveResult =\n | { ok: true; hash: string }\n /** The file moved under the editor; `hash` is what it holds now. */\n | { ok: false; stale: true; error: string; hash?: string }\n | { ok: false; stale: false; error: string };\n\nexport async function saveFileContent(\n sessionId: string,\n filePath: string,\n expectedHash: string,\n content: string,\n): Promise<SaveResult> {\n const result = await api.session(sessionId).save({ body: { path: filePath, expectedHash, content } });\n // The agent runs in the same working directory, so it can rewrite the file\n // while a reader is still editing it. A moved hash is the one refusal the\n // editor recovers from, so it is read before the generic failure.\n if (result.status === 409) {\n const data = result.ok ? undefined : result.data;\n const hash = isRecord(data) && typeof data.hash === 'string' ? data.hash : undefined;\n return {\n ok: false,\n stale: true,\n error: result.ok ? 'The file changed since it was opened.' : messageOf(result),\n ...(hash === undefined ? {} : { hash }),\n };\n }\n if (!result.ok) return { ok: false, stale: false, error: messageOf(result) };\n return { ok: true, hash: isRecord(result.data) && typeof result.data.hash === 'string' ? result.data.hash : '' };\n}\n\nexport type DeleteResult = { ok: true } | { ok: false; error: string };\n\n/**\n * Removes the file from disk.\n *\n * The route takes only a path, with no hash to prove the reader saw what is\n * there now: a deletion discards the file whatever it holds, so a staleness\n * check would guard nothing. The confirmation in front of it is the guard.\n */\nexport async function deleteFile(sessionId: string, filePath: string): Promise<DeleteResult> {\n const result = await api.session(sessionId).remove({ query: { [PATH_QUERY_PARAM]: filePath } });\n return result.ok ? { ok: true } : { ok: false, error: messageOf(result) };\n}\n\n/** Binds a save to this package's guarded sealed route and one file version. */\nexport async function prepareFileSave(\n sessionId: string,\n path: string,\n signal: AbortSignal,\n): Promise<Parameters<NonNullable<WebPluginSlotProps['nativeSaveFile']>>[0]> {\n const load = async (headers: Record<string, string>, signal: AbortSignal): Promise<Response> => {\n if (signal.aborted) throw new Error('Download cancelled.');\n const result = await api.session(sessionId).file({ query: { path }, headers, signal });\n if (!result.ok && result.status !== 416) throw new Error(result.error || 'File could not be read.');\n if (!result.response) throw new Error('File could not be read.');\n return result.response;\n };\n const probe = await load({ Range: 'bytes=0-0' }, signal);\n if (signal.aborted) throw new Error('Download cancelled.');\n const range = /^bytes 0-0\\/(\\d+)$/u.exec(probe.headers.get('content-range') ?? '');\n const empty =\n (probe.status === 416 && probe.headers.get('content-range') === 'bytes */0') ||\n (probe.status === 200 && probe.headers.get('content-length') === '0');\n if (!empty && (probe.status !== 206 || !range)) throw new Error('The file does not support bounded downloads.');\n const size = empty ? 0 : Number(range![1]);\n if (!Number.isSafeInteger(size) || size < 0) throw new Error('Invalid file size.');\n const probeBytes = await probe.arrayBuffer();\n if (probeBytes.byteLength !== (empty ? 0 : 1)) throw new Error('Invalid file response.');\n const version = probe.headers.get('etag');\n if (!version) throw new Error('The file has no version validator.');\n return {\n name: path.split(/[\\\\/]/u).at(-1) ?? '',\n mimeType: probe.headers.get('content-type')?.split(';')[0]?.trim() || 'application/octet-stream',\n size,\n signal,\n read: async (offset, count, signal) => {\n if (\n !Number.isSafeInteger(offset) ||\n !Number.isSafeInteger(count) ||\n offset < 0 ||\n count < 1 ||\n count > 1024 * 1024 ||\n offset + count > size\n )\n throw new Error('Invalid download range.');\n const end = offset + count - 1;\n const response = await load({ Range: `bytes=${offset}-${end}`, 'If-Match': version }, signal);\n if (signal.aborted) throw new Error('Download cancelled.');\n if (\n response.status !== 206 ||\n response.headers.get('etag') !== version ||\n response.headers.get('content-range') !== `bytes ${offset}-${end}/${size}`\n )\n throw new Error('The file changed or its range response is invalid.');\n const bytes = new Uint8Array(await response.arrayBuffer());\n if (signal.aborted) throw new Error('Download cancelled.');\n if (bytes.byteLength !== count) throw new Error('The file response is incomplete.');\n return bytes;\n },\n };\n}\n","import type { WebPluginSlotProps } from '@agimon-ai/po-core/native';\nimport { CodeBlock, Markdown } from '@agimon-ai/po-native-components';\nimport type { PoNativeTheme } from '@agimon-ai/po-web-components/nativeTheme';\nimport { useEffect, useState } from 'react';\nimport { Text, View } from 'react-native';\nimport { StyleSheet } from 'react-native-unistyles';\n\nimport { api } from '../../../../../../generated/client.native';\nimport type { FileEditsWorkingView } from '../../../../../types/fileEditsApi';\n\nconst MEDIA = /\\.(?:png|jpe?g|gif|webp|bmp|svg|ico|mp3|wav|m4a|ogg|mp4|mov|webm|pdf)$/iu;\nconst MAX_MEDIA_BYTES = 5 * 1024 * 1024;\n\nfunction base64(bytes: Uint8Array): string {\n const alphabet = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';\n const parts: string[] = [];\n let chunk = '';\n for (let offset = 0; offset < bytes.length; offset += 3) {\n const first = bytes[offset]!;\n const second = bytes[offset + 1];\n const third = bytes[offset + 2];\n chunk +=\n alphabet[first >> 2]! +\n alphabet[((first & 3) << 4) | ((second ?? 0) >> 4)]! +\n (second === undefined ? '=' : alphabet[((second & 15) << 2) | ((third ?? 0) >> 6)]!) +\n (third === undefined ? '=' : alphabet[third & 63]!);\n if (chunk.length >= 8192) {\n parts.push(chunk);\n chunk = '';\n }\n }\n parts.push(chunk);\n return parts.join('');\n}\n\nfunction SessionMedia({\n sessionId,\n path,\n renderMediaPreview,\n}: Pick<WebPluginSlotProps, 'sessionId' | 'renderMediaPreview'> & { path: string }) {\n const [loaded, setLoaded] = useState<{\n sessionId: string;\n path: string;\n data?: string;\n type?: string;\n error?: string;\n }>();\n useEffect(() => {\n if (sessionId === null) return;\n const controller = new AbortController();\n void (async () => {\n const result = await api.session(sessionId).file({ query: { path }, signal: controller.signal });\n if (!result.ok) throw new Error(result.error || `Media could not be loaded (${result.status}).`);\n const size = Number(result.response.headers.get('content-length'));\n if (size > MAX_MEDIA_BYTES) throw new Error('This media is too large to preview.');\n const bytes = new Uint8Array(await result.response.arrayBuffer());\n if (bytes.length > MAX_MEDIA_BYTES) throw new Error('This media is too large to preview.');\n const type = result.response.headers.get('content-type')?.split(';')[0]?.trim().toLowerCase() ?? '';\n if (!/^(?:image\\/[a-z0-9.+-]+|audio\\/[a-z0-9.+-]+|video\\/[a-z0-9.+-]+|application\\/pdf)$/u.test(type))\n throw new Error('This media type cannot be previewed.');\n if (!controller.signal.aborted) setLoaded({ sessionId, path, type, data: base64(bytes) });\n })().catch((failure: unknown) => {\n if (!controller.signal.aborted)\n setLoaded({ sessionId, path, error: failure instanceof Error ? failure.message : String(failure) });\n });\n return () => controller.abort();\n }, [sessionId, path]);\n const current = loaded?.sessionId === sessionId && loaded.path === path ? loaded : undefined;\n if (!current?.data)\n return (\n <Text accessibilityRole={current?.error ? 'alert' : 'text'} style={current?.error ? styles.error : styles.meta}>\n {current?.error ?? 'Loading media...'}\n </Text>\n );\n return renderMediaPreview ? (\n <>\n {renderMediaPreview({\n key: `file-media-${sessionId}-${path}`,\n data: current.data,\n mimeType: current.type!,\n title: path,\n path,\n })}\n </>\n ) : (\n <Text style={styles.error}>This host cannot display this media preview.</Text>\n );\n}\n\n/** Rendering is separate from reading: only the guarded package API supplies file content or bytes. */\nexport function FilePreview({\n path,\n working,\n ...props\n}: WebPluginSlotProps & { path: string; working: FileEditsWorkingView }) {\n if (MEDIA.test(path))\n return <SessionMedia sessionId={props.sessionId} path={path} renderMediaPreview={props.renderMediaPreview} />;\n if (working.unavailable) return <Text style={styles.meta}>{working.reason ?? 'this file cannot be shown'}</Text>;\n if (/\\.html?$/iu.test(path))\n return props.renderFilePreview ? (\n <View style={styles.html}>\n {props.renderFilePreview({ key: `file-html-${props.sessionId}-${path}`, html: working.content, title: path })}\n </View>\n ) : (\n <Text style={styles.error}>This host cannot display HTML previews.</Text>\n );\n if (/\\.(?:md|markdown)$/iu.test(path))\n return (\n <Markdown\n text={working.content}\n onFileLink={(file) => {\n const tab = props.fileTabFor(file);\n return tab ? () => props.openTransientTab(tab) : undefined;\n }}\n />\n );\n return <CodeBlock text={working.content} language={path.split('.').at(-1)} />;\n}\n\nconst styles = StyleSheet.create((theme: PoNativeTheme) => ({\n html: { minHeight: theme.spacing(90) },\n meta: { fontSize: theme.fontSize.sm, color: theme.colors.dim },\n error: { fontSize: theme.fontSize.sm, color: theme.colors.red },\n}));\n","import type { WebPluginSlotProps } from '@agimon-ai/po-core/native';\nimport {\n Button,\n DropdownMenu,\n DropdownMenuContent,\n DropdownMenuItem,\n DropdownMenuTrigger,\n KebabIcon,\n Label,\n SegmentedControl,\n Sheet,\n SheetBody,\n SheetContent,\n SheetHeader,\n SheetTitle,\n Textarea,\n fontOf,\n} from '@agimon-ai/po-native-components';\nimport type { ReviewComment } from '@agimon-ai/po-web-components';\nimport type { PoNativeTheme } from '@agimon-ai/po-web-components/nativeTheme';\nimport { useCallback, useEffect, useRef, useState, useSyncExternalStore } from 'react';\nimport { ScrollView, Text, View } from 'react-native';\nimport { StyleSheet } from 'react-native-unistyles';\n\nimport type { FileEditsDiffHunk } from '../../../../../types/fileEditsApi';\nimport { fileTabId } from '../_lib/fileIdentity';\nimport { deleteFile, fetchFileDetail, prepareFileSave, saveFileContent } from '../_lib/filesApi.native';\nimport {\n addComment,\n clearComments,\n files,\n markLoading,\n removeComment,\n storeDetail,\n storeError,\n} from '../_lib/filesStore.native';\nimport { FilePreview } from './FilePreview.native';\n\ntype Selection = Pick<ReviewComment, 'snippet' | 'side' | 'startLine' | 'endLine'>;\n\nfunction Diff({ hunks, comment }: { hunks: readonly FileEditsDiffHunk[]; comment: (selection: Selection) => void }) {\n return (\n <View style={styles.diff}>\n {hunks.map((hunk, index) => (\n <View key={`${hunk.start}-${index}`}>\n <Text style={styles.meta}>line {hunk.start}</Text>\n {hunk.rows.map((row, position) => (\n <Button\n key={`${row.line}-${position}`}\n variant=\"ghost\"\n accessibilityLabel={`comment on ${row.marker === '-' ? 'removed' : 'new'} line ${row.line}`}\n onPress={() =>\n comment({\n snippet: row.content,\n side: row.marker === '-' ? 'old' : 'new',\n startLine: row.line,\n endLine: row.line,\n })\n }\n >\n <Text\n selectable\n style={row.marker === '+' ? styles.added : row.marker === '-' ? styles.removed : styles.code}\n >\n {row.marker} {row.line} {row.content}\n </Text>\n </Button>\n ))}\n </View>\n ))}\n </View>\n );\n}\n\nfunction ReviewSheet({\n selection,\n close,\n submit,\n}: {\n selection: Selection;\n close: () => void;\n submit: (body: string, snippet: string) => void;\n}) {\n const [body, setBody] = useState('');\n const [snippet, setSnippet] = useState(selection.snippet);\n return (\n <Sheet\n open\n onOpenChange={(open) => {\n if (!open) close();\n }}\n >\n <SheetContent>\n <SheetHeader>\n <SheetTitle>review comment</SheetTitle>\n </SheetHeader>\n <SheetBody>\n <Label>quotation</Label>\n <Textarea accessibilityLabel=\"quotation\" value={snippet} onChangeText={setSnippet} rows={3} />\n <Label>comment</Label>\n <Textarea accessibilityLabel=\"comment\" value={body} onChangeText={setBody} rows={3} />\n <View style={styles.actions}>\n <Button variant=\"ghost\" onPress={close}>\n cancel\n </Button>\n <Button variant=\"primary\" disabled={!body.trim()} onPress={() => submit(body.trim(), snippet)}>\n add comment\n </Button>\n </View>\n </SheetBody>\n </SheetContent>\n </Sheet>\n );\n}\n\n/** File writes retain the existing containment and stale-hash guards; deletion always asks first. */\nexport function FilePanel({ filePath, relPath, ...props }: WebPluginSlotProps & { filePath: string; relPath: string }) {\n const { sessionId, sendSessionFrame, closeTransientTab } = props;\n const subscribe = useCallback((listener: () => void) => {\n const subscription = files.store.subscribe(listener);\n return () => subscription.unsubscribe();\n }, []);\n const session = useSyncExternalStore(subscribe, () => files.select(files.store.state, sessionId));\n const detail = session.detail[filePath];\n const working = detail?.working;\n const comments = session.comments.filter((comment) => comment.path === filePath);\n const [view, setView] = useState('preview');\n const [source, setSource] = useState<string>();\n const [expanded, setExpanded] = useState<number>();\n const [selection, setSelection] = useState<Selection>();\n const [draft, setDraft] = useState<Selection>();\n const [confirmingDelete, setConfirmingDelete] = useState(false);\n const [busy, setBusy] = useState(false);\n const [note, setNote] = useState<string>();\n const [reviewError, setReviewError] = useState<string>();\n const outside =\n relPath === '..' ||\n relPath.startsWith('../') ||\n relPath.startsWith('/') ||\n relPath.startsWith('..\\\\') ||\n /^[a-z]:[\\\\/]/iu.test(relPath);\n const writable = sessionId !== null && !outside && working !== undefined && !working.unavailable;\n const revision = session.items.find((item) => item.path === filePath)?.count ?? 0;\n useEffect(() => {\n if (sessionId === null) return;\n let cancelled = false;\n markLoading(sessionId, filePath);\n void fetchFileDetail(sessionId, filePath)\n .then((result) => {\n if (cancelled) return;\n if (result.ok) {\n storeDetail(sessionId, result.detail);\n setSource(undefined);\n setNote(undefined);\n } else storeError(sessionId, filePath, result.error);\n })\n .catch((failure: unknown) => {\n if (!cancelled) storeError(sessionId, filePath, failure instanceof Error ? failure.message : String(failure));\n });\n return () => {\n cancelled = true;\n };\n }, [sessionId, filePath, revision]);\n\n const downloadController = useRef<AbortController | undefined>(undefined);\n useEffect(() => () => downloadController.current?.abort(), [sessionId, relPath]);\n const download = async () => {\n if (sessionId === null || outside || busy || !props.nativeSaveFile) return;\n const controller = new AbortController();\n downloadController.current = controller;\n setBusy(true);\n try {\n await props.nativeSaveFile(await prepareFileSave(sessionId, relPath, controller.signal));\n if (!controller.signal.aborted) setNote('saved');\n } catch (error) {\n if (!controller.signal.aborted) setNote(error instanceof Error ? error.message : String(error));\n } finally {\n setBusy(false);\n }\n };\n const save = async () => {\n if (!writable || sessionId === null || !working || source === undefined || busy) return;\n setBusy(true);\n try {\n const result = await saveFileContent(sessionId, filePath, working.hash, source);\n if (!result.ok) {\n setNote(result.error);\n return;\n }\n setNote('saved');\n const refreshed = await fetchFileDetail(sessionId, filePath);\n if (refreshed.ok) {\n storeDetail(sessionId, refreshed.detail);\n setSource(undefined);\n } else storeError(sessionId, filePath, refreshed.error);\n } catch (failure) {\n setNote(failure instanceof Error ? failure.message : String(failure));\n } finally {\n setBusy(false);\n }\n };\n const remove = async () => {\n if (!writable || sessionId === null || busy) return;\n setBusy(true);\n try {\n const result = await deleteFile(sessionId, filePath);\n if (!result.ok) {\n storeError(sessionId, filePath, result.error);\n setConfirmingDelete(false);\n } else {\n setConfirmingDelete(false);\n closeTransientTab(fileTabId(filePath));\n }\n } catch (failure) {\n storeError(sessionId, filePath, failure instanceof Error ? failure.message : String(failure));\n setConfirmingDelete(false);\n } finally {\n setBusy(false);\n }\n };\n const sendReview = () => {\n if (sessionId === null || comments.length === 0) return;\n const message =\n `I left ${comments.length} review ${comments.length === 1 ? 'comment' : 'comments'} on files you changed. Please address them.\\n\\n` +\n comments\n .map((comment) => {\n const anchor =\n comment.startLine === undefined\n ? comment.relPath\n : comment.side === 'old'\n ? `${comment.relPath} (removed line ${comment.startLine})`\n : `${comment.relPath}:${comment.startLine}`;\n return `### ${anchor}\\n\\n${comment.snippet\n .split('\\n')\n .slice(0, 20)\n .join('\\n')\n .slice(0, 2000)\n .split('\\n')\n .map((line) => `> ${line}`)\n .join('\\n')}\\n\\n${comment.body.trim()}`;\n })\n .join('\\n\\n');\n try {\n sendSessionFrame(sessionId, { type: 'follow_up', message });\n clearComments(sessionId, filePath);\n setReviewError(undefined);\n } catch (failure) {\n setReviewError(failure instanceof Error ? failure.message : String(failure));\n }\n };\n\n return (\n <ScrollView testID=\"files-file-panel\" contentContainerStyle={styles.panel}>\n <View style={styles.header}>\n <Text selectable style={styles.path}>\n {relPath}\n </Text>\n <DropdownMenu>\n <DropdownMenuTrigger variant=\"ghost\" size=\"icon\" accessibilityLabel=\"file actions\">\n <KebabIcon />\n </DropdownMenuTrigger>\n <DropdownMenuContent>\n <DropdownMenuItem\n disabled={sessionId === null || outside || busy || !props.nativeSaveFile}\n onSelect={() => void download()}\n >\n download\n </DropdownMenuItem>\n {busy ? (\n <DropdownMenuItem onSelect={() => downloadController.current?.abort()}>cancel download</DropdownMenuItem>\n ) : null}\n <DropdownMenuItem disabled={!writable} onSelect={() => setView('edit')}>\n edit\n </DropdownMenuItem>\n <DropdownMenuItem variant=\"destructive\" disabled={!writable} onSelect={() => setConfirmingDelete(true)}>\n delete\n </DropdownMenuItem>\n <DropdownMenuItem onSelect={() => closeTransientTab(fileTabId(filePath))}>close</DropdownMenuItem>\n </DropdownMenuContent>\n </DropdownMenu>\n </View>\n {view !== 'edit' && note ? <Text style={note === 'saved' ? styles.success : styles.error}>{note}</Text> : null}\n <SegmentedControl\n accessibilityLabel=\"file view\"\n options={[\n { value: 'preview', label: 'preview' },\n { value: 'diff', label: 'diff' },\n ]}\n value={view}\n onValueChange={setView}\n />\n {view === 'edit' ? <Text style={styles.meta}>editing</Text> : null}\n {session.loading.includes(filePath) && !detail ? (\n <Text style={styles.meta}>reading this file's history…</Text>\n ) : null}\n {session.errors[filePath] ? (\n <Text accessibilityRole=\"alert\" style={styles.error}>\n {session.errors[filePath]}\n </Text>\n ) : null}\n {detail ? (\n view === 'diff' ? (\n <>\n <Text style={styles.meta}>\n +{detail.cumulative.additions} -{detail.cumulative.removals}\n </Text>\n {detail.cumulative.note ? <Text style={styles.meta}>{detail.cumulative.note}</Text> : null}\n {detail.cumulative.hunks ? <Diff hunks={detail.cumulative.hunks} comment={setDraft} /> : null}\n <Text style={styles.title}>{detail.versions.length} changes this session</Text>\n {detail.versions.map((version) => (\n <View key={version.index}>\n <Button\n variant=\"ghost\"\n accessibilityState={{ expanded: expanded === version.index }}\n onPress={() => setExpanded(expanded === version.index ? undefined : version.index)}\n >\n #{version.index} {version.tool} +{version.additions} -{version.removals}\n {version.origin === 'scan' ? ' · no baseline' : ''}\n </Button>\n {expanded === version.index ? (\n version.hunks ? (\n <Diff hunks={version.hunks} comment={setDraft} />\n ) : (\n <Text style={styles.meta}>{version.note ?? 'nothing to show'}</Text>\n )\n ) : null}\n </View>\n ))}\n </>\n ) : view === 'edit' ? (\n <>\n {writable ? (\n <>\n <Textarea\n accessibilityLabel=\"file source\"\n value={source ?? working?.content ?? ''}\n onChangeText={setSource}\n rows={12}\n onSelectionChange={(event) => {\n const content = source ?? working?.content ?? '';\n const { start, end } = event.nativeEvent.selection;\n setSelection(\n end > start\n ? {\n snippet: content.slice(start, end),\n startLine: content.slice(0, start).split('\\n').length,\n endLine: content.slice(0, end).split('\\n').length,\n }\n : undefined,\n );\n }}\n />\n <View style={styles.actions}>\n <Button variant=\"primary\" disabled={source === undefined || busy} onPress={() => void save()}>\n save to disk\n </Button>\n <Button variant=\"ghost\" disabled={source === undefined} onPress={() => setSource(undefined)}>\n discard edits\n </Button>\n </View>\n <Button variant=\"ghost\" disabled={!selection} onPress={() => setDraft(selection)}>\n comment on selection\n </Button>\n </>\n ) : (\n <Text style={styles.meta}>{working?.reason ?? 'this file cannot be edited'}</Text>\n )}\n {note ? <Text style={note === 'saved' ? styles.success : styles.error}>{note}</Text> : null}\n </>\n ) : working ? (\n <FilePreview {...props} path={relPath} working={{ ...working, content: source ?? working.content }} />\n ) : null\n ) : null}\n {detail && sessionId !== null ? (\n <Button variant=\"ghost\" onPress={() => setDraft({ snippet: '' })}>\n add review comment\n </Button>\n ) : null}\n {comments.length ? (\n <View style={styles.diff}>\n <Button variant=\"outline\" disabled={sessionId === null} onPress={sendReview}>\n send review ({comments.length})\n </Button>\n {reviewError ? (\n <Text accessibilityRole=\"alert\" style={styles.error}>\n review not sent: {reviewError}\n </Text>\n ) : null}\n {comments.map((comment) => (\n <View key={comment.id}>\n <Text style={styles.meta}>\n {comment.relPath}\n {comment.startLine === undefined ? '' : `:${comment.startLine}`} · {comment.body}\n </Text>\n <Button\n variant=\"ghost\"\n onPress={() => {\n if (sessionId !== null) removeComment(sessionId, comment.id);\n }}\n >\n remove comment\n </Button>\n </View>\n ))}\n </View>\n ) : null}\n {draft ? (\n <ReviewSheet\n selection={draft}\n close={() => setDraft(undefined)}\n submit={(body, snippet) => {\n if (sessionId !== null)\n addComment(sessionId, {\n id: `${filePath}:${draft.side ?? 'new'}:${draft.startLine ?? 0}:${comments.length}:${body.length}`,\n path: filePath,\n relPath,\n ...draft,\n snippet,\n body,\n });\n setDraft(undefined);\n }}\n />\n ) : null}\n {confirmingDelete ? (\n <Sheet\n open\n onOpenChange={(open) => {\n if (!open) setConfirmingDelete(false);\n }}\n >\n <SheetContent>\n <SheetHeader>\n <SheetTitle>delete file</SheetTitle>\n </SheetHeader>\n <SheetBody>\n <Text style={styles.meta}>This removes {relPath} from disk. It cannot be undone here.</Text>\n <View style={styles.actions}>\n <Button variant=\"ghost\" onPress={() => setConfirmingDelete(false)}>\n cancel\n </Button>\n <Button variant=\"danger\" disabled={!writable || busy} onPress={() => void remove()}>\n delete\n </Button>\n </View>\n </SheetBody>\n </SheetContent>\n </Sheet>\n ) : null}\n </ScrollView>\n );\n}\n\nexport function fileTab(filePath: string, relPath: string): Parameters<WebPluginSlotProps['openTransientTab']>[0] {\n return {\n id: fileTabId(filePath),\n label: relPath.split('/').at(-1) ?? relPath,\n panel: (props) => <FilePanel {...props} filePath={filePath} relPath={relPath} />,\n };\n}\n\nconst styles = StyleSheet.create((theme: PoNativeTheme) => ({\n panel: { padding: theme.spacing(4), gap: theme.spacing(3) },\n header: { flexDirection: 'row', alignItems: 'center', gap: theme.spacing(2) },\n actions: { flexDirection: 'row', flexWrap: 'wrap', gap: theme.spacing(2) },\n diff: { gap: theme.spacing(2) },\n title: { fontSize: theme.fontSize.base, fontWeight: '600', color: theme.colors.hi },\n path: { flex: 1, fontFamily: fontOf(theme.fontFamily.mono), fontSize: theme.fontSize.base, color: theme.colors.hi },\n code: { fontFamily: fontOf(theme.fontFamily.mono), fontSize: theme.fontSize.sm, color: theme.colors.text },\n added: { fontFamily: fontOf(theme.fontFamily.mono), fontSize: theme.fontSize.sm, color: theme.colors.green },\n removed: { fontFamily: fontOf(theme.fontFamily.mono), fontSize: theme.fontSize.sm, color: theme.colors.red },\n meta: { fontSize: theme.fontSize.sm, color: theme.colors.dim },\n error: { fontSize: theme.fontSize.sm, color: theme.colors.red },\n success: { fontSize: theme.fontSize.sm, color: theme.colors.green },\n}));\n","import type { WebPluginSlotProps } from '@agimon-ai/po-core/native';\nimport {\n Button,\n Input,\n ListRow,\n Sheet,\n SheetContent,\n SheetHeader,\n SheetTitle,\n SheetBody,\n} from '@agimon-ai/po-native-components';\nimport { useCallback, useState, useSyncExternalStore } from 'react';\nimport { Text, View } from 'react-native';\n\nimport type { FilesItemView } from '../../../../../../types/webFiles';\nimport { fileTab } from '../../_components/FilePanel.native';\nimport { files } from '../../_lib/filesStore.native';\n\n/** The latest changes and a searchable complete picker, backed by the native channel store. */\nexport function FilesActivitySection({ sessionId, openTransientTab }: WebPluginSlotProps) {\n const subscribe = useCallback((listener: () => void) => {\n const subscription = files.store.subscribe(listener);\n return () => subscription.unsubscribe();\n }, []);\n const { items } = useSyncExternalStore(subscribe, () => files.select(files.store.state, sessionId));\n const [open, setOpen] = useState(false);\n const [query, setQuery] = useState('');\n const choose = (item: FilesItemView) => {\n if (sessionId !== null) {\n openTransientTab(fileTab(item.path, item.relPath));\n setOpen(false);\n }\n };\n const row = (item: FilesItemView) => (\n <ListRow\n key={item.path}\n title={item.relPath}\n description={`${item.tool === 'bash' ? 'command' : item.tool === 'user' ? 'you' : item.tool}${item.count > 1 ? ` · ${item.count}×` : ''}${item.diffable ? '' : ' · no baseline'}`}\n disabled={sessionId === null}\n onPress={() => choose(item)}\n />\n );\n if (!items.length) return <Text>nothing changed yet</Text>;\n return (\n <View>\n {items.slice(0, 5).map(row)}\n {items.length > 5 ? (\n <Button variant=\"ghost\" onPress={() => setOpen(true)}>\n show all {items.length} files\n </Button>\n ) : null}\n {open ? (\n <Sheet open onOpenChange={setOpen}>\n <SheetContent>\n <SheetHeader>\n <SheetTitle>changed files</SheetTitle>\n </SheetHeader>\n <SheetBody>\n <Input\n accessibilityLabel=\"search changed file paths\"\n value={query}\n onChangeText={setQuery}\n placeholder=\"search paths…\"\n />\n {items\n .filter((item) => item.relPath.toLocaleLowerCase().includes(query.trim().toLocaleLowerCase()))\n .map(row)}\n </SheetBody>\n </SheetContent>\n </Sheet>\n ) : null}\n </View>\n );\n}\n","import { defineFill } from '@agimon-ai/po-core/native';\n\nimport { FilesActivitySection } from './_components/FilesActivitySection.native';\nexport default defineFill({ slot: 'activity.files', id: 'files', component: FilesActivitySection });\n","// Generated by @agimon-ai/po-build. Do not edit by hand.\nimport { defineNativePlugin, type WebPluginContributions } from '@agimon-ai/po-core/native';\n\nimport activityGroupFiles from '../src/extensions/workspaces/sessions/(frontend)/activity-group/files.native';\nimport channelFileEdits from '../src/extensions/workspaces/sessions/(frontend)/channel/file-edits.native';\nimport fillFiles from '../src/extensions/workspaces/sessions/(frontend)/fill/Files.activity.files.native';\n\nconst via = <T>(identity: Record<string, unknown>, value: unknown): T =>\n (value === undefined ? undefined : { ...identity, ...(value as object) }) as T;\n\nexport const nativePlugin = defineNativePlugin({\n id: 'files',\n session: {\n get activityGroups(): WebPluginContributions['activityGroups'] { return [via({ name: 'files' }, activityGroupFiles)]; },\n get channels(): WebPluginContributions['channels'] { return [via({ channel: 'file_edits' }, channelFileEdits)]; },\n get fills(): WebPluginContributions['fills'] { return [via({ slot: 'activity.files', id: 'files' }, fillFiles)]; },\n },\n});\n"],"mappings":"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"}
1
+ {"version":3,"file":"native.mjs","names":["channelFileEdits"],"sources":["../../src/types/webFiles.ts","../../src/extensions/workspaces/sessions/(frontend)/_lib/filesModel.ts","../../src/extensions/workspaces/sessions/(frontend)/_lib/filesStore.native.ts","../../src/extensions/workspaces/sessions/(frontend)/channel/file-edits.native.ts","../../generated/native.ts"],"sourcesContent":["import type { FileEditTool } from './domain';\n\n/**\n * View types shared by this package's hub channel and its web plugin. Wire\n * JSON only, no node types, so the cockpit bundle can carry them; the\n * cockpit receives them as 'file_edits' channel payloads.\n *\n * The channel carries the list alone. One file's diffs and content are large\n * and only wanted once a reader opens the file, so those come from the session\n * API instead (see fileEditsApi.ts).\n */\n\n/** One file this session changed, as the activity dock lists it. */\nexport interface FilesItemView {\n /** Absolute path, and the identity every API route takes back. */\n path: string;\n /** Path relative to the session's working directory, which is what a row shows. */\n relPath: string;\n /** The tool behind the most recent change. */\n tool: FileEditTool;\n /** When that change happened, epoch milliseconds. */\n at: number;\n /** How many changes this session recorded for the file. */\n count: number;\n /**\n * Whether any change captured a baseline, so a diff can be shown at all. A\n * file found by comparing the tree around a bash call has no \"before\", so it\n * is listed and readable but never diffed.\n */\n diffable: boolean;\n}\n\n/** The frame type the hub publishes and the web plugin claims; declared in the poWeb block too. */\nexport const filesChannelType = 'file_edits';\n\n/** Footer status key whose presence shows the activity group; the extension publishes it. */\nexport const filesStatusKey = 'po-file-edit-files';\n","import type { FilesItemView } from '../../../../../types/webFiles';\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n\nfunction isItem(value: unknown): value is FilesItemView {\n return (\n isRecord(value) &&\n typeof value.path === 'string' &&\n typeof value.relPath === 'string' &&\n typeof value.tool === 'string' &&\n typeof value.at === 'number' &&\n typeof value.count === 'number'\n );\n}\n\nexport interface FilesPayload {\n items: FilesItemView[];\n}\n\n/** The shared wire gate for browser and native stores. */\nexport function parseFilesPayload(input: unknown): FilesPayload | null {\n if (!isRecord(input) || !Array.isArray(input.items)) return null;\n return { items: input.items.filter(isItem) };\n}\n","import { defineSessionStore } from '@agimon-ai/po-core/native';\nimport type { ReviewComment } from '@agimon-ai/po-web-components';\n\nimport type { FileEditsDetailView } from '../../../../../types/fileEditsApi';\nimport { filesChannelType, type FilesItemView } from '../../../../../types/webFiles';\nimport { parseFilesPayload, type FilesPayload } from './filesModel';\nexport type { FilesPayload } from './filesModel';\n\n/**\n * One session's record: the hub's last report plus whatever this page does with\n * it. Records are immutable values; the reducer and every action return a new one.\n *\n * Detail is cached per file rather than per open tab, because a reader closes a\n * file and comes back to it, and refetching the same history for the same click\n * is work the session already did.\n */\nexport interface FilesSession {\n items: FilesItemView[];\n /** One file's fetched history, keyed by absolute path. */\n detail: Readonly<Record<string, FileEditsDetailView>>;\n /** Paths with a detail request in flight, so a panel can say it is loading. */\n loading: readonly string[];\n /** What a failed fetch or a refused save reported, keyed by absolute path. */\n errors: Readonly<Record<string, string>>;\n /** Review notes waiting to be sent, in the order they were written. */\n comments: readonly ReviewComment[];\n}\n\nconst empty: FilesSession = { items: [], detail: {}, loading: [], errors: {}, comments: [] };\n\nexport const files = defineSessionStore<FilesSession>(empty);\n\n/** The plugin's session data channel: 'file_edits' payloads into the store. */\nexport const filesChannel = files.channel<FilesPayload>({\n channel: filesChannelType,\n parse: parseFilesPayload,\n // Only the list is replaced. The cached detail and the pending notes belong\n // to files a reader opened, not to the list: a file the session deletes stops\n // being listed, and pruning here would blank the tab still open on it and\n // then refetch it on the next frame.\n reduce: (current, { items }) => ({ ...current, items }),\n});\n\nexport function markLoading(sessionId: string, filePath: string): void {\n files.update(sessionId, (current) =>\n current.loading.includes(filePath)\n ? current\n : { ...current, loading: [...current.loading, filePath], errors: withoutKey(current.errors, filePath) },\n );\n}\n\nexport function storeDetail(sessionId: string, detail: FileEditsDetailView): void {\n files.update(sessionId, (current) => ({\n ...current,\n detail: { ...current.detail, [detail.path]: detail },\n loading: current.loading.filter((path) => path !== detail.path),\n errors: withoutKey(current.errors, detail.path),\n }));\n}\n\nexport function storeError(sessionId: string, filePath: string, message: string): void {\n files.update(sessionId, (current) => ({\n ...current,\n loading: current.loading.filter((path) => path !== filePath),\n errors: { ...current.errors, [filePath]: message },\n }));\n}\n\nexport function addComment(sessionId: string, comment: ReviewComment): void {\n files.update(sessionId, (current) => ({ ...current, comments: [...current.comments, comment] }));\n}\n\nexport function removeComment(sessionId: string, id: string): void {\n files.update(sessionId, (current) => ({\n ...current,\n comments: current.comments.filter((comment) => comment.id !== id),\n }));\n}\n\nexport function clearComments(sessionId: string, filePath: string): void {\n files.update(sessionId, (current) => ({\n ...current,\n comments: current.comments.filter((comment) => comment.path !== filePath),\n }));\n}\n\nfunction withoutKey(source: Readonly<Record<string, string>>, key: string): Record<string, string> {\n return Object.fromEntries(Object.entries(source).filter(([entry]) => entry !== key));\n}\n","import { defineChannelFile } from '@agimon-ai/po-core/native';\n\nimport { filesChannel } from '../_lib/filesStore.native';\nexport default defineChannelFile(filesChannel);\n","// Generated by @agimon-ai/po-build. Do not edit by hand.\nimport { defineNativePlugin, type WebPluginContributions } from '@agimon-ai/po-core/native';\n\nimport channelFileEdits from '../src/extensions/workspaces/sessions/(frontend)/channel/file-edits.native';\n\nconst via = <T>(identity: Record<string, unknown>, value: unknown): T =>\n (value === undefined ? undefined : { ...identity, ...(value as object) }) as T;\n\nexport const nativePlugin = defineNativePlugin({\n id: 'files',\n session: {\n get channels(): WebPluginContributions['channels'] { return [via({ channel: 'file_edits' }, channelFileEdits)]; },\n },\n});\n"],"mappings":";;;AAiCA,MAAa,mBAAmB;;;AC/BhC,SAAS,SAAS,OAAkD;CAClE,OAAO,OAAO,UAAU,YAAY,UAAU,QAAQ,CAAC,MAAM,QAAQ,KAAK;AAC5E;AAEA,SAAS,OAAO,OAAwC;CACtD,OACE,SAAS,KAAK,KACd,OAAO,MAAM,SAAS,YACtB,OAAO,MAAM,YAAY,YACzB,OAAO,MAAM,SAAS,YACtB,OAAO,MAAM,OAAO,YACpB,OAAO,MAAM,UAAU;AAE3B;;AAOA,SAAgB,kBAAkB,OAAqC;CACrE,IAAI,CAAC,SAAS,KAAK,KAAK,CAAC,MAAM,QAAQ,MAAM,KAAK,GAAG,OAAO;CAC5D,OAAO,EAAE,OAAO,MAAM,MAAM,OAAO,MAAM,EAAE;AAC7C;;ACQA,MAAa,eAHQ,mBAAiC;CAFxB,OAAO,CAAC;CAAG,QAAQ,CAAC;CAAG,SAAS,CAAC;CAAG,QAAQ,CAAC;CAAG,UAAU,CAAC;AAEnC,CAG1B,CAAA,CAAM,QAAsB;CACtD,SAAS;CACT,OAAO;CAKP,SAAS,SAAS,EAAE,aAAa;EAAE,GAAG;EAAS;CAAM;AACvD,CAAC;;;ACtCD,IAAA,4BAAe,kBAAkB,YAAY;;;ACE7C,MAAM,OAAU,UAAmC,UAChD,UAAU,KAAA,IAAY,KAAA,IAAY;CAAE,GAAG;CAAU,GAAI;AAAiB;AAEzE,MAAa,eAAe,mBAAmB;CAC7C,IAAI;CACJ,SAAS,EACP,IAAI,WAA+C;EAAE,OAAO,CAAC,IAAI,EAAE,SAAS,aAAa,GAAGA,yBAAgB,CAAC;CAAG,EAClH;AACF,CAAC"}