@hediet/linkrpc-cli 0.0.2 → 0.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +33 -1
- package/dist/chunks/{cli-D_-vlAa2.js → cli-FDKN1ydZ.js} +55 -15
- package/dist/chunks/cli-FDKN1ydZ.js.map +1 -0
- package/dist/chunks/{runApprovalUi-BvJZdjKm.js → runApprovalUi-CTyhiDpa.js} +3 -3
- package/dist/chunks/{runApprovalUi-BvJZdjKm.js.map → runApprovalUi-CTyhiDpa.js.map} +1 -1
- package/dist/chunks/{runComplete-BkQwzPbF.js → runComplete-Du5wmOdB.js} +12 -72
- package/dist/chunks/runComplete-Du5wmOdB.js.map +1 -0
- package/dist/chunks/{runUi-D-8LMU4F.js → runUi-CuJr8_tY.js} +4 -4
- package/dist/chunks/{runUi-D-8LMU4F.js.map → runUi-CuJr8_tY.js.map} +1 -1
- package/dist/chunks/{scroll-BTzAYh4N.js → scroll--AVfTs5W.js} +2 -2
- package/dist/chunks/{scroll-BTzAYh4N.js.map → scroll--AVfTs5W.js.map} +1 -1
- package/dist/hub.js +1 -1
- package/dist/index.js +1 -1
- package/dist/linkrpc.js +1 -1
- package/dist/rpc.js +1 -1
- package/package.json +10 -5
- package/dist/chunks/cli-D_-vlAa2.js.map +0 -1
- package/dist/chunks/runComplete-BkQwzPbF.js.map +0 -1
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { a as observableValue, n as approvalDetailLines } from "./cli-
|
|
2
|
-
import { n as useObservable, t as useScroll } from "./scroll
|
|
1
|
+
import { a as observableValue, n as approvalDetailLines } from "./cli-FDKN1ydZ.js";
|
|
2
|
+
import { n as useObservable, t as useScroll } from "./scroll--AVfTs5W.js";
|
|
3
3
|
import { jcsCanonicalize } from "@hediet/linkrpc";
|
|
4
4
|
import React from "react";
|
|
5
5
|
import { Box, Text, render, useApp, useInput, useStdout } from "ink";
|
|
@@ -712,4 +712,4 @@ function raceAbort(promise, signal) {
|
|
|
712
712
|
//#endregion
|
|
713
713
|
export { runApprovalUi };
|
|
714
714
|
|
|
715
|
-
//# sourceMappingURL=runApprovalUi-
|
|
715
|
+
//# sourceMappingURL=runApprovalUi-CTyhiDpa.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"runApprovalUi-BvJZdjKm.js","names":[],"sources":["../../src/approval-ui/ApprovalApp.tsx","../../src/approval-ui/ApprovalUiModel.ts","../../src/approval-ui/runApprovalUi.tsx"],"sourcesContent":["import React from 'react';\nimport { Box, Text, useApp, useInput, useStdout } from 'ink';\nimport TextInput from 'ink-text-input';\nimport type { PendingApprovalRequest } from '../commands/approval';\nimport {\n approvalDetailLines,\n type ApprovalPresentationLine as DetailLine,\n} from '../approvalPresentation';\nimport { useObservable } from '../ui/useObservable';\nimport { useScroll } from '../ui/scroll';\nimport { ApprovalUiModel, type ApprovalUiMessageKind } from './ApprovalUiModel';\n\nexport { approvalDetailLines } from '../approvalPresentation';\n\nexport interface ApprovalAppProps {\n readonly model: ApprovalUiModel;\n}\n\ninterface TerminalSize {\n readonly columns: number;\n readonly rows: number;\n}\n\nconst HEADER_HEIGHT = 2;\nconst FOOTER_HEIGHT = 2;\nconst PANE_CHROME_HEIGHT = 3;\nconst MIN_FULL_HEIGHT = 13;\nconst SPLIT_COLUMNS = 96;\n\nexport const ApprovalApp: React.FC<ApprovalAppProps> = ({ model }) => {\n const requests = useObservable(model.requests);\n const selectedId = useObservable(model.selectedRequestId);\n const connectionState = useObservable(model.connectionState);\n const mode = useObservable(model.mode);\n const busy = useObservable(model.busy);\n const message = useObservable(model.message);\n const denialReason = useObservable(model.denialReason);\n const detailOffset = useObservable(model.detailOffset);\n const preparedApproval = useObservable(model.preparedApproval);\n const size = useTerminalSize();\n const { exit } = useApp();\n\n const selectedIndex = requests.findIndex((item) => item.id === selectedId);\n const selected = selectedIndex >= 0 ? requests[selectedIndex] : undefined;\n const rawDetails = selected === undefined\n ? []\n : approvalDetailLines(selected, mode === 'approve' ? preparedApproval : undefined);\n const bodyHeight = Math.max(1, size.rows - HEADER_HEIGHT - FOOTER_HEIGHT);\n const sideBySide = size.columns >= SPLIT_COLUMNS;\n const listPaneHeight = sideBySide ? bodyHeight : Math.max(5, Math.floor(bodyHeight * 0.42));\n const detailPaneHeight = sideBySide ? bodyHeight : Math.max(1, bodyHeight - listPaneHeight);\n const detailViewport = Math.max(1, detailPaneHeight - PANE_CHROME_HEIGHT);\n const detailPaneWidth = sideBySide ? Math.floor(size.columns * 0.62) : size.columns;\n const details = wrapDetailLines(rawDetails, Math.max(1, detailPaneWidth - 6));\n const approvalReviewed = mode === 'approve'\n && preparedApproval !== undefined\n && details.length > 0\n && detailOffset + detailViewport >= details.length;\n\n useInput((input, key) => {\n const canReviewAuthority = size.rows >= MIN_FULL_HEIGHT;\n if (busy) return;\n if (mode === 'deny') {\n if (key.escape) model.cancelMode();\n return;\n }\n if (mode === 'approve') {\n if (key.escape) {\n model.cancelMode();\n } else if (key.pageUp) {\n model.scrollDetails(-detailViewport, details.length, detailViewport);\n } else if (key.pageDown) {\n model.scrollDetails(detailViewport, details.length, detailViewport);\n } else if (key.return && canReviewAuthority && approvalReviewed) {\n void model.confirmCurrentMode();\n }\n return;\n }\n if (mode === 'help') {\n if (key.escape || input === '?' || input === 'q') model.cancelMode();\n return;\n }\n if (input === 'q') {\n exit();\n } else if (input === '?' || key.f1) {\n model.showHelp();\n } else if (input === 'a' && canReviewAuthority) {\n void model.beginApprove();\n } else if (input === 'd' && canReviewAuthority) {\n model.beginDeny();\n } else if (input === 'r') {\n void model.refresh();\n } else if (key.upArrow || input === 'k') {\n model.selectBy(-1);\n } else if (key.downArrow || input === 'j') {\n model.selectBy(1);\n } else if (key.pageUp) {\n model.scrollDetails(-detailViewport, details.length, detailViewport);\n } else if (key.pageDown) {\n model.scrollDetails(detailViewport, details.length, detailViewport);\n }\n });\n\n if (size.rows < MIN_FULL_HEIGHT) {\n return (\n <CompactApprovalApp\n model={model}\n selected={selected}\n requestCount={requests.length}\n connectionState={connectionState}\n mode={mode}\n busy={busy}\n message={message}\n rows={size.rows}\n />\n );\n }\n\n return (\n <Box flexDirection=\"column\" height={size.rows} width={size.columns}>\n <Header\n principalId={model.principalId}\n state={connectionState}\n requestCount={requests.length}\n />\n {mode === 'help' ? (\n <Help height={bodyHeight} />\n ) : (\n <Box\n flexDirection={sideBySide ? 'row' : 'column'}\n height={bodyHeight}\n >\n <RequestList\n requests={requests}\n selectedIndex={selectedIndex}\n height={listPaneHeight}\n width={sideBySide ? '38%' : '100%'}\n />\n <RequestDetails\n selected={selected}\n lines={details}\n offset={detailOffset}\n height={detailPaneHeight}\n width={sideBySide ? '62%' : '100%'}\n />\n </Box>\n )}\n <Footer\n mode={mode}\n busy={busy}\n message={message}\n selected={selected}\n denialReason={denialReason}\n approvalReviewed={approvalReviewed}\n onReasonChange={(value) => model.setDenialReason(value)}\n onDeny={() => void model.confirmCurrentMode()}\n />\n </Box>\n );\n};\n\nconst Header: React.FC<{\n principalId: string;\n state: 'connecting' | 'live' | 'stale';\n requestCount: number;\n}> = ({ principalId, state, requestCount }) => (\n <Box flexDirection=\"column\" height={HEADER_HEIGHT}>\n <Box justifyContent=\"space-between\">\n <Text bold>Hub access approvals</Text>\n <Text color={state === 'live' ? 'green' : state === 'stale' ? 'yellow' : 'cyan'}>\n {state === 'live' ? '● live' : state === 'stale' ? '● reconnecting' : '○ connecting'}\n <Text color=\"white\"> {requestCount} pending</Text>\n </Text>\n </Box>\n <Text dimColor wrap=\"truncate-end\">approver: {safeTerminalText(principalId)}</Text>\n </Box>\n);\n\nconst RequestList: React.FC<{\n requests: readonly PendingApprovalRequest[];\n selectedIndex: number;\n height: number;\n width: number | `${number}%`;\n}> = ({ requests, selectedIndex, height, width }) => {\n const viewport = Math.max(1, height - PANE_CHROME_HEIGHT);\n const window = useScroll(requests.length, Math.max(0, selectedIndex), viewport);\n\n return (\n <Pane title=\"Requests\" height={height} width={width}>\n {requests.length === 0 ? (\n <Box flexDirection=\"column\">\n <Text color=\"green\">No pending access requests.</Text>\n <Text dimColor>Watching the Hub for new requests...</Text>\n </Box>\n ) : (\n <>\n <ScrollMarker direction=\"up\" count={window.above} />\n {requests.slice(window.start, window.end).map((item, index) => {\n const actualIndex = window.start + index;\n const selected = actualIndex === selectedIndex;\n const duration = item.request.duration ?? 'unspecified';\n return (\n <Text\n key={item.id}\n color={selected ? 'cyan' : undefined}\n bold={selected}\n inverse={selected}\n wrap=\"truncate-end\"\n >\n {selected ? '› ' : ' '}\n {safeTerminalText(item.request.consumer.name)}\n <Text dimColor>\n {' '}{safeTerminalText(item.request.kind)} / {safeTerminalText(duration)}\n </Text>\n </Text>\n );\n })}\n <ScrollMarker direction=\"down\" count={window.below} />\n </>\n )}\n </Pane>\n );\n};\n\nconst RequestDetails: React.FC<{\n selected: PendingApprovalRequest | undefined;\n lines: readonly DetailLine[];\n offset: number;\n height: number;\n width: number | `${number}%`;\n}> = ({ selected, lines, offset, height, width }) => {\n const viewport = Math.max(1, height - PANE_CHROME_HEIGHT);\n const safeOffset = Math.min(offset, Math.max(0, lines.length - viewport));\n const visible = lines.slice(safeOffset, safeOffset + viewport);\n const range = lines.length > viewport\n ? ` (${safeOffset + 1}-${safeOffset + visible.length} of ${lines.length})`\n : '';\n\n return (\n <Pane title={`Request details${range}`} height={height} width={width}>\n {selected === undefined ? (\n <Text dimColor>Select a request to inspect its exact authority.</Text>\n ) : (\n <>\n {visible.map((line, index) => (\n <Text\n key={`${safeOffset + index}:${line.label ?? ''}:${line.text}`}\n color={line.tone === 'warning' ? 'yellow' : undefined}\n dimColor={line.tone === 'muted'}\n wrap=\"truncate-end\"\n >\n {line.label !== undefined && <Text bold>{safeTerminalText(line.label)}: </Text>}\n {safeTerminalText(line.text) || '—'}\n </Text>\n ))}\n </>\n )}\n </Pane>\n );\n};\n\nconst Footer: React.FC<{\n mode: 'browse' | 'approve' | 'deny' | 'help';\n busy: boolean;\n message: { readonly kind: ApprovalUiMessageKind; readonly text: string } | undefined;\n selected: PendingApprovalRequest | undefined;\n denialReason: string;\n approvalReviewed: boolean;\n onReasonChange(value: string): void;\n onDeny(): void;\n}> = ({\n mode,\n busy,\n message,\n selected,\n denialReason,\n approvalReviewed,\n onReasonChange,\n onDeny,\n}) => {\n if (busy) {\n return (\n <Box flexDirection=\"column\" height={FOOTER_HEIGHT}>\n <Text color=\"cyan\">Working... The manifest will be rechecked before the decision is applied.</Text>\n <Text dimColor>Please wait.</Text>\n </Box>\n );\n }\n if (mode === 'approve') {\n return (\n <Box flexDirection=\"column\" height={FOOTER_HEIGHT}>\n <Text color=\"yellow\" wrap=\"truncate-end\">\n Approve all displayed authority for{' '}\n <Text bold>{safeTerminalText(selected?.request.consumer.name ?? '')}</Text>?\n </Text>\n {approvalReviewed ? (\n <Text><Text bold>Enter</Text> confirm <Text bold>Esc</Text> cancel</Text>\n ) : (\n <Text><Text bold>PgDn</Text> review all authority before confirming <Text bold>Esc</Text> cancel</Text>\n )}\n </Box>\n );\n }\n if (mode === 'deny') {\n return (\n <Box flexDirection=\"column\" height={FOOTER_HEIGHT}>\n <Box>\n <Text color=\"red\">Denial reason (optional): </Text>\n <TextInput value={denialReason} onChange={onReasonChange} onSubmit={onDeny} />\n </Box>\n <Text><Text bold>Enter</Text> deny <Text bold>Esc</Text> cancel</Text>\n </Box>\n );\n }\n\n return (\n <Box flexDirection=\"column\" height={FOOTER_HEIGHT}>\n <Text\n color={messageColor(message?.kind)}\n dimColor={message === undefined}\n wrap=\"truncate-end\"\n >\n {safeTerminalText(message?.text ?? 'Review the exact authority before approving.')}\n </Text>\n <Text dimColor wrap=\"truncate-end\">\n ↑/↓ or j/k select a approve d deny PgUp/PgDn details r refresh ? help q quit\n </Text>\n </Box>\n );\n};\n\nconst Help: React.FC<{ height: number }> = ({ height }) => (\n <Pane title=\"Keyboard help\" height={height} width=\"100%\">\n <Text><Text bold>↑/↓, j/k</Text> Move through pending requests</Text>\n <Text><Text bold>PgUp/PgDn</Text> Scroll long request details</Text>\n <Text><Text bold>a</Text> Review and confirm approval</Text>\n <Text><Text bold>d</Text> Deny with an optional reason</Text>\n <Text><Text bold>r</Text> Refresh the authoritative manifest snapshot</Text>\n <Text><Text bold>?, F1</Text> Toggle this help</Text>\n <Text><Text bold>q</Text> Quit without deciding remaining requests</Text>\n <Text dimColor>Press Esc, ?, or q to return.</Text>\n </Pane>\n);\n\nconst CompactApprovalApp: React.FC<{\n model: ApprovalUiModel;\n selected: PendingApprovalRequest | undefined;\n requestCount: number;\n connectionState: 'connecting' | 'live' | 'stale';\n mode: 'browse' | 'approve' | 'deny' | 'help';\n busy: boolean;\n message: { readonly kind: ApprovalUiMessageKind; readonly text: string } | undefined;\n rows: number;\n}> = ({\n model,\n selected,\n requestCount,\n connectionState,\n mode,\n busy,\n message,\n rows,\n}) => (\n <Box flexDirection=\"column\" height={Math.max(1, rows)}>\n <Text bold wrap=\"truncate-end\">Hub approvals {connectionState} {requestCount} pending</Text>\n <Text wrap=\"truncate-end\">\n {selected === undefined\n ? 'No pending access requests.'\n : safeTerminalText(\n `${selected.request.consumer.name} · ${selected.request.kind} · ${selected.request.duration ?? 'unspecified'}`,\n )}\n </Text>\n {rows >= 4 && (\n <Text color={messageColor(message?.kind)} wrap=\"truncate-end\">\n {safeTerminalText(busy ? 'Resolving request...' : message?.text ?? model.principalId)}\n </Text>\n )}\n {rows >= 5 && (\n <Text color=\"yellow\" wrap=\"truncate-end\">\n Enlarge to at least {MIN_FULL_HEIGHT} rows to review and decide. ↑/↓ select q quit\n </Text>\n )}\n </Box>\n);\n\nconst Pane: React.FC<{\n title: string;\n height: number;\n width: number | `${number}%`;\n children: React.ReactNode;\n}> = ({ title, height, width, children }) => (\n <Box\n flexDirection=\"column\"\n borderStyle=\"round\"\n borderColor=\"gray\"\n height={height}\n width={width}\n paddingX={1}\n overflow=\"hidden\"\n >\n <Text bold>{title}</Text>\n {children}\n </Box>\n);\n\nconst ScrollMarker: React.FC<{ direction: 'up' | 'down'; count: number }> = ({ direction, count }) => {\n if (count === 0) return null;\n return <Text dimColor>{direction === 'up' ? '▲' : '▼'} {count} more</Text>;\n};\n\nfunction wrapDetailLines(lines: readonly DetailLine[], width: number): readonly DetailLine[] {\n return lines.flatMap((line) => {\n const text = safeTerminalText(`${line.label === undefined ? '' : `${line.label}: `}${line.text || '—'}`);\n return wrapTerminalText(text, width).map((chunk) => ({\n text: chunk,\n ...(line.tone === undefined ? {} : { tone: line.tone }),\n }));\n });\n}\n\nfunction wrapTerminalText(text: string, width: number): readonly string[] {\n const lines: string[] = [];\n let current = '';\n let currentWidth = 0;\n for (const character of text) {\n const characterWidth = terminalCharacterWidth(character);\n if (current.length > 0 && currentWidth + characterWidth > width) {\n lines.push(current);\n current = '';\n currentWidth = 0;\n }\n current += character;\n currentWidth += characterWidth;\n }\n if (current.length > 0 || lines.length === 0) lines.push(current);\n return lines;\n}\n\nfunction terminalCharacterWidth(character: string): number {\n if (/^\\p{Mark}$/u.test(character)) return 0;\n return character.codePointAt(0)! <= 0x7e ? 1 : 2;\n}\n\nexport function safeTerminalText(text: string): string {\n let result = '';\n for (const character of text) {\n result += /^[\\p{Cc}\\p{Cf}\\p{Zl}\\p{Zp}]$/u.test(character)\n ? `\\\\u{${character.codePointAt(0)!.toString(16).padStart(4, '0')}}`\n : character;\n }\n return result;\n}\n\nfunction messageColor(kind: ApprovalUiMessageKind | undefined): 'red' | 'green' | 'cyan' | undefined {\n if (kind === 'error') return 'red';\n if (kind === 'success') return 'green';\n if (kind === 'info') return 'cyan';\n return undefined;\n}\n\nfunction useTerminalSize(): TerminalSize {\n const { stdout } = useStdout();\n const [size, setSize] = React.useState<TerminalSize>({\n columns: stdout.columns ?? 100,\n rows: stdout.rows ?? 30,\n });\n React.useEffect(() => {\n const onResize = () => setSize({\n columns: stdout.columns ?? 100,\n rows: stdout.rows ?? 30,\n });\n stdout.on('resize', onResize);\n return () => stdout.off('resize', onResize);\n }, [stdout]);\n return size;\n}\n","import { jcsCanonicalize } from '@hediet/linkrpc';\nimport { observableValue, type IObservable, type ISettableObservable } from '@vscode/observables';\nimport type {\n ApprovalSnapshot,\n ApprovalSubscription,\n ApprovalDecisionOutcome,\n PendingApprovalRequest,\n PreparedApproval,\n} from '../commands/approval';\n\nexport type ApprovalUiMode = 'browse' | 'approve' | 'deny' | 'help';\nexport type ApprovalUiMessageKind = 'info' | 'success' | 'error';\n\nexport interface ApprovalUiMessage {\n readonly kind: ApprovalUiMessageKind;\n readonly text: string;\n}\n\nexport interface ApprovalUiClient {\n readonly principalId: string;\n watch(listener: (snapshot: ApprovalSnapshot) => void): ApprovalSubscription;\n refresh(): Promise<void>;\n prepareApproval(requestId: string): Promise<PreparedApproval>;\n approvePrepared(prepared: PreparedApproval): Promise<ApprovalDecisionOutcome>;\n deny(\n requestId: string,\n reason?: string,\n expected?: PendingApprovalRequest,\n ): Promise<ApprovalDecisionOutcome>;\n}\n\nexport class ApprovalUiModel {\n private readonly _requests: ISettableObservable<readonly PendingApprovalRequest[]>;\n public readonly requests: IObservable<readonly PendingApprovalRequest[]>;\n private readonly _connectionState: ISettableObservable<ApprovalSnapshot['state']>;\n public readonly connectionState: IObservable<ApprovalSnapshot['state']>;\n private readonly _selectedRequestId: ISettableObservable<string | undefined>;\n public readonly selectedRequestId: IObservable<string | undefined>;\n private readonly _mode: ISettableObservable<ApprovalUiMode>;\n public readonly mode: IObservable<ApprovalUiMode>;\n private readonly _busy: ISettableObservable<boolean>;\n public readonly busy: IObservable<boolean>;\n private readonly _message: ISettableObservable<ApprovalUiMessage | undefined>;\n public readonly message: IObservable<ApprovalUiMessage | undefined>;\n private readonly _denialReason: ISettableObservable<string>;\n public readonly denialReason: IObservable<string>;\n private readonly _detailOffset: ISettableObservable<number>;\n public readonly detailOffset: IObservable<number>;\n private readonly _preparedApproval: ISettableObservable<PreparedApproval | undefined>;\n public readonly preparedApproval: IObservable<PreparedApproval | undefined>;\n\n private readonly _client: ApprovalUiClient;\n private readonly _subscription: ApprovalSubscription;\n private _disposed = false;\n\n constructor(client: ApprovalUiClient) {\n this._client = client;\n this._requests = observableValue(this, []);\n this.requests = this._requests;\n this._connectionState = observableValue(this, 'connecting');\n this.connectionState = this._connectionState;\n this._selectedRequestId = observableValue(this, undefined);\n this.selectedRequestId = this._selectedRequestId;\n this._mode = observableValue(this, 'browse');\n this.mode = this._mode;\n this._busy = observableValue(this, false);\n this.busy = this._busy;\n this._message = observableValue(this, undefined);\n this.message = this._message;\n this._denialReason = observableValue(this, '');\n this.denialReason = this._denialReason;\n this._detailOffset = observableValue(this, 0);\n this.detailOffset = this._detailOffset;\n this._preparedApproval = observableValue(this, undefined);\n this.preparedApproval = this._preparedApproval;\n this._subscription = client.watch((snapshot) => this._applySnapshot(snapshot));\n }\n\n public get principalId(): string {\n return this._client.principalId;\n }\n\n public get selectedRequest(): PendingApprovalRequest | undefined {\n const selectedId = this._selectedRequestId.get();\n return this._requests.get().find((item) => item.id === selectedId);\n }\n\n public selectBy(delta: number): void {\n if (this._busy.get() || this._mode.get() !== 'browse') return;\n const requests = this._requests.get();\n if (requests.length === 0) return;\n const currentIndex = Math.max(\n 0,\n requests.findIndex((item) => item.id === this._selectedRequestId.get()),\n );\n const nextIndex = Math.max(0, Math.min(requests.length - 1, currentIndex + delta));\n if (nextIndex === currentIndex) return;\n this._selectedRequestId.set(requests[nextIndex].id, undefined);\n this._detailOffset.set(0, undefined);\n }\n\n public showHelp(): void {\n if (this._busy.get()) return;\n this._mode.set('help', undefined);\n }\n\n public async beginApprove(): Promise<void> {\n if (!this._canDecide()) return;\n const selected = this.selectedRequest;\n if (selected === undefined) return;\n this._busy.set(true, undefined);\n this._message.set({ kind: 'info', text: 'Resolving exact authority...' }, undefined);\n try {\n const prepared = await this._client.prepareApproval(selected.id);\n if (\n this.selectedRequest?.id !== selected.id\n || jcsCanonicalize(this.selectedRequest.request)\n !== jcsCanonicalize(prepared.pending.request)\n ) {\n this._message.set({\n kind: 'info',\n text: 'The request changed while its authority was being resolved. Review it again.',\n }, undefined);\n return;\n }\n this._preparedApproval.set(prepared, undefined);\n this._detailOffset.set(0, undefined);\n this._mode.set('approve', undefined);\n this._message.set(undefined, undefined);\n } catch (error) {\n this._message.set({\n kind: 'error',\n text: error instanceof Error ? error.message : String(error),\n }, undefined);\n } finally {\n this._busy.set(false, undefined);\n }\n }\n\n public beginDeny(): void {\n if (!this._canDecide()) return;\n this._denialReason.set('', undefined);\n this._mode.set('deny', undefined);\n }\n\n public setDenialReason(reason: string): void {\n this._denialReason.set(reason, undefined);\n }\n\n public cancelMode(): void {\n if (this._busy.get()) return;\n this._mode.set('browse', undefined);\n this._denialReason.set('', undefined);\n this._preparedApproval.set(undefined, undefined);\n }\n\n public async confirmCurrentMode(): Promise<void> {\n const mode = this._mode.get();\n const selected = this.selectedRequest;\n if (this._busy.get() || selected === undefined || (mode !== 'approve' && mode !== 'deny')) return;\n\n this._busy.set(true, undefined);\n this._message.set({\n kind: 'info',\n text: mode === 'approve' ? 'Approving request...' : 'Denying request...',\n }, undefined);\n try {\n let outcome: ApprovalDecisionOutcome;\n if (mode === 'approve') {\n const prepared = this._preparedApproval.get();\n if (prepared === undefined) {\n throw new Error('approval details are no longer available; review the request again');\n }\n outcome = await this._client.approvePrepared(prepared);\n } else {\n const reason = this._denialReason.get().trim();\n outcome = await this._client.deny(\n selected.id,\n reason.length > 0 ? reason : undefined,\n selected,\n );\n }\n this._message.set({\n kind: outcome === 'applied' ? 'success' : 'info',\n text: outcome === 'applied'\n ? `${mode === 'approve' ? 'Approved' : 'Denied'} ${selected.request.consumer.name}.`\n : `Decision accepted for ${selected.request.consumer.name}, `\n + 'but a matching request is still pending. The consumer may have retried.',\n }, undefined);\n } catch (error) {\n this._message.set({\n kind: 'error',\n text: error instanceof Error ? error.message : String(error),\n }, undefined);\n } finally {\n this._busy.set(false, undefined);\n this._mode.set('browse', undefined);\n this._denialReason.set('', undefined);\n this._preparedApproval.set(undefined, undefined);\n }\n }\n\n public async refresh(): Promise<void> {\n if (this._busy.get()) return;\n this._message.set({ kind: 'info', text: 'Refreshing approval requests...' }, undefined);\n try {\n await this._client.refresh();\n if (this._connectionState.get() === 'live') {\n this._message.set({ kind: 'info', text: 'Approval requests are up to date.' }, undefined);\n }\n } catch (error) {\n this._message.set({\n kind: 'error',\n text: error instanceof Error ? error.message : String(error),\n }, undefined);\n }\n }\n\n public scrollDetails(delta: number, lineCount: number, viewportSize: number): void {\n const maxOffset = Math.max(0, lineCount - Math.max(1, viewportSize));\n const next = Math.max(0, Math.min(maxOffset, this._detailOffset.get() + delta));\n this._detailOffset.set(next, undefined);\n }\n\n public dispose(): void {\n if (this._disposed) return;\n this._disposed = true;\n this._subscription.dispose();\n }\n\n private _canDecide(): boolean {\n if (this._busy.get() || this.selectedRequest === undefined) return false;\n if (this._connectionState.get() !== 'live') {\n this._message.set({\n kind: 'error',\n text: 'Cannot decide requests while the approval connection is stale.',\n }, undefined);\n return false;\n }\n return true;\n }\n\n private _applySnapshot(snapshot: ApprovalSnapshot): void {\n const previous = this._requests.get();\n const selectedId = this._selectedRequestId.get();\n const previousSelected = previous.find((item) => item.id === selectedId);\n const previousIndex = Math.max(0, previous.findIndex((item) => item.id === selectedId));\n const selectedStillExists = snapshot.requests.some((item) => item.id === selectedId);\n const nextSelected = snapshot.requests.find((item) => item.id === selectedId);\n const selectedChanged = previousSelected !== undefined\n && nextSelected !== undefined\n && jcsCanonicalize(previousSelected.request) !== jcsCanonicalize(nextSelected.request);\n\n this._requests.set(snapshot.requests, undefined);\n this._connectionState.set(snapshot.state, undefined);\n\n if (snapshot.requests.length === 0) {\n this._selectedRequestId.set(undefined, undefined);\n this._detailOffset.set(0, undefined);\n } else if (!selectedStillExists) {\n const nextIndex = Math.min(previousIndex, snapshot.requests.length - 1);\n this._selectedRequestId.set(snapshot.requests[nextIndex].id, undefined);\n this._detailOffset.set(0, undefined);\n this._preparedApproval.set(undefined, undefined);\n }\n\n if (\n ((!selectedStillExists && selectedId !== undefined) || selectedChanged)\n && this._mode.get() !== 'browse'\n ) {\n this._mode.set('browse', undefined);\n this._denialReason.set('', undefined);\n this._preparedApproval.set(undefined, undefined);\n this._message.set({\n kind: 'info',\n text: selectedChanged\n ? 'The selected request changed. Review it again before deciding.'\n : 'The selected request is no longer pending.',\n }, undefined);\n }\n if (snapshot.state === 'stale' && snapshot.error !== undefined) {\n this._message.set({ kind: 'error', text: snapshot.error }, undefined);\n }\n }\n}\n","import React from 'react';\nimport { render } from 'ink';\nimport type { ApprovalCommandClient } from '../commands/approval';\nimport { ApprovalApp } from './ApprovalApp';\nimport { ApprovalUiModel } from './ApprovalUiModel';\n\nexport interface RunApprovalUiOptions {\n readonly client: ApprovalCommandClient;\n readonly signal: AbortSignal;\n}\n\nexport async function runApprovalUi(options: RunApprovalUiOptions): Promise<void> {\n const model = new ApprovalUiModel(options.client);\n const instance = render(<ApprovalApp model={model} />);\n const onAbort = () => instance.unmount();\n options.signal.addEventListener('abort', onAbort, { once: true });\n if (options.signal.aborted) onAbort();\n try {\n await raceAbort(model.refresh(), options.signal);\n if (options.signal.aborted) return;\n await instance.waitUntilExit();\n } finally {\n options.signal.removeEventListener('abort', onAbort);\n instance.unmount();\n model.dispose();\n }\n}\n\nfunction raceAbort<T>(promise: Promise<T>, signal: AbortSignal): Promise<T | undefined> {\n if (signal.aborted) return Promise.resolve(undefined);\n return new Promise<T | undefined>((resolve, reject) => {\n const onAbort = () => {\n signal.removeEventListener('abort', onAbort);\n resolve(undefined);\n };\n signal.addEventListener('abort', onAbort, { once: true });\n promise.then(\n (value) => {\n signal.removeEventListener('abort', onAbort);\n resolve(value);\n },\n (error: unknown) => {\n signal.removeEventListener('abort', onAbort);\n reject(error);\n },\n );\n });\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"runApprovalUi-CTyhiDpa.js","names":[],"sources":["../../src/approval-ui/ApprovalApp.tsx","../../src/approval-ui/ApprovalUiModel.ts","../../src/approval-ui/runApprovalUi.tsx"],"sourcesContent":["import React from 'react';\nimport { Box, Text, useApp, useInput, useStdout } from 'ink';\nimport TextInput from 'ink-text-input';\nimport type { PendingApprovalRequest } from '../commands/approval';\nimport {\n approvalDetailLines,\n type ApprovalPresentationLine as DetailLine,\n} from '../approvalPresentation';\nimport { useObservable } from '../ui/useObservable';\nimport { useScroll } from '../ui/scroll';\nimport { ApprovalUiModel, type ApprovalUiMessageKind } from './ApprovalUiModel';\n\nexport { approvalDetailLines } from '../approvalPresentation';\n\nexport interface ApprovalAppProps {\n readonly model: ApprovalUiModel;\n}\n\ninterface TerminalSize {\n readonly columns: number;\n readonly rows: number;\n}\n\nconst HEADER_HEIGHT = 2;\nconst FOOTER_HEIGHT = 2;\nconst PANE_CHROME_HEIGHT = 3;\nconst MIN_FULL_HEIGHT = 13;\nconst SPLIT_COLUMNS = 96;\n\nexport const ApprovalApp: React.FC<ApprovalAppProps> = ({ model }) => {\n const requests = useObservable(model.requests);\n const selectedId = useObservable(model.selectedRequestId);\n const connectionState = useObservable(model.connectionState);\n const mode = useObservable(model.mode);\n const busy = useObservable(model.busy);\n const message = useObservable(model.message);\n const denialReason = useObservable(model.denialReason);\n const detailOffset = useObservable(model.detailOffset);\n const preparedApproval = useObservable(model.preparedApproval);\n const size = useTerminalSize();\n const { exit } = useApp();\n\n const selectedIndex = requests.findIndex((item) => item.id === selectedId);\n const selected = selectedIndex >= 0 ? requests[selectedIndex] : undefined;\n const rawDetails = selected === undefined\n ? []\n : approvalDetailLines(selected, mode === 'approve' ? preparedApproval : undefined);\n const bodyHeight = Math.max(1, size.rows - HEADER_HEIGHT - FOOTER_HEIGHT);\n const sideBySide = size.columns >= SPLIT_COLUMNS;\n const listPaneHeight = sideBySide ? bodyHeight : Math.max(5, Math.floor(bodyHeight * 0.42));\n const detailPaneHeight = sideBySide ? bodyHeight : Math.max(1, bodyHeight - listPaneHeight);\n const detailViewport = Math.max(1, detailPaneHeight - PANE_CHROME_HEIGHT);\n const detailPaneWidth = sideBySide ? Math.floor(size.columns * 0.62) : size.columns;\n const details = wrapDetailLines(rawDetails, Math.max(1, detailPaneWidth - 6));\n const approvalReviewed = mode === 'approve'\n && preparedApproval !== undefined\n && details.length > 0\n && detailOffset + detailViewport >= details.length;\n\n useInput((input, key) => {\n const canReviewAuthority = size.rows >= MIN_FULL_HEIGHT;\n if (busy) return;\n if (mode === 'deny') {\n if (key.escape) model.cancelMode();\n return;\n }\n if (mode === 'approve') {\n if (key.escape) {\n model.cancelMode();\n } else if (key.pageUp) {\n model.scrollDetails(-detailViewport, details.length, detailViewport);\n } else if (key.pageDown) {\n model.scrollDetails(detailViewport, details.length, detailViewport);\n } else if (key.return && canReviewAuthority && approvalReviewed) {\n void model.confirmCurrentMode();\n }\n return;\n }\n if (mode === 'help') {\n if (key.escape || input === '?' || input === 'q') model.cancelMode();\n return;\n }\n if (input === 'q') {\n exit();\n } else if (input === '?' || key.f1) {\n model.showHelp();\n } else if (input === 'a' && canReviewAuthority) {\n void model.beginApprove();\n } else if (input === 'd' && canReviewAuthority) {\n model.beginDeny();\n } else if (input === 'r') {\n void model.refresh();\n } else if (key.upArrow || input === 'k') {\n model.selectBy(-1);\n } else if (key.downArrow || input === 'j') {\n model.selectBy(1);\n } else if (key.pageUp) {\n model.scrollDetails(-detailViewport, details.length, detailViewport);\n } else if (key.pageDown) {\n model.scrollDetails(detailViewport, details.length, detailViewport);\n }\n });\n\n if (size.rows < MIN_FULL_HEIGHT) {\n return (\n <CompactApprovalApp\n model={model}\n selected={selected}\n requestCount={requests.length}\n connectionState={connectionState}\n mode={mode}\n busy={busy}\n message={message}\n rows={size.rows}\n />\n );\n }\n\n return (\n <Box flexDirection=\"column\" height={size.rows} width={size.columns}>\n <Header\n principalId={model.principalId}\n state={connectionState}\n requestCount={requests.length}\n />\n {mode === 'help' ? (\n <Help height={bodyHeight} />\n ) : (\n <Box\n flexDirection={sideBySide ? 'row' : 'column'}\n height={bodyHeight}\n >\n <RequestList\n requests={requests}\n selectedIndex={selectedIndex}\n height={listPaneHeight}\n width={sideBySide ? '38%' : '100%'}\n />\n <RequestDetails\n selected={selected}\n lines={details}\n offset={detailOffset}\n height={detailPaneHeight}\n width={sideBySide ? '62%' : '100%'}\n />\n </Box>\n )}\n <Footer\n mode={mode}\n busy={busy}\n message={message}\n selected={selected}\n denialReason={denialReason}\n approvalReviewed={approvalReviewed}\n onReasonChange={(value) => model.setDenialReason(value)}\n onDeny={() => void model.confirmCurrentMode()}\n />\n </Box>\n );\n};\n\nconst Header: React.FC<{\n principalId: string;\n state: 'connecting' | 'live' | 'stale';\n requestCount: number;\n}> = ({ principalId, state, requestCount }) => (\n <Box flexDirection=\"column\" height={HEADER_HEIGHT}>\n <Box justifyContent=\"space-between\">\n <Text bold>Hub access approvals</Text>\n <Text color={state === 'live' ? 'green' : state === 'stale' ? 'yellow' : 'cyan'}>\n {state === 'live' ? '● live' : state === 'stale' ? '● reconnecting' : '○ connecting'}\n <Text color=\"white\"> {requestCount} pending</Text>\n </Text>\n </Box>\n <Text dimColor wrap=\"truncate-end\">approver: {safeTerminalText(principalId)}</Text>\n </Box>\n);\n\nconst RequestList: React.FC<{\n requests: readonly PendingApprovalRequest[];\n selectedIndex: number;\n height: number;\n width: number | `${number}%`;\n}> = ({ requests, selectedIndex, height, width }) => {\n const viewport = Math.max(1, height - PANE_CHROME_HEIGHT);\n const window = useScroll(requests.length, Math.max(0, selectedIndex), viewport);\n\n return (\n <Pane title=\"Requests\" height={height} width={width}>\n {requests.length === 0 ? (\n <Box flexDirection=\"column\">\n <Text color=\"green\">No pending access requests.</Text>\n <Text dimColor>Watching the Hub for new requests...</Text>\n </Box>\n ) : (\n <>\n <ScrollMarker direction=\"up\" count={window.above} />\n {requests.slice(window.start, window.end).map((item, index) => {\n const actualIndex = window.start + index;\n const selected = actualIndex === selectedIndex;\n const duration = item.request.duration ?? 'unspecified';\n return (\n <Text\n key={item.id}\n color={selected ? 'cyan' : undefined}\n bold={selected}\n inverse={selected}\n wrap=\"truncate-end\"\n >\n {selected ? '› ' : ' '}\n {safeTerminalText(item.request.consumer.name)}\n <Text dimColor>\n {' '}{safeTerminalText(item.request.kind)} / {safeTerminalText(duration)}\n </Text>\n </Text>\n );\n })}\n <ScrollMarker direction=\"down\" count={window.below} />\n </>\n )}\n </Pane>\n );\n};\n\nconst RequestDetails: React.FC<{\n selected: PendingApprovalRequest | undefined;\n lines: readonly DetailLine[];\n offset: number;\n height: number;\n width: number | `${number}%`;\n}> = ({ selected, lines, offset, height, width }) => {\n const viewport = Math.max(1, height - PANE_CHROME_HEIGHT);\n const safeOffset = Math.min(offset, Math.max(0, lines.length - viewport));\n const visible = lines.slice(safeOffset, safeOffset + viewport);\n const range = lines.length > viewport\n ? ` (${safeOffset + 1}-${safeOffset + visible.length} of ${lines.length})`\n : '';\n\n return (\n <Pane title={`Request details${range}`} height={height} width={width}>\n {selected === undefined ? (\n <Text dimColor>Select a request to inspect its exact authority.</Text>\n ) : (\n <>\n {visible.map((line, index) => (\n <Text\n key={`${safeOffset + index}:${line.label ?? ''}:${line.text}`}\n color={line.tone === 'warning' ? 'yellow' : undefined}\n dimColor={line.tone === 'muted'}\n wrap=\"truncate-end\"\n >\n {line.label !== undefined && <Text bold>{safeTerminalText(line.label)}: </Text>}\n {safeTerminalText(line.text) || '—'}\n </Text>\n ))}\n </>\n )}\n </Pane>\n );\n};\n\nconst Footer: React.FC<{\n mode: 'browse' | 'approve' | 'deny' | 'help';\n busy: boolean;\n message: { readonly kind: ApprovalUiMessageKind; readonly text: string } | undefined;\n selected: PendingApprovalRequest | undefined;\n denialReason: string;\n approvalReviewed: boolean;\n onReasonChange(value: string): void;\n onDeny(): void;\n}> = ({\n mode,\n busy,\n message,\n selected,\n denialReason,\n approvalReviewed,\n onReasonChange,\n onDeny,\n}) => {\n if (busy) {\n return (\n <Box flexDirection=\"column\" height={FOOTER_HEIGHT}>\n <Text color=\"cyan\">Working... The manifest will be rechecked before the decision is applied.</Text>\n <Text dimColor>Please wait.</Text>\n </Box>\n );\n }\n if (mode === 'approve') {\n return (\n <Box flexDirection=\"column\" height={FOOTER_HEIGHT}>\n <Text color=\"yellow\" wrap=\"truncate-end\">\n Approve all displayed authority for{' '}\n <Text bold>{safeTerminalText(selected?.request.consumer.name ?? '')}</Text>?\n </Text>\n {approvalReviewed ? (\n <Text><Text bold>Enter</Text> confirm <Text bold>Esc</Text> cancel</Text>\n ) : (\n <Text><Text bold>PgDn</Text> review all authority before confirming <Text bold>Esc</Text> cancel</Text>\n )}\n </Box>\n );\n }\n if (mode === 'deny') {\n return (\n <Box flexDirection=\"column\" height={FOOTER_HEIGHT}>\n <Box>\n <Text color=\"red\">Denial reason (optional): </Text>\n <TextInput value={denialReason} onChange={onReasonChange} onSubmit={onDeny} />\n </Box>\n <Text><Text bold>Enter</Text> deny <Text bold>Esc</Text> cancel</Text>\n </Box>\n );\n }\n\n return (\n <Box flexDirection=\"column\" height={FOOTER_HEIGHT}>\n <Text\n color={messageColor(message?.kind)}\n dimColor={message === undefined}\n wrap=\"truncate-end\"\n >\n {safeTerminalText(message?.text ?? 'Review the exact authority before approving.')}\n </Text>\n <Text dimColor wrap=\"truncate-end\">\n ↑/↓ or j/k select a approve d deny PgUp/PgDn details r refresh ? help q quit\n </Text>\n </Box>\n );\n};\n\nconst Help: React.FC<{ height: number }> = ({ height }) => (\n <Pane title=\"Keyboard help\" height={height} width=\"100%\">\n <Text><Text bold>↑/↓, j/k</Text> Move through pending requests</Text>\n <Text><Text bold>PgUp/PgDn</Text> Scroll long request details</Text>\n <Text><Text bold>a</Text> Review and confirm approval</Text>\n <Text><Text bold>d</Text> Deny with an optional reason</Text>\n <Text><Text bold>r</Text> Refresh the authoritative manifest snapshot</Text>\n <Text><Text bold>?, F1</Text> Toggle this help</Text>\n <Text><Text bold>q</Text> Quit without deciding remaining requests</Text>\n <Text dimColor>Press Esc, ?, or q to return.</Text>\n </Pane>\n);\n\nconst CompactApprovalApp: React.FC<{\n model: ApprovalUiModel;\n selected: PendingApprovalRequest | undefined;\n requestCount: number;\n connectionState: 'connecting' | 'live' | 'stale';\n mode: 'browse' | 'approve' | 'deny' | 'help';\n busy: boolean;\n message: { readonly kind: ApprovalUiMessageKind; readonly text: string } | undefined;\n rows: number;\n}> = ({\n model,\n selected,\n requestCount,\n connectionState,\n mode,\n busy,\n message,\n rows,\n}) => (\n <Box flexDirection=\"column\" height={Math.max(1, rows)}>\n <Text bold wrap=\"truncate-end\">Hub approvals {connectionState} {requestCount} pending</Text>\n <Text wrap=\"truncate-end\">\n {selected === undefined\n ? 'No pending access requests.'\n : safeTerminalText(\n `${selected.request.consumer.name} · ${selected.request.kind} · ${selected.request.duration ?? 'unspecified'}`,\n )}\n </Text>\n {rows >= 4 && (\n <Text color={messageColor(message?.kind)} wrap=\"truncate-end\">\n {safeTerminalText(busy ? 'Resolving request...' : message?.text ?? model.principalId)}\n </Text>\n )}\n {rows >= 5 && (\n <Text color=\"yellow\" wrap=\"truncate-end\">\n Enlarge to at least {MIN_FULL_HEIGHT} rows to review and decide. ↑/↓ select q quit\n </Text>\n )}\n </Box>\n);\n\nconst Pane: React.FC<{\n title: string;\n height: number;\n width: number | `${number}%`;\n children: React.ReactNode;\n}> = ({ title, height, width, children }) => (\n <Box\n flexDirection=\"column\"\n borderStyle=\"round\"\n borderColor=\"gray\"\n height={height}\n width={width}\n paddingX={1}\n overflow=\"hidden\"\n >\n <Text bold>{title}</Text>\n {children}\n </Box>\n);\n\nconst ScrollMarker: React.FC<{ direction: 'up' | 'down'; count: number }> = ({ direction, count }) => {\n if (count === 0) return null;\n return <Text dimColor>{direction === 'up' ? '▲' : '▼'} {count} more</Text>;\n};\n\nfunction wrapDetailLines(lines: readonly DetailLine[], width: number): readonly DetailLine[] {\n return lines.flatMap((line) => {\n const text = safeTerminalText(`${line.label === undefined ? '' : `${line.label}: `}${line.text || '—'}`);\n return wrapTerminalText(text, width).map((chunk) => ({\n text: chunk,\n ...(line.tone === undefined ? {} : { tone: line.tone }),\n }));\n });\n}\n\nfunction wrapTerminalText(text: string, width: number): readonly string[] {\n const lines: string[] = [];\n let current = '';\n let currentWidth = 0;\n for (const character of text) {\n const characterWidth = terminalCharacterWidth(character);\n if (current.length > 0 && currentWidth + characterWidth > width) {\n lines.push(current);\n current = '';\n currentWidth = 0;\n }\n current += character;\n currentWidth += characterWidth;\n }\n if (current.length > 0 || lines.length === 0) lines.push(current);\n return lines;\n}\n\nfunction terminalCharacterWidth(character: string): number {\n if (/^\\p{Mark}$/u.test(character)) return 0;\n return character.codePointAt(0)! <= 0x7e ? 1 : 2;\n}\n\nexport function safeTerminalText(text: string): string {\n let result = '';\n for (const character of text) {\n result += /^[\\p{Cc}\\p{Cf}\\p{Zl}\\p{Zp}]$/u.test(character)\n ? `\\\\u{${character.codePointAt(0)!.toString(16).padStart(4, '0')}}`\n : character;\n }\n return result;\n}\n\nfunction messageColor(kind: ApprovalUiMessageKind | undefined): 'red' | 'green' | 'cyan' | undefined {\n if (kind === 'error') return 'red';\n if (kind === 'success') return 'green';\n if (kind === 'info') return 'cyan';\n return undefined;\n}\n\nfunction useTerminalSize(): TerminalSize {\n const { stdout } = useStdout();\n const [size, setSize] = React.useState<TerminalSize>({\n columns: stdout.columns ?? 100,\n rows: stdout.rows ?? 30,\n });\n React.useEffect(() => {\n const onResize = () => setSize({\n columns: stdout.columns ?? 100,\n rows: stdout.rows ?? 30,\n });\n stdout.on('resize', onResize);\n return () => stdout.off('resize', onResize);\n }, [stdout]);\n return size;\n}\n","import { jcsCanonicalize } from '@hediet/linkrpc';\nimport { observableValue, type IObservable, type ISettableObservable } from '@vscode/observables';\nimport type {\n ApprovalSnapshot,\n ApprovalSubscription,\n ApprovalDecisionOutcome,\n PendingApprovalRequest,\n PreparedApproval,\n} from '../commands/approval';\n\nexport type ApprovalUiMode = 'browse' | 'approve' | 'deny' | 'help';\nexport type ApprovalUiMessageKind = 'info' | 'success' | 'error';\n\nexport interface ApprovalUiMessage {\n readonly kind: ApprovalUiMessageKind;\n readonly text: string;\n}\n\nexport interface ApprovalUiClient {\n readonly principalId: string;\n watch(listener: (snapshot: ApprovalSnapshot) => void): ApprovalSubscription;\n refresh(): Promise<void>;\n prepareApproval(requestId: string): Promise<PreparedApproval>;\n approvePrepared(prepared: PreparedApproval): Promise<ApprovalDecisionOutcome>;\n deny(\n requestId: string,\n reason?: string,\n expected?: PendingApprovalRequest,\n ): Promise<ApprovalDecisionOutcome>;\n}\n\nexport class ApprovalUiModel {\n private readonly _requests: ISettableObservable<readonly PendingApprovalRequest[]>;\n public readonly requests: IObservable<readonly PendingApprovalRequest[]>;\n private readonly _connectionState: ISettableObservable<ApprovalSnapshot['state']>;\n public readonly connectionState: IObservable<ApprovalSnapshot['state']>;\n private readonly _selectedRequestId: ISettableObservable<string | undefined>;\n public readonly selectedRequestId: IObservable<string | undefined>;\n private readonly _mode: ISettableObservable<ApprovalUiMode>;\n public readonly mode: IObservable<ApprovalUiMode>;\n private readonly _busy: ISettableObservable<boolean>;\n public readonly busy: IObservable<boolean>;\n private readonly _message: ISettableObservable<ApprovalUiMessage | undefined>;\n public readonly message: IObservable<ApprovalUiMessage | undefined>;\n private readonly _denialReason: ISettableObservable<string>;\n public readonly denialReason: IObservable<string>;\n private readonly _detailOffset: ISettableObservable<number>;\n public readonly detailOffset: IObservable<number>;\n private readonly _preparedApproval: ISettableObservable<PreparedApproval | undefined>;\n public readonly preparedApproval: IObservable<PreparedApproval | undefined>;\n\n private readonly _client: ApprovalUiClient;\n private readonly _subscription: ApprovalSubscription;\n private _disposed = false;\n\n constructor(client: ApprovalUiClient) {\n this._client = client;\n this._requests = observableValue(this, []);\n this.requests = this._requests;\n this._connectionState = observableValue(this, 'connecting');\n this.connectionState = this._connectionState;\n this._selectedRequestId = observableValue(this, undefined);\n this.selectedRequestId = this._selectedRequestId;\n this._mode = observableValue(this, 'browse');\n this.mode = this._mode;\n this._busy = observableValue(this, false);\n this.busy = this._busy;\n this._message = observableValue(this, undefined);\n this.message = this._message;\n this._denialReason = observableValue(this, '');\n this.denialReason = this._denialReason;\n this._detailOffset = observableValue(this, 0);\n this.detailOffset = this._detailOffset;\n this._preparedApproval = observableValue(this, undefined);\n this.preparedApproval = this._preparedApproval;\n this._subscription = client.watch((snapshot) => this._applySnapshot(snapshot));\n }\n\n public get principalId(): string {\n return this._client.principalId;\n }\n\n public get selectedRequest(): PendingApprovalRequest | undefined {\n const selectedId = this._selectedRequestId.get();\n return this._requests.get().find((item) => item.id === selectedId);\n }\n\n public selectBy(delta: number): void {\n if (this._busy.get() || this._mode.get() !== 'browse') return;\n const requests = this._requests.get();\n if (requests.length === 0) return;\n const currentIndex = Math.max(\n 0,\n requests.findIndex((item) => item.id === this._selectedRequestId.get()),\n );\n const nextIndex = Math.max(0, Math.min(requests.length - 1, currentIndex + delta));\n if (nextIndex === currentIndex) return;\n this._selectedRequestId.set(requests[nextIndex].id, undefined);\n this._detailOffset.set(0, undefined);\n }\n\n public showHelp(): void {\n if (this._busy.get()) return;\n this._mode.set('help', undefined);\n }\n\n public async beginApprove(): Promise<void> {\n if (!this._canDecide()) return;\n const selected = this.selectedRequest;\n if (selected === undefined) return;\n this._busy.set(true, undefined);\n this._message.set({ kind: 'info', text: 'Resolving exact authority...' }, undefined);\n try {\n const prepared = await this._client.prepareApproval(selected.id);\n if (\n this.selectedRequest?.id !== selected.id\n || jcsCanonicalize(this.selectedRequest.request)\n !== jcsCanonicalize(prepared.pending.request)\n ) {\n this._message.set({\n kind: 'info',\n text: 'The request changed while its authority was being resolved. Review it again.',\n }, undefined);\n return;\n }\n this._preparedApproval.set(prepared, undefined);\n this._detailOffset.set(0, undefined);\n this._mode.set('approve', undefined);\n this._message.set(undefined, undefined);\n } catch (error) {\n this._message.set({\n kind: 'error',\n text: error instanceof Error ? error.message : String(error),\n }, undefined);\n } finally {\n this._busy.set(false, undefined);\n }\n }\n\n public beginDeny(): void {\n if (!this._canDecide()) return;\n this._denialReason.set('', undefined);\n this._mode.set('deny', undefined);\n }\n\n public setDenialReason(reason: string): void {\n this._denialReason.set(reason, undefined);\n }\n\n public cancelMode(): void {\n if (this._busy.get()) return;\n this._mode.set('browse', undefined);\n this._denialReason.set('', undefined);\n this._preparedApproval.set(undefined, undefined);\n }\n\n public async confirmCurrentMode(): Promise<void> {\n const mode = this._mode.get();\n const selected = this.selectedRequest;\n if (this._busy.get() || selected === undefined || (mode !== 'approve' && mode !== 'deny')) return;\n\n this._busy.set(true, undefined);\n this._message.set({\n kind: 'info',\n text: mode === 'approve' ? 'Approving request...' : 'Denying request...',\n }, undefined);\n try {\n let outcome: ApprovalDecisionOutcome;\n if (mode === 'approve') {\n const prepared = this._preparedApproval.get();\n if (prepared === undefined) {\n throw new Error('approval details are no longer available; review the request again');\n }\n outcome = await this._client.approvePrepared(prepared);\n } else {\n const reason = this._denialReason.get().trim();\n outcome = await this._client.deny(\n selected.id,\n reason.length > 0 ? reason : undefined,\n selected,\n );\n }\n this._message.set({\n kind: outcome === 'applied' ? 'success' : 'info',\n text: outcome === 'applied'\n ? `${mode === 'approve' ? 'Approved' : 'Denied'} ${selected.request.consumer.name}.`\n : `Decision accepted for ${selected.request.consumer.name}, `\n + 'but a matching request is still pending. The consumer may have retried.',\n }, undefined);\n } catch (error) {\n this._message.set({\n kind: 'error',\n text: error instanceof Error ? error.message : String(error),\n }, undefined);\n } finally {\n this._busy.set(false, undefined);\n this._mode.set('browse', undefined);\n this._denialReason.set('', undefined);\n this._preparedApproval.set(undefined, undefined);\n }\n }\n\n public async refresh(): Promise<void> {\n if (this._busy.get()) return;\n this._message.set({ kind: 'info', text: 'Refreshing approval requests...' }, undefined);\n try {\n await this._client.refresh();\n if (this._connectionState.get() === 'live') {\n this._message.set({ kind: 'info', text: 'Approval requests are up to date.' }, undefined);\n }\n } catch (error) {\n this._message.set({\n kind: 'error',\n text: error instanceof Error ? error.message : String(error),\n }, undefined);\n }\n }\n\n public scrollDetails(delta: number, lineCount: number, viewportSize: number): void {\n const maxOffset = Math.max(0, lineCount - Math.max(1, viewportSize));\n const next = Math.max(0, Math.min(maxOffset, this._detailOffset.get() + delta));\n this._detailOffset.set(next, undefined);\n }\n\n public dispose(): void {\n if (this._disposed) return;\n this._disposed = true;\n this._subscription.dispose();\n }\n\n private _canDecide(): boolean {\n if (this._busy.get() || this.selectedRequest === undefined) return false;\n if (this._connectionState.get() !== 'live') {\n this._message.set({\n kind: 'error',\n text: 'Cannot decide requests while the approval connection is stale.',\n }, undefined);\n return false;\n }\n return true;\n }\n\n private _applySnapshot(snapshot: ApprovalSnapshot): void {\n const previous = this._requests.get();\n const selectedId = this._selectedRequestId.get();\n const previousSelected = previous.find((item) => item.id === selectedId);\n const previousIndex = Math.max(0, previous.findIndex((item) => item.id === selectedId));\n const selectedStillExists = snapshot.requests.some((item) => item.id === selectedId);\n const nextSelected = snapshot.requests.find((item) => item.id === selectedId);\n const selectedChanged = previousSelected !== undefined\n && nextSelected !== undefined\n && jcsCanonicalize(previousSelected.request) !== jcsCanonicalize(nextSelected.request);\n\n this._requests.set(snapshot.requests, undefined);\n this._connectionState.set(snapshot.state, undefined);\n\n if (snapshot.requests.length === 0) {\n this._selectedRequestId.set(undefined, undefined);\n this._detailOffset.set(0, undefined);\n } else if (!selectedStillExists) {\n const nextIndex = Math.min(previousIndex, snapshot.requests.length - 1);\n this._selectedRequestId.set(snapshot.requests[nextIndex].id, undefined);\n this._detailOffset.set(0, undefined);\n this._preparedApproval.set(undefined, undefined);\n }\n\n if (\n ((!selectedStillExists && selectedId !== undefined) || selectedChanged)\n && this._mode.get() !== 'browse'\n ) {\n this._mode.set('browse', undefined);\n this._denialReason.set('', undefined);\n this._preparedApproval.set(undefined, undefined);\n this._message.set({\n kind: 'info',\n text: selectedChanged\n ? 'The selected request changed. Review it again before deciding.'\n : 'The selected request is no longer pending.',\n }, undefined);\n }\n if (snapshot.state === 'stale' && snapshot.error !== undefined) {\n this._message.set({ kind: 'error', text: snapshot.error }, undefined);\n }\n }\n}\n","import React from 'react';\nimport { render } from 'ink';\nimport type { ApprovalCommandClient } from '../commands/approval';\nimport { ApprovalApp } from './ApprovalApp';\nimport { ApprovalUiModel } from './ApprovalUiModel';\n\nexport interface RunApprovalUiOptions {\n readonly client: ApprovalCommandClient;\n readonly signal: AbortSignal;\n}\n\nexport async function runApprovalUi(options: RunApprovalUiOptions): Promise<void> {\n const model = new ApprovalUiModel(options.client);\n const instance = render(<ApprovalApp model={model} />);\n const onAbort = () => instance.unmount();\n options.signal.addEventListener('abort', onAbort, { once: true });\n if (options.signal.aborted) onAbort();\n try {\n await raceAbort(model.refresh(), options.signal);\n if (options.signal.aborted) return;\n await instance.waitUntilExit();\n } finally {\n options.signal.removeEventListener('abort', onAbort);\n instance.unmount();\n model.dispose();\n }\n}\n\nfunction raceAbort<T>(promise: Promise<T>, signal: AbortSignal): Promise<T | undefined> {\n if (signal.aborted) return Promise.resolve(undefined);\n return new Promise<T | undefined>((resolve, reject) => {\n const onAbort = () => {\n signal.removeEventListener('abort', onAbort);\n resolve(undefined);\n };\n signal.addEventListener('abort', onAbort, { once: true });\n promise.then(\n (value) => {\n signal.removeEventListener('abort', onAbort);\n resolve(value);\n },\n (error: unknown) => {\n signal.removeEventListener('abort', onAbort);\n reject(error);\n },\n );\n });\n}\n"],"mappings":"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"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { ErrorCode, InMemoryManagedIdentity, JsonRpcChannel, RpcError, SigningSender, TransportPair, capabilityFreshAt,
|
|
1
|
+
import { ErrorCode, InMemoryManagedIdentity, JsonRpcChannel, RpcError, SigningSender, TransportPair, capabilityFreshAt, defineInterface, isAssignable, parseStaticHubSchema, permissionMatchesTarget, requestType, traceMessageTransport } from "@hediet/linkrpc";
|
|
2
2
|
import { z } from "zod";
|
|
3
3
|
import { LINKRPC_ENDPOINT_VAR, LINKRPC_TOKEN_VAR, WebSocketTransport, connectNdjson, createManagedPrincipal, createSelfManagedPrincipal, createSelfManagedPrincipalFromFile, isHubEndpoint, loadOrCreateIdentity, openWebSocket, parseEndpointUri, runInitializeHandshake } from "@hediet/linkrpc/node";
|
|
4
4
|
import { Hub, HubConnectionAcceptor, RootOverlay, anonymousHandler, createHubServiceInterfaces, registerHubServices, registerIdentityServices } from "@hediet/linkrpc-hub/hub/server/client";
|
|
@@ -3513,75 +3513,6 @@ async function loadStaticHubSchema(source) {
|
|
|
3513
3513
|
function isHttpUrl(source) {
|
|
3514
3514
|
return /^https?:\/\//i.test(source);
|
|
3515
3515
|
}
|
|
3516
|
-
function parseStaticHubSchema(value) {
|
|
3517
|
-
const root = expectRecord(value, "hub schema");
|
|
3518
|
-
const rawServices = expectArray(root.services, "services");
|
|
3519
|
-
const interfaceSchemas = expectArray(root.interfaceSchemas, "interfaceSchemas").map((schema, index) => parseInterfaceSchema(schema, `interfaceSchemas[${index}]`));
|
|
3520
|
-
const schemasByKey = /* @__PURE__ */ new Map();
|
|
3521
|
-
for (const schema of interfaceSchemas) {
|
|
3522
|
-
const key = interfaceKey$1(schema.id, schema.hash);
|
|
3523
|
-
if (schemasByKey.has(key)) throw new Error(`interfaceSchemas contains duplicate ${schema.id}@${schema.hash}`);
|
|
3524
|
-
schemasByKey.set(key, schema);
|
|
3525
|
-
}
|
|
3526
|
-
const services = rawServices.map((service, index) => parseService(service, `services[${index}]`));
|
|
3527
|
-
for (const [serviceIndex, service] of services.entries()) for (const [interfaceIndex, ref] of service.interfaces.entries()) requireResolvedReference(ref, schemasByKey, `services[${serviceIndex}].interfaces[${interfaceIndex}]`);
|
|
3528
|
-
const defaultInterface = root.defaultInterface === void 0 ? void 0 : parseInterfaceReference(root.defaultInterface, "defaultInterface");
|
|
3529
|
-
if (defaultInterface !== void 0) requireResolvedReference(defaultInterface, schemasByKey, "defaultInterface");
|
|
3530
|
-
return {
|
|
3531
|
-
services,
|
|
3532
|
-
...defaultInterface === void 0 ? {} : { defaultInterface },
|
|
3533
|
-
interfaceSchemas
|
|
3534
|
-
};
|
|
3535
|
-
}
|
|
3536
|
-
function parseService(value, path) {
|
|
3537
|
-
const service = expectRecord(value, path);
|
|
3538
|
-
if (typeof service.serviceId !== "string") throw new Error(`${path}.serviceId must be a string`);
|
|
3539
|
-
return {
|
|
3540
|
-
serviceId: service.serviceId,
|
|
3541
|
-
interfaces: expectArray(service.interfaces, `${path}.interfaces`).map((ref, index) => parseInterfaceReference(ref, `${path}.interfaces[${index}]`))
|
|
3542
|
-
};
|
|
3543
|
-
}
|
|
3544
|
-
function parseInterfaceReference(value, path) {
|
|
3545
|
-
const ref = expectRecord(value, path);
|
|
3546
|
-
if (typeof ref.interfaceId !== "string" || ref.interfaceId.length === 0) throw new Error(`${path}.interfaceId must be a non-empty string`);
|
|
3547
|
-
if (typeof ref.interfaceHash !== "string" || ref.interfaceHash.length === 0) throw new Error(`${path}.interfaceHash must be a non-empty string`);
|
|
3548
|
-
return {
|
|
3549
|
-
interfaceId: ref.interfaceId,
|
|
3550
|
-
interfaceHash: ref.interfaceHash
|
|
3551
|
-
};
|
|
3552
|
-
}
|
|
3553
|
-
function parseInterfaceSchema(value, path) {
|
|
3554
|
-
const schema = expectRecord(value, path);
|
|
3555
|
-
if (typeof schema.id !== "string" || schema.id.length === 0) throw new Error(`${path}.id must be a non-empty string`);
|
|
3556
|
-
if (typeof schema.hash !== "string" || schema.hash.length === 0) throw new Error(`${path}.hash must be a non-empty string`);
|
|
3557
|
-
if (typeof schema.methods !== "object" || schema.methods === null || Array.isArray(schema.methods)) throw new Error(`${path}.methods must be an object`);
|
|
3558
|
-
for (const [name, method] of Object.entries(schema.methods)) {
|
|
3559
|
-
if (name.length === 0) throw new Error(`${path}.methods keys must be non-empty strings`);
|
|
3560
|
-
const parsed = expectRecord(method, `${path}.methods.${name}`);
|
|
3561
|
-
if (!Object.hasOwn(parsed, "params")) throw new Error(`${path}.methods.${name}.params is required`);
|
|
3562
|
-
}
|
|
3563
|
-
const typed = schema;
|
|
3564
|
-
const computedHash = computeInterfaceHash(typed);
|
|
3565
|
-
if (computedHash !== typed.hash) throw new Error(`${path} hash mismatch for ${typed.id}: declared ${typed.hash}, computed ${computedHash}`);
|
|
3566
|
-
return typed;
|
|
3567
|
-
}
|
|
3568
|
-
function requireResolvedReference(ref, schemasByKey, path) {
|
|
3569
|
-
if (!schemasByKey.has(interfaceKey$1(ref.interfaceId, ref.interfaceHash))) throw new Error(`${path} ${formatReference(ref)} does not resolve to an interface schema`);
|
|
3570
|
-
}
|
|
3571
|
-
function formatReference(ref) {
|
|
3572
|
-
return `${ref.interfaceId}@${ref.interfaceHash}`;
|
|
3573
|
-
}
|
|
3574
|
-
function interfaceKey$1(interfaceId, interfaceHash) {
|
|
3575
|
-
return `${interfaceId}\0${interfaceHash}`;
|
|
3576
|
-
}
|
|
3577
|
-
function expectRecord(value, path) {
|
|
3578
|
-
if (value === null || typeof value !== "object" || Array.isArray(value)) throw new Error(`${path} must be an object`);
|
|
3579
|
-
return value;
|
|
3580
|
-
}
|
|
3581
|
-
function expectArray(value, path) {
|
|
3582
|
-
if (!Array.isArray(value)) throw new Error(`${path} must be an array`);
|
|
3583
|
-
return value;
|
|
3584
|
-
}
|
|
3585
3516
|
//#endregion
|
|
3586
3517
|
//#region src/commands/staticHubReflection.ts
|
|
3587
3518
|
const DIRECTORY_INTERFACE_ID = "hubrpc.directory";
|
|
@@ -3599,7 +3530,7 @@ var StaticHubReflection = class {
|
|
|
3599
3530
|
_hashesByServiceInterface = /* @__PURE__ */ new Map();
|
|
3600
3531
|
constructor(_schema) {
|
|
3601
3532
|
this._schema = _schema;
|
|
3602
|
-
this._directory = _schema.services.flatMap((service) => service.interfaces.map((ref) => ({
|
|
3533
|
+
this._directory = (_schema.services ?? []).flatMap((service) => service.interfaces.map((ref) => ({
|
|
3603
3534
|
serviceId: service.serviceId,
|
|
3604
3535
|
interfaceId: ref.interfaceId,
|
|
3605
3536
|
interfaceHash: ref.interfaceHash
|
|
@@ -3620,6 +3551,11 @@ var StaticHubReflection = class {
|
|
|
3620
3551
|
hashes.add(ref.interfaceHash);
|
|
3621
3552
|
this._activeHashesById.set(ref.interfaceId, hashes);
|
|
3622
3553
|
}
|
|
3554
|
+
for (const { interface: ref } of _schema.bareInterfaces ?? []) {
|
|
3555
|
+
const hashes = this._activeHashesById.get(ref.interfaceId) ?? /* @__PURE__ */ new Set();
|
|
3556
|
+
hashes.add(ref.interfaceHash);
|
|
3557
|
+
this._activeHashesById.set(ref.interfaceId, hashes);
|
|
3558
|
+
}
|
|
3623
3559
|
}
|
|
3624
3560
|
tryHandleRequest(call) {
|
|
3625
3561
|
return this.tryHandle(call.method, call.params, call.signal);
|
|
@@ -3628,6 +3564,10 @@ var StaticHubReflection = class {
|
|
|
3628
3564
|
const reflectionCall = parseReflectionMethod(method);
|
|
3629
3565
|
if (reflectionCall === void 0) return;
|
|
3630
3566
|
switch (reflectionCall.method) {
|
|
3567
|
+
case `${DEFAULTS_INTERFACE_ID}::listBindings`: return Promise.resolve({ result: { bindings: (this._schema.bareInterfaces ?? []).map((binding) => ({
|
|
3568
|
+
prefix: binding.prefix,
|
|
3569
|
+
...binding.interface
|
|
3570
|
+
})) } });
|
|
3631
3571
|
case DIRECTORY_LIST_METHOD: return Promise.resolve(this._listDirectory(params));
|
|
3632
3572
|
case DIRECTORY_WATCH_METHOD: return this._watchDirectory(params, signal);
|
|
3633
3573
|
case SCHEMAS_GET_METHOD: return Promise.resolve(this._getSchema(params, reflectionCall.serviceId));
|
|
@@ -3946,4 +3886,4 @@ function _endpointCacheKey(endpoint, staticSchema) {
|
|
|
3946
3886
|
//#endregion
|
|
3947
3887
|
export { connectViaRootOverlay as A, parseParamOverride as B, findMethodInSchema as C, formatPrincipalSource as D, logoutCliIdentity as E, describeSchema as F, mcpForwardInterface as H, explainValidation as I, validateValueAgainstSchema as L, resolveTargetEndpoint as M, resolvedEndpointToConfig as N, parsePrincipalSpec as O, describeObjectParams as P, valueToConstSchema as R, fetchSchema$1 as S, walkHubDetailed as T, MethodRefWithOptHash as V, ChannelDirectorySource as _, resolveStaticHubSchemaSource as a, setupSigning as b, resolveInvocationEndpoint as c, formatContextReference as d, complete as f, parseLine as g, COMMAND_TREE as h, loadStaticHubSchema as i, connectViaTransport as j, connect as k, validationDefault as l, resolveSlot as m, StaticHubReflection as n, mutationReference as o, resolveCliInvocation as p, withStaticHubReflection as r, resolveInvocationContext as s, completeForLine as t, ContextStore as u, requestReflectionAccess as v, walkHub as w, fetchDefaults as x, requestTopologyAccess as y, mergeParams as z };
|
|
3948
3888
|
|
|
3949
|
-
//# sourceMappingURL=runComplete-
|
|
3889
|
+
//# sourceMappingURL=runComplete-Du5wmOdB.js.map
|