@agimon-ai/po-web-dashboard 0.0.0-alpha.97 → 0.0.0-alpha.99

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/dist/core.cjs CHANGED
@@ -19,6 +19,7 @@ const require_sessionModel = require("./web/lib/sessionModel.cjs");
19
19
  const require_qrMatrix = require("./web/lib/qrMatrix.cjs");
20
20
  const require_sessionSummary = require("./web/lib/sessionSummary.cjs");
21
21
  const require_sessionRailModel = require("./web/lib/sessionRailModel.cjs");
22
+ const require_settingsDraft = require("./web/lib/settingsDraft.cjs");
22
23
  const require_toolCompletionTabs = require("./web/lib/toolCompletionTabs.cjs");
23
24
  const require_toolMessageProps = require("./web/lib/toolMessageProps.cjs");
24
25
  const require_toolPrompt = require("./web/lib/toolPrompt.cjs");
@@ -87,6 +88,7 @@ exports.bindThreadReader = require_threadStore.bindThreadReader;
87
88
  exports.bindTransport = require_transport.bindTransport;
88
89
  exports.buildRailWorkspaces = require_sessionRailModel.buildRailWorkspaces;
89
90
  exports.builtinCommandFrame = require_commands.builtinCommandFrame;
91
+ exports.canSaveSettings = require_settingsDraft.canSaveSettings;
90
92
  exports.cancelDialog = require_sessionStore.cancelDialog;
91
93
  exports.claimDialogMenu = require_menuStore.claimDialogMenu;
92
94
  exports.clearDialog = require_sessionModel.clearDialog;
@@ -174,6 +176,7 @@ exports.parseSelection = require_statusLine.parseSelection;
174
176
  exports.pendingMenuFor = require_menuStore.pendingMenuFor;
175
177
  exports.pendingSetupView = require_sessionRailModel.pendingSetupView;
176
178
  exports.personaInitials = require_sessionSummary.personaInitials;
179
+ exports.plannedSettingsWrites = require_settingsDraft.plannedSettingsWrites;
177
180
  exports.pluginActivityGroups = require_pluginRegistry.pluginActivityGroups;
178
181
  exports.pluginContextActions = require_pluginRegistry.pluginContextActions;
179
182
  exports.pluginDockFaces = require_pluginRegistry.pluginDockFaces;
@@ -268,6 +271,8 @@ exports.setThinkingLevelCommand = require_commands.setThinkingLevelCommand;
268
271
  exports.setTransientTabSession = require_transientTabsStore.setTransientTabSession;
269
272
  exports.setUiTraceSink = require_uiTrace.setUiTraceSink;
270
273
  exports.setWebPluginLoadDiagnostics = require_pluginRegistry.setWebPluginLoadDiagnostics;
274
+ exports.settingsKeyOf = require_settingsDraft.settingsKeyOf;
275
+ exports.settingsLockedReason = require_settingsDraft.settingsLockedReason;
271
276
  exports.slotFills = require_pluginRegistry.slotFills;
272
277
  exports.splitHostId = require_hostIdentity.splitHostId;
273
278
  exports.startPluginDefinitions = require_pluginRegistry.startPluginDefinitions;
package/dist/core.d.mts CHANGED
@@ -25,6 +25,7 @@ import { ThreadTranscriptReader, applyThreadTranscriptFrame, bindThreadReader, d
25
25
  import { WorkspacesState, applyWorkspaceRemoved, applyWorkspaceUpsert, applyWorkspacesSnapshot, resetWorkspaces, selectWorkspace, workspacesStore } from "./web/stores/workspacesStore.mjs";
26
26
  import { ActivityGroup, MinorMode, SelectionAxis, activityGroups, fileTabForPath, minorModes, selectionAxes, subscribeActivitySources, useActivityGroups, useDockFaceBadges, useDockFaces, useFileLinks } from "./web/lib/composition.mjs";
27
27
  import { parseSelection } from "./web/lib/statusLine.mjs";
28
+ import { canSaveSettings, plannedSettingsWrites, settingsKeyOf, settingsLockedReason } from "./web/lib/settingsDraft.mjs";
28
29
  import { MenuClaim, MenuKind, MenuState, claimDialogMenu, clearPendingMenu, menuStore, pendingMenuFor, releaseDialogMenu, resetMenuStore, setPendingMenu } from "./web/stores/menuStore.mjs";
29
30
  import { ContextGroup, ContextItemSource, contextGroups, inactiveTotal, ownerLabel, ownersOf, projectedGroups, totalTokens } from "./web/lib/contextComposition.mjs";
30
31
  import { closeTransientTab, dropTransientTabs, findTransientTab, openTransientTab, setTransientTabSession, transientTabsStore, useTransientTabs } from "./web/stores/transientTabsStore.mjs";
@@ -35,4 +36,4 @@ import { bindSessionFileLinkModes, sessionMinorModes } from "./web/stores/fileLi
35
36
  import { createToolCompletionTabs } from "./web/lib/toolCompletionTabs.mjs";
36
37
  import { createWebMcpSimulator } from "./web/lib/webmcpSimulator.mjs";
37
38
  import { localHostId, parseHostKey, qualifyHostId, qualifyHostKey, splitHostId } from "./web/lib/hostIdentity.mjs";
38
- export { type ActivityGroup, AgentInfo, AssistantEntry, AttachPhase, BUILTIN_COMMANDS, CommandInfo, CompletionItem, CompletionKind, CompletionTrigger, ComposerPromptClaim, type ContextGroup, type ContextItemSource, DialogMethod, DialogPromptClaim, DialogRequest, EditorTextRequest, EntryKind, HOST_SLOTS, HistoryPage, ImageRefScope, InputSender, InstallDiagnostic, InstallDiagnosticKind, InstalledContextAction, InstalledDashboardTile, InstalledHomeContribution, type InstalledNativeTemplate, InstalledRepositorySettingsPanel, InstalledSettingsPanel, InstalledUserMessageAction, IntercomEntry, LEGACY_WORKSPACE_ID, MAX_COMPLETION_ITEMS, MenuClaim, MenuKind, MenuState, type MinorMode, ModelChoice, type NativeTemplateCatalog, NoticeEntry, ProfileIdentity, QueuedEntry, RailRestartState, RailSessionInput, ReduceSessionOptions, ResolvedFill, RpcImage, type SelectionAxis, SessionMeta, SessionRailModelInput, SessionSocket, SessionSocketHandlers, SessionState, SessionStats, SessionsState, SettledEntry, StatusClock, StatusLineInput, TRIGGER_CHARS, ThreadTranscriptReader, TimelineEntry, ToolEntry, ToolPromptClaim, ToolPromptInput, ToolRendererBoundary, type TransientTabActions, UPDATE_REQUIRED_REASON, UiTraceRecord, UiTraceSink, UserEntry, UserImage, WebPluginRegistry, WorkspacesState, abbreviateCwd, abortCommand, abortRun, activateWebPluginHost, activateWebPluginSession, activateWebPluginWorkspace, activeSessionId, activityGroupSlot, activityGroups, activityWaitingCount, answerDialogConfirm, answerDialogValue, appendQueued, appendUserPrompt, applyCaptureFrame, applyHistoryPage, applyProtocolQueue, applyProtocolTranscript, applySelectionAnswer, applySessionBacklog, applySessionFrame, applySessionLifecycle, applySessionRemoved, applySessionUpsert, applySessionsSnapshot, applyThreadFrame, applyThreadTranscriptFrame, applyWorkspaceRemoved, applyWorkspaceUpsert, applyWorkspacesSnapshot, beginSessionReplay, beginSessionTransfer, bindBundledNativeTemplates, bindHistoryReader, bindHostTransport, bindImageReader, bindSessionFileLinkModes, bindSessionProtocol, bindSessionWebWorkspace, bindThreadReader, bindTransport, buildRailWorkspaces, builtinCommandFrame, cancelDialog, claimDialogMenu, clearDialog, clearPendingMenu, clearQueueCommand, clearQueuedEntries, clearQueuedMessages, closeTransientTab, commandCompletions, compactCommand, completeSessionTransfer, contextGroups, createDashboardTransport, createPagedTranscript, createProtocolHubSocket, createToolCompletionTabs, createWebMcpSimulator, createWebPluginRegistry, dashboardTileFills, deleteQueuedMessage, dialogCancelled, dialogConfirmed, dialogValue, disconnectCaptures, dispatchChannelFrame, dispatchHeldSessionChannel, dropPluginSessionData, dropSessionStore, dropThreads, dropTransientTabs, endSessionReplay, enqueueAutomaticCommand, fileCompletions, fileTabForPath, findTransientTab, flushUiTrace, followUpCommand, getAvailableModelsCommand, getAvailableThinkingLevelsCommand, getCommandsCommand, getSessionStatsCommand, getStateCommand, globalSlotFills, hasSessionProtocol, heldSessionChannels, heldThreads, heldVoiceSessions, holdSessionChannels, holdVoiceSession, imagesFromContent, inactiveTotal, initialSessionState, installGlobalWebPlugins, installSessionWebPlugins, installWebPlugins, installWorkspaceWebPlugins, installedWebPlugins, invokeServerMethod, isDesktopClient, isSupportedImageMimeType, legacyHomeAppFills, loadImageRef, loadModelChoices, localHostId, markSocketClosed, markUpdateRequired, menuStore, mergeScopedPlugins, minorModes, nativeTemplateCatalog, noSessions, noteRender, noteStoreUpdate, notifyHubConnected, onCaptureStatus, onComposerSubmitted, onHubConnected, openTransientTab, ownerLabel, ownersOf, paletteCommands, parseDashboardTileData, parseHostKey, parseSelection, pendingMenuFor, pendingSetupView, personaInitials, pluginActivityGroups, pluginContextActions, pluginDockFaces, pluginFileLinks, pluginHomeContributions, pluginLeaderBindings, pluginMinorModes, pluginRepositorySettingsPanels, pluginSelectionAxes, pluginSessionContext, pluginSettingsPanels, pluginSettingsSections, pluginSlotProps, pluginToolRenderer, pluginUserMessageActions, pluginsAtScope, prependHistory, projectedGroups, promoteQueuedCommand, promoteQueuedMessage, promptCommand, qrMatrix, qualifyHostId, qualifyHostKey, queueFollowUp, queueFollowUpWithAck, railSessionStatus, reduceSession, refreshSessionFacts, refreshSessionSelection, refreshSessionStats, releaseDialogMenu, releaseProtocolTranscript, releaseTransport, removeHostWebPlugins, removeQueuedCommand, removeQueuedEntry, removeSessionWebPlugins, removeWorkspaceWebPlugins, renameSession, replaceQueuedEntries, requestLatestHistory, requestNewerHistory, requestOlderHistory, requestSessionProtocolFrame, resetMenuStore, resetSessionStore, resetSessionStores, resetSessions, resetThreads, resetWebPlugins, resetWorkspaces, resolveNativeTemplate, resolveParentId, resubscribeThreads, resumeQueueCommand, resumeQueuedMessages, reuseRailWorkspaces, rewindCommand, rewindToMessage, runCommand, runningCount, sameRailEntries, sameRailEntry, seedHistoryCursor, selectFastMode, selectModel, selectThinkingLevel, selectWorkspace, selectionAxes, selectionStatuses, sendFrame, sendFrameWithAck, sendHubFrame, sendSessionProtocolFrame, sessionMinorModes, sessionStatusClock, sessionStatusLine, sessionStoreFor, sessionToolRenderer, sessionWaitingCount, sessionWebPluginsInstalled, sessionsStore, setActiveSession, setAgentLock, setHasNewerHistory, setModelCommand, setPendingMenu, setSessionNameCommand, setSessionStreamed, setThinkingLevelCommand, setTransientTabSession, setUiTraceSink, setWebPluginLoadDiagnostics, slotFills, splitHostId, startPluginDefinitions, startWebPlugins, steerCommand, streamedSessions, submitCapture, submitMessage, submitMessageWithAck, subscribeActivitySources, subscribeThread, subscribeWebPluginRegistry, summariseArgs, summaryValueEqual, textFromContent, threadStoreKey, toolMessageProps, toolPromptClaim, totalTokens, traceProfilerRender, traceStore, transientTabsStore, transportForHost, triggerTokenAt, unsubscribeThread, updateDialogDraft, useActiveSession, useActiveSessionMeta, useActivityGroups, useDialogDraft, useDockFaceBadges, useDockFaces, useFileLinks, useHasOlderHistory, useImageRefs, useNoSessions, useRailEntries, useRailEntry, useRenderTrace, useTransientTabs, validateComposerCapture, waitForSession, watchHubThread, webPluginDiagnostics, webPluginRegistryForHost, webPluginRegistryRevision, webPluginsInstalled, webTabs, webTemplateCatalog, workspaceName, workspaceSlotFills, workspacesStore };
39
+ export { type ActivityGroup, AgentInfo, AssistantEntry, AttachPhase, BUILTIN_COMMANDS, CommandInfo, CompletionItem, CompletionKind, CompletionTrigger, ComposerPromptClaim, type ContextGroup, type ContextItemSource, DialogMethod, DialogPromptClaim, DialogRequest, EditorTextRequest, EntryKind, HOST_SLOTS, HistoryPage, ImageRefScope, InputSender, InstallDiagnostic, InstallDiagnosticKind, InstalledContextAction, InstalledDashboardTile, InstalledHomeContribution, type InstalledNativeTemplate, InstalledRepositorySettingsPanel, InstalledSettingsPanel, InstalledUserMessageAction, IntercomEntry, LEGACY_WORKSPACE_ID, MAX_COMPLETION_ITEMS, MenuClaim, MenuKind, MenuState, type MinorMode, ModelChoice, type NativeTemplateCatalog, NoticeEntry, ProfileIdentity, QueuedEntry, RailRestartState, RailSessionInput, ReduceSessionOptions, ResolvedFill, RpcImage, type SelectionAxis, SessionMeta, SessionRailModelInput, SessionSocket, SessionSocketHandlers, SessionState, SessionStats, SessionsState, SettledEntry, StatusClock, StatusLineInput, TRIGGER_CHARS, ThreadTranscriptReader, TimelineEntry, ToolEntry, ToolPromptClaim, ToolPromptInput, ToolRendererBoundary, type TransientTabActions, UPDATE_REQUIRED_REASON, UiTraceRecord, UiTraceSink, UserEntry, UserImage, WebPluginRegistry, WorkspacesState, abbreviateCwd, abortCommand, abortRun, activateWebPluginHost, activateWebPluginSession, activateWebPluginWorkspace, activeSessionId, activityGroupSlot, activityGroups, activityWaitingCount, answerDialogConfirm, answerDialogValue, appendQueued, appendUserPrompt, applyCaptureFrame, applyHistoryPage, applyProtocolQueue, applyProtocolTranscript, applySelectionAnswer, applySessionBacklog, applySessionFrame, applySessionLifecycle, applySessionRemoved, applySessionUpsert, applySessionsSnapshot, applyThreadFrame, applyThreadTranscriptFrame, applyWorkspaceRemoved, applyWorkspaceUpsert, applyWorkspacesSnapshot, beginSessionReplay, beginSessionTransfer, bindBundledNativeTemplates, bindHistoryReader, bindHostTransport, bindImageReader, bindSessionFileLinkModes, bindSessionProtocol, bindSessionWebWorkspace, bindThreadReader, bindTransport, buildRailWorkspaces, builtinCommandFrame, canSaveSettings, cancelDialog, claimDialogMenu, clearDialog, clearPendingMenu, clearQueueCommand, clearQueuedEntries, clearQueuedMessages, closeTransientTab, commandCompletions, compactCommand, completeSessionTransfer, contextGroups, createDashboardTransport, createPagedTranscript, createProtocolHubSocket, createToolCompletionTabs, createWebMcpSimulator, createWebPluginRegistry, dashboardTileFills, deleteQueuedMessage, dialogCancelled, dialogConfirmed, dialogValue, disconnectCaptures, dispatchChannelFrame, dispatchHeldSessionChannel, dropPluginSessionData, dropSessionStore, dropThreads, dropTransientTabs, endSessionReplay, enqueueAutomaticCommand, fileCompletions, fileTabForPath, findTransientTab, flushUiTrace, followUpCommand, getAvailableModelsCommand, getAvailableThinkingLevelsCommand, getCommandsCommand, getSessionStatsCommand, getStateCommand, globalSlotFills, hasSessionProtocol, heldSessionChannels, heldThreads, heldVoiceSessions, holdSessionChannels, holdVoiceSession, imagesFromContent, inactiveTotal, initialSessionState, installGlobalWebPlugins, installSessionWebPlugins, installWebPlugins, installWorkspaceWebPlugins, installedWebPlugins, invokeServerMethod, isDesktopClient, isSupportedImageMimeType, legacyHomeAppFills, loadImageRef, loadModelChoices, localHostId, markSocketClosed, markUpdateRequired, menuStore, mergeScopedPlugins, minorModes, nativeTemplateCatalog, noSessions, noteRender, noteStoreUpdate, notifyHubConnected, onCaptureStatus, onComposerSubmitted, onHubConnected, openTransientTab, ownerLabel, ownersOf, paletteCommands, parseDashboardTileData, parseHostKey, parseSelection, pendingMenuFor, pendingSetupView, personaInitials, plannedSettingsWrites, pluginActivityGroups, pluginContextActions, pluginDockFaces, pluginFileLinks, pluginHomeContributions, pluginLeaderBindings, pluginMinorModes, pluginRepositorySettingsPanels, pluginSelectionAxes, pluginSessionContext, pluginSettingsPanels, pluginSettingsSections, pluginSlotProps, pluginToolRenderer, pluginUserMessageActions, pluginsAtScope, prependHistory, projectedGroups, promoteQueuedCommand, promoteQueuedMessage, promptCommand, qrMatrix, qualifyHostId, qualifyHostKey, queueFollowUp, queueFollowUpWithAck, railSessionStatus, reduceSession, refreshSessionFacts, refreshSessionSelection, refreshSessionStats, releaseDialogMenu, releaseProtocolTranscript, releaseTransport, removeHostWebPlugins, removeQueuedCommand, removeQueuedEntry, removeSessionWebPlugins, removeWorkspaceWebPlugins, renameSession, replaceQueuedEntries, requestLatestHistory, requestNewerHistory, requestOlderHistory, requestSessionProtocolFrame, resetMenuStore, resetSessionStore, resetSessionStores, resetSessions, resetThreads, resetWebPlugins, resetWorkspaces, resolveNativeTemplate, resolveParentId, resubscribeThreads, resumeQueueCommand, resumeQueuedMessages, reuseRailWorkspaces, rewindCommand, rewindToMessage, runCommand, runningCount, sameRailEntries, sameRailEntry, seedHistoryCursor, selectFastMode, selectModel, selectThinkingLevel, selectWorkspace, selectionAxes, selectionStatuses, sendFrame, sendFrameWithAck, sendHubFrame, sendSessionProtocolFrame, sessionMinorModes, sessionStatusClock, sessionStatusLine, sessionStoreFor, sessionToolRenderer, sessionWaitingCount, sessionWebPluginsInstalled, sessionsStore, setActiveSession, setAgentLock, setHasNewerHistory, setModelCommand, setPendingMenu, setSessionNameCommand, setSessionStreamed, setThinkingLevelCommand, setTransientTabSession, setUiTraceSink, setWebPluginLoadDiagnostics, settingsKeyOf, settingsLockedReason, slotFills, splitHostId, startPluginDefinitions, startWebPlugins, steerCommand, streamedSessions, submitCapture, submitMessage, submitMessageWithAck, subscribeActivitySources, subscribeThread, subscribeWebPluginRegistry, summariseArgs, summaryValueEqual, textFromContent, threadStoreKey, toolMessageProps, toolPromptClaim, totalTokens, traceProfilerRender, traceStore, transientTabsStore, transportForHost, triggerTokenAt, unsubscribeThread, updateDialogDraft, useActiveSession, useActiveSessionMeta, useActivityGroups, useDialogDraft, useDockFaceBadges, useDockFaces, useFileLinks, useHasOlderHistory, useImageRefs, useNoSessions, useRailEntries, useRailEntry, useRenderTrace, useTransientTabs, validateComposerCapture, waitForSession, watchHubThread, webPluginDiagnostics, webPluginRegistryForHost, webPluginRegistryRevision, webPluginsInstalled, webTabs, webTemplateCatalog, workspaceName, workspaceSlotFills, workspacesStore };
package/dist/core.mjs CHANGED
@@ -18,6 +18,7 @@ import { appendQueued, appendUserPrompt, applySelectionAnswer, clearDialog, clea
18
18
  import { qrMatrix } from "./web/lib/qrMatrix.mjs";
19
19
  import { abbreviateCwd, personaInitials, runningCount, sessionStatusClock, sessionStatusLine, summaryValueEqual } from "./web/lib/sessionSummary.mjs";
20
20
  import { LEGACY_WORKSPACE_ID, activityWaitingCount, buildRailWorkspaces, pendingSetupView, railSessionStatus, reuseRailWorkspaces, sessionWaitingCount, workspaceName } from "./web/lib/sessionRailModel.mjs";
21
+ import { canSaveSettings, plannedSettingsWrites, settingsKeyOf, settingsLockedReason } from "./web/lib/settingsDraft.mjs";
21
22
  import { createToolCompletionTabs } from "./web/lib/toolCompletionTabs.mjs";
22
23
  import { toolMessageProps } from "./web/lib/toolMessageProps.mjs";
23
24
  import { toolPromptClaim } from "./web/lib/toolPrompt.mjs";
@@ -35,4 +36,4 @@ import { applyThreadTranscriptFrame, bindThreadReader, dropThreads, heldThreads,
35
36
  import { closeTransientTab, dropTransientTabs, findTransientTab, openTransientTab, setTransientTabSession, transientTabsStore, useTransientTabs } from "./web/stores/transientTabsStore.mjs";
36
37
  import { updateDialogDraft, useDialogDraft } from "./web/stores/dialogDraftStore.mjs";
37
38
  import { createWebMcpSimulator } from "./web/lib/webmcpSimulator.mjs";
38
- export { BUILTIN_COMMANDS, HOST_SLOTS, ImageRefScope, LEGACY_WORKSPACE_ID, MAX_COMPLETION_ITEMS, TRIGGER_CHARS, ToolRendererBoundary, UPDATE_REQUIRED_REASON, abbreviateCwd, abortCommand, abortRun, activateWebPluginHost, activateWebPluginSession, activateWebPluginWorkspace, activeSessionId, activityGroupSlot, activityGroups, activityWaitingCount, answerDialogConfirm, answerDialogValue, appendQueued, appendUserPrompt, applyCaptureFrame, applyHistoryPage, applyProtocolQueue, applyProtocolTranscript, applySelectionAnswer, applySessionBacklog, applySessionFrame, applySessionLifecycle, applySessionRemoved, applySessionUpsert, applySessionsSnapshot, applyThreadFrame, applyThreadTranscriptFrame, applyWorkspaceRemoved, applyWorkspaceUpsert, applyWorkspacesSnapshot, beginSessionReplay, beginSessionTransfer, bindBundledNativeTemplates, bindHistoryReader, bindHostTransport, bindImageReader, bindSessionFileLinkModes, bindSessionProtocol, bindSessionWebWorkspace, bindThreadReader, bindTransport, buildRailWorkspaces, builtinCommandFrame, cancelDialog, claimDialogMenu, clearDialog, clearPendingMenu, clearQueueCommand, clearQueuedEntries, clearQueuedMessages, closeTransientTab, commandCompletions, compactCommand, completeSessionTransfer, contextGroups, createDashboardTransport, createPagedTranscript, createProtocolHubSocket, createToolCompletionTabs, createWebMcpSimulator, createWebPluginRegistry, dashboardTileFills, deleteQueuedMessage, dialogCancelled, dialogConfirmed, dialogValue, disconnectCaptures, dispatchChannelFrame, dispatchHeldSessionChannel, dropPluginSessionData, dropSessionStore, dropThreads, dropTransientTabs, endSessionReplay, enqueueAutomaticCommand, fileCompletions, fileTabForPath, findTransientTab, flushUiTrace, followUpCommand, getAvailableModelsCommand, getAvailableThinkingLevelsCommand, getCommandsCommand, getSessionStatsCommand, getStateCommand, globalSlotFills, hasSessionProtocol, heldSessionChannels, heldThreads, heldVoiceSessions, holdSessionChannels, holdVoiceSession, imagesFromContent, inactiveTotal, initialSessionState, installGlobalWebPlugins, installSessionWebPlugins, installWebPlugins, installWorkspaceWebPlugins, installedWebPlugins, invokeServerMethod, isDesktopClient, isSupportedImageMimeType, legacyHomeAppFills, loadImageRef, loadModelChoices, localHostId, markSocketClosed, markUpdateRequired, menuStore, mergeScopedPlugins, minorModes, nativeTemplateCatalog, noSessions, noteRender, noteStoreUpdate, notifyHubConnected, onCaptureStatus, onComposerSubmitted, onHubConnected, openTransientTab, ownerLabel, ownersOf, paletteCommands, parseDashboardTileData, parseHostKey, parseSelection, pendingMenuFor, pendingSetupView, personaInitials, pluginActivityGroups, pluginContextActions, pluginDockFaces, pluginFileLinks, pluginHomeContributions, pluginLeaderBindings, pluginMinorModes, pluginRepositorySettingsPanels, pluginSelectionAxes, pluginSessionContext, pluginSettingsPanels, pluginSettingsSections, pluginSlotProps, pluginToolRenderer, pluginUserMessageActions, pluginsAtScope, prependHistory, projectedGroups, promoteQueuedCommand, promoteQueuedMessage, promptCommand, qrMatrix, qualifyHostId, qualifyHostKey, queueFollowUp, queueFollowUpWithAck, railSessionStatus, reduceSession, refreshSessionFacts, refreshSessionSelection, refreshSessionStats, releaseDialogMenu, releaseProtocolTranscript, releaseTransport, removeHostWebPlugins, removeQueuedCommand, removeQueuedEntry, removeSessionWebPlugins, removeWorkspaceWebPlugins, renameSession, replaceQueuedEntries, requestLatestHistory, requestNewerHistory, requestOlderHistory, requestSessionProtocolFrame, resetMenuStore, resetSessionStore, resetSessionStores, resetSessions, resetThreads, resetWebPlugins, resetWorkspaces, resolveNativeTemplate, resolveParentId, resubscribeThreads, resumeQueueCommand, resumeQueuedMessages, reuseRailWorkspaces, rewindCommand, rewindToMessage, runCommand, runningCount, sameRailEntries, sameRailEntry, seedHistoryCursor, selectFastMode, selectModel, selectThinkingLevel, selectWorkspace, selectionAxes, selectionStatuses, sendFrame, sendFrameWithAck, sendHubFrame, sendSessionProtocolFrame, sessionMinorModes, sessionStatusClock, sessionStatusLine, sessionStoreFor, sessionToolRenderer, sessionWaitingCount, sessionWebPluginsInstalled, sessionsStore, setActiveSession, setAgentLock, setHasNewerHistory, setModelCommand, setPendingMenu, setSessionNameCommand, setSessionStreamed, setThinkingLevelCommand, setTransientTabSession, setUiTraceSink, setWebPluginLoadDiagnostics, slotFills, splitHostId, startPluginDefinitions, startWebPlugins, steerCommand, streamedSessions, submitCapture, submitMessage, submitMessageWithAck, subscribeActivitySources, subscribeThread, subscribeWebPluginRegistry, summariseArgs, summaryValueEqual, textFromContent, threadStoreKey, toolMessageProps, toolPromptClaim, totalTokens, traceProfilerRender, traceStore, transientTabsStore, transportForHost, triggerTokenAt, unsubscribeThread, updateDialogDraft, useActiveSession, useActiveSessionMeta, useActivityGroups, useDialogDraft, useDockFaceBadges, useDockFaces, useFileLinks, useHasOlderHistory, useImageRefs, useNoSessions, useRailEntries, useRailEntry, useRenderTrace, useTransientTabs, validateComposerCapture, waitForSession, watchHubThread, webPluginDiagnostics, webPluginRegistryForHost, webPluginRegistryRevision, webPluginsInstalled, webTabs, webTemplateCatalog, workspaceName, workspaceSlotFills, workspacesStore };
39
+ export { BUILTIN_COMMANDS, HOST_SLOTS, ImageRefScope, LEGACY_WORKSPACE_ID, MAX_COMPLETION_ITEMS, TRIGGER_CHARS, ToolRendererBoundary, UPDATE_REQUIRED_REASON, abbreviateCwd, abortCommand, abortRun, activateWebPluginHost, activateWebPluginSession, activateWebPluginWorkspace, activeSessionId, activityGroupSlot, activityGroups, activityWaitingCount, answerDialogConfirm, answerDialogValue, appendQueued, appendUserPrompt, applyCaptureFrame, applyHistoryPage, applyProtocolQueue, applyProtocolTranscript, applySelectionAnswer, applySessionBacklog, applySessionFrame, applySessionLifecycle, applySessionRemoved, applySessionUpsert, applySessionsSnapshot, applyThreadFrame, applyThreadTranscriptFrame, applyWorkspaceRemoved, applyWorkspaceUpsert, applyWorkspacesSnapshot, beginSessionReplay, beginSessionTransfer, bindBundledNativeTemplates, bindHistoryReader, bindHostTransport, bindImageReader, bindSessionFileLinkModes, bindSessionProtocol, bindSessionWebWorkspace, bindThreadReader, bindTransport, buildRailWorkspaces, builtinCommandFrame, canSaveSettings, cancelDialog, claimDialogMenu, clearDialog, clearPendingMenu, clearQueueCommand, clearQueuedEntries, clearQueuedMessages, closeTransientTab, commandCompletions, compactCommand, completeSessionTransfer, contextGroups, createDashboardTransport, createPagedTranscript, createProtocolHubSocket, createToolCompletionTabs, createWebMcpSimulator, createWebPluginRegistry, dashboardTileFills, deleteQueuedMessage, dialogCancelled, dialogConfirmed, dialogValue, disconnectCaptures, dispatchChannelFrame, dispatchHeldSessionChannel, dropPluginSessionData, dropSessionStore, dropThreads, dropTransientTabs, endSessionReplay, enqueueAutomaticCommand, fileCompletions, fileTabForPath, findTransientTab, flushUiTrace, followUpCommand, getAvailableModelsCommand, getAvailableThinkingLevelsCommand, getCommandsCommand, getSessionStatsCommand, getStateCommand, globalSlotFills, hasSessionProtocol, heldSessionChannels, heldThreads, heldVoiceSessions, holdSessionChannels, holdVoiceSession, imagesFromContent, inactiveTotal, initialSessionState, installGlobalWebPlugins, installSessionWebPlugins, installWebPlugins, installWorkspaceWebPlugins, installedWebPlugins, invokeServerMethod, isDesktopClient, isSupportedImageMimeType, legacyHomeAppFills, loadImageRef, loadModelChoices, localHostId, markSocketClosed, markUpdateRequired, menuStore, mergeScopedPlugins, minorModes, nativeTemplateCatalog, noSessions, noteRender, noteStoreUpdate, notifyHubConnected, onCaptureStatus, onComposerSubmitted, onHubConnected, openTransientTab, ownerLabel, ownersOf, paletteCommands, parseDashboardTileData, parseHostKey, parseSelection, pendingMenuFor, pendingSetupView, personaInitials, plannedSettingsWrites, pluginActivityGroups, pluginContextActions, pluginDockFaces, pluginFileLinks, pluginHomeContributions, pluginLeaderBindings, pluginMinorModes, pluginRepositorySettingsPanels, pluginSelectionAxes, pluginSessionContext, pluginSettingsPanels, pluginSettingsSections, pluginSlotProps, pluginToolRenderer, pluginUserMessageActions, pluginsAtScope, prependHistory, projectedGroups, promoteQueuedCommand, promoteQueuedMessage, promptCommand, qrMatrix, qualifyHostId, qualifyHostKey, queueFollowUp, queueFollowUpWithAck, railSessionStatus, reduceSession, refreshSessionFacts, refreshSessionSelection, refreshSessionStats, releaseDialogMenu, releaseProtocolTranscript, releaseTransport, removeHostWebPlugins, removeQueuedCommand, removeQueuedEntry, removeSessionWebPlugins, removeWorkspaceWebPlugins, renameSession, replaceQueuedEntries, requestLatestHistory, requestNewerHistory, requestOlderHistory, requestSessionProtocolFrame, resetMenuStore, resetSessionStore, resetSessionStores, resetSessions, resetThreads, resetWebPlugins, resetWorkspaces, resolveNativeTemplate, resolveParentId, resubscribeThreads, resumeQueueCommand, resumeQueuedMessages, reuseRailWorkspaces, rewindCommand, rewindToMessage, runCommand, runningCount, sameRailEntries, sameRailEntry, seedHistoryCursor, selectFastMode, selectModel, selectThinkingLevel, selectWorkspace, selectionAxes, selectionStatuses, sendFrame, sendFrameWithAck, sendHubFrame, sendSessionProtocolFrame, sessionMinorModes, sessionStatusClock, sessionStatusLine, sessionStoreFor, sessionToolRenderer, sessionWaitingCount, sessionWebPluginsInstalled, sessionsStore, setActiveSession, setAgentLock, setHasNewerHistory, setModelCommand, setPendingMenu, setSessionNameCommand, setSessionStreamed, setThinkingLevelCommand, setTransientTabSession, setUiTraceSink, setWebPluginLoadDiagnostics, settingsKeyOf, settingsLockedReason, slotFills, splitHostId, startPluginDefinitions, startWebPlugins, steerCommand, streamedSessions, submitCapture, submitMessage, submitMessageWithAck, subscribeActivitySources, subscribeThread, subscribeWebPluginRegistry, summariseArgs, summaryValueEqual, textFromContent, threadStoreKey, toolMessageProps, toolPromptClaim, totalTokens, traceProfilerRender, traceStore, transientTabsStore, transportForHost, triggerTokenAt, unsubscribeThread, updateDialogDraft, useActiveSession, useActiveSessionMeta, useActivityGroups, useDialogDraft, useDockFaceBadges, useDockFaces, useFileLinks, useHasOlderHistory, useImageRefs, useNoSessions, useRailEntries, useRailEntry, useRenderTrace, useTransientTabs, validateComposerCapture, waitForSession, watchHubThread, webPluginDiagnostics, webPluginRegistryForHost, webPluginRegistryRevision, webPluginsInstalled, webTabs, webTemplateCatalog, workspaceName, workspaceSlotFills, workspacesStore };
package/dist/index.d.mts CHANGED
@@ -24,6 +24,7 @@ import { ThreadTranscriptReader, applyThreadTranscriptFrame, bindThreadReader, d
24
24
  import { WorkspacesState, applyWorkspaceRemoved, applyWorkspaceUpsert, applyWorkspacesSnapshot, resetWorkspaces, selectWorkspace, workspacesStore } from "./web/stores/workspacesStore.mjs";
25
25
  import { ActivityGroup, FileLinkResolver, MinorMode, MinorModeAvailability, MinorModeSource, PACKAGED_MINOR_MODES, PACKAGED_SELECTION_AXES, SelectionAxis, activityGroups, bindFileLinkModes, fileLinkFor, fileLinkMentions, fileTabForPath, minorModes, selectionAxes, subscribeActivitySources, useActivityGroups, useDockFaceBadges, useDockFaces, useFileLinks } from "./web/lib/composition.mjs";
26
26
  import { Selection, ansiSegments, emptySelection, parseSelection, stripAnsi } from "./web/lib/statusLine.mjs";
27
+ import { PlannedWritesInput, canSaveSettings, plannedSettingsWrites, settingsKeyOf, settingsLockedReason } from "./web/lib/settingsDraft.mjs";
27
28
  import { MenuClaim, MenuKind, MenuState, claimDialogMenu, clearPendingMenu, menuStore, pendingMenuFor, releaseDialogMenu, resetMenuStore, setPendingMenu } from "./web/stores/menuStore.mjs";
28
29
  import { ContextGroup, ContextGroupKind, ContextItem, ContextItemSource, ContextOwner, contextGroups, inactiveTotal, ownerLabel, ownersOf, projectedGroups, totalTokens } from "./web/lib/contextComposition.mjs";
29
30
  import { closeTransientTab, dropTransientTabs, findTransientTab, openTransientTab, resetTransientTabs, setTransientTabSession, transientTabsOf, transientTabsStore, useTransientTabs } from "./web/stores/transientTabsStore.mjs";
@@ -56,7 +57,6 @@ import { loadSessionAvatar } from "./web/lib/sessionAvatar.mjs";
56
57
  import { SessionMcpResult, createSessionMcpClient, isSessionMcpActivity, listSessionMcpClients, readSessionMcpActivity, readSessionMcpConfig, removeSessionMcpSetup, revokeSessionMcpClient } from "./web/lib/sessionMcpApi.mjs";
57
58
  import { bindSessionTranscriptRenderer, releaseSessionTranscriptRenderer, renderSessionTranscript } from "./web/lib/sessionTranscriptRenderer.mjs";
58
59
  import { ImageSettingsResult, ReadConfigResult, ReadRepositorySettingsResult, WriteConfigResult, listSettingsModels, listSettingsRepositories, readImageSettings, readRepositorySettings, readSettingsConfig, writeImageSettings, writeRepositorySelection, writeSettingsValue } from "./web/lib/settingsApi.mjs";
59
- import { PlannedWritesInput, canSaveSettings, plannedSettingsWrites, settingsKeyOf, settingsLockedReason } from "./web/lib/settingsDraft.mjs";
60
60
  import { DEFAULT_REPOSITORY_SETTINGS_SECTION, DEFAULT_SETTINGS_SECTION, SettingsSection, SettingsWorkspace, settingsSection, settingsSections } from "./web/lib/settingsSections.mjs";
61
61
  import { fetchWithStepUp } from "./web/lib/stepUp.mjs";
62
62
  import { bindThreadRenderer, releaseThreadRenderer, renderThread } from "./web/lib/threadRenderer.mjs";
package/dist/types.d.mts CHANGED
@@ -1,11 +1,11 @@
1
1
  import { ATTACHED_TYPE, ATTACH_ERROR_TYPE, ATTACH_TYPE, BRIDGE_STATUS_TYPE, BridgeState, BridgeStatusFrame, REPLAY_TYPE, SessionFrame, bridgeStatus } from "./types/session.mjs";
2
2
  import { AGENT_MODEL_ENTRY_TYPE, API_SESSION_QUERY_PARAM, CONTEXT_ENTRY_TYPE, ContextGroupKind, ContextGroupProjection, ContextItemProjection, ContextItemSource, ContextProjection, DIALOG_ANSWERED_TYPE, DIRECTORIES_API_ROUTE, DIRECTORY_CHILDREN_API_ROUTE, DirectoryListing, HISTORY_PAGE_SIZE, HISTORY_PAGE_TYPE, HISTORY_REQUEST_TYPE, HUB_HELLO_TYPE, HUB_PROTOCOL_VERSION, HUB_ROLE, HistoryPageFrame, HistoryRequestFrame, HubHelloFrame, MINOR_MODE_ENTRY_TYPE, MinorModeActionProjection, MinorModeProjection, MinorModeRecordProjection, PO_FOLDERS_API_ROUTE, PROFILE_IDENTITY_ENTRY_TYPE, PiSessionHistoryItem, RESOURCE_CATALOG_ENTRY_TYPE, RemovedSessionItem, SESSIONS_API_ROUTE, SESSION_COMMAND_TYPE, SessionCommandFrame, SessionGitStatus, SessionNativeComposition, SessionPhase, SessionProfile, SessionSummary, SessionWebComposition, WORKSPACES_API_ROUTE, WORKSPACE_SANDBOX_STATES, WorkspaceSandboxState, WorkspaceSummary, hubHello, sessionCommand } from "./types/hub.mjs";
3
+ import { RepositoryCatalogOption, RepositorySelectionChanges, RepositorySelectionValue, RepositorySelectionWriteRequest, RepositorySettingsView, SETTINGS_CONFIG_API_ROUTE, SETTINGS_IMAGES_API_ROUTE, SETTINGS_MODELS_API_ROUTE, SETTINGS_REPOSITORIES_API_ROUTE, SETTINGS_REPOSITORY_API_ROUTE, SETTINGS_REPOSITORY_SELECTION_API_ROUTE, SETTINGS_VALUE_API_ROUTE, SettingsBatchWriteRequest, SettingsConfigView, SettingsErrorView, SettingsImagesView, SettingsImagesWriteRequest, SettingsKeyScope, SettingsModel, SettingsOrigin, SettingsRepository, SettingsScope, SettingsValueView, SettingsWriteRequest } from "./types/settings.mjs";
3
4
  import { AUTH_LOGINS_API_ROUTE, AUTH_PROVIDERS_API_ROUTE, AuthMethodType, AuthRuntime, AuthRuntimeProvider, LoginEvent, LoginFlowSnapshot, LoginFlowStatus, LoginInteraction, LoginPrompt, LoginPromptView, LoginSelectOption, ProviderAuthMethod, ProviderAuthSummary } from "./types/auth.mjs";
4
5
  import { DEV_PROXY_API_ROUTE, DEV_PROXY_PREFIX, DEV_PROXY_TARGETS_ROUTE, DevProxyStateView, DevProxyTarget } from "./types/devProxy.mjs";
5
6
  import { MAX_SESSION_FILE_BYTES, MEDIA_TYPES, MediaKind, MediaType, SESSION_FILE_EXPECTED_SHA256_HEADER, SESSION_FILE_ROUTE, SESSION_FILE_SHA256_HEADER, sessionFileUrl } from "./types/media.mjs";
6
7
  import { BUNDLE_MINIMUM_REVISION_PARAM, BUNDLE_SIGNING_KEY_PARAM, BundlePairingTrust, COOKIE_CEILING_SECONDS, DEVICE_COOKIE, NATIVE_PAIRING_LINK_PREFIX, PAIRING_CLAIM_ROUTE, PAIRING_CODE_TTL_MS, PAIRING_PAGE_ROUTE, PAIRING_REQUEST_TTL_MS, PAIRING_STATUS_QUERY, PAIRING_STATUS_ROUTE, PASSKEY_AUTH_BEGIN_ROUTE, PASSKEY_AUTH_FINISH_ROUTE, PASSKEY_REGISTER_BEGIN_ROUTE, PASSKEY_REGISTER_FINISH_ROUTE, PROTOCOL_SOCKET_ROUTE, PairedDeviceView, PairingRequestView, PairingStatus, REMOTE_API_ROUTE, REMOTE_CHANNEL_ROUTE, REMOTE_HTTP_ROUTE, REMOTE_PAIRING_REQUEST_TYPE, REMOTE_PUSH_KEY_ROUTE, REMOTE_PUSH_ROUTE, REMOTE_STATE_TYPE, RemoteAccessSettings, RemoteAccessStateView, RemoteAccessStatus, RemoteChannelScope, STEP_UP_HEADER, TRUSTED_DEVICES_ROUTE, TrustedDevicePlatform, TrustedDeviceView, TunnelConfig, TunnelFailure, TunnelKind, TunnelLauncher, TunnelStartInput, TunnelStartResult, WEB_DEV_SERVER_PORT } from "./types/remoteAccess.mjs";
7
8
  import { CreateSessionMcpClientInput, CreatedSessionMcpClient, SessionMcpClient, SessionMcpConfig, SessionMcpRouting, SessionMcpScope, SessionMcpSkill, SessionMcpTool } from "./types/sessionMcp.mjs";
8
- import { RepositoryCatalogOption, RepositorySelectionChanges, RepositorySelectionValue, RepositorySelectionWriteRequest, RepositorySettingsView, SETTINGS_CONFIG_API_ROUTE, SETTINGS_IMAGES_API_ROUTE, SETTINGS_MODELS_API_ROUTE, SETTINGS_REPOSITORIES_API_ROUTE, SETTINGS_REPOSITORY_API_ROUTE, SETTINGS_REPOSITORY_SELECTION_API_ROUTE, SETTINGS_VALUE_API_ROUTE, SettingsBatchWriteRequest, SettingsConfigView, SettingsErrorView, SettingsImagesView, SettingsImagesWriteRequest, SettingsKeyScope, SettingsModel, SettingsOrigin, SettingsRepository, SettingsScope, SettingsValueView, SettingsWriteRequest } from "./types/settings.mjs";
9
9
  import { WebServer, WebServerOptions } from "./types/bridge.mjs";
10
10
  import { PoNotificationEntry, parsePoNotificationEntry } from "./types/notification.mjs";
11
11
  export { AGENT_MODEL_ENTRY_TYPE, API_SESSION_QUERY_PARAM, ATTACHED_TYPE, ATTACH_ERROR_TYPE, ATTACH_TYPE, AUTH_LOGINS_API_ROUTE, AUTH_PROVIDERS_API_ROUTE, AuthMethodType, AuthRuntime, AuthRuntimeProvider, BRIDGE_STATUS_TYPE, BUNDLE_MINIMUM_REVISION_PARAM, BUNDLE_SIGNING_KEY_PARAM, BridgeState, BridgeStatusFrame, BundlePairingTrust, CONTEXT_ENTRY_TYPE, COOKIE_CEILING_SECONDS, ContextGroupKind, ContextGroupProjection, ContextItemProjection, ContextItemSource, ContextProjection, CreateSessionMcpClientInput, CreatedSessionMcpClient, DEVICE_COOKIE, DEV_PROXY_API_ROUTE, DEV_PROXY_PREFIX, DEV_PROXY_TARGETS_ROUTE, DIALOG_ANSWERED_TYPE, DIRECTORIES_API_ROUTE, DIRECTORY_CHILDREN_API_ROUTE, DevProxyStateView, DevProxyTarget, DirectoryListing, HISTORY_PAGE_SIZE, HISTORY_PAGE_TYPE, HISTORY_REQUEST_TYPE, HUB_HELLO_TYPE, HUB_PROTOCOL_VERSION, HUB_ROLE, HistoryPageFrame, HistoryRequestFrame, HubHelloFrame, LoginEvent, LoginFlowSnapshot, LoginFlowStatus, LoginInteraction, LoginPrompt, LoginPromptView, LoginSelectOption, MAX_SESSION_FILE_BYTES, MEDIA_TYPES, MINOR_MODE_ENTRY_TYPE, MediaKind, MediaType, MinorModeActionProjection, MinorModeProjection, MinorModeRecordProjection, NATIVE_PAIRING_LINK_PREFIX, PAIRING_CLAIM_ROUTE, PAIRING_CODE_TTL_MS, PAIRING_PAGE_ROUTE, PAIRING_REQUEST_TTL_MS, PAIRING_STATUS_QUERY, PAIRING_STATUS_ROUTE, PASSKEY_AUTH_BEGIN_ROUTE, PASSKEY_AUTH_FINISH_ROUTE, PASSKEY_REGISTER_BEGIN_ROUTE, PASSKEY_REGISTER_FINISH_ROUTE, PO_FOLDERS_API_ROUTE, PROFILE_IDENTITY_ENTRY_TYPE, PROTOCOL_SOCKET_ROUTE, PairedDeviceView, PairingRequestView, PairingStatus, PiSessionHistoryItem, PoNotificationEntry, ProviderAuthMethod, ProviderAuthSummary, REMOTE_API_ROUTE, REMOTE_CHANNEL_ROUTE, REMOTE_HTTP_ROUTE, REMOTE_PAIRING_REQUEST_TYPE, REMOTE_PUSH_KEY_ROUTE, REMOTE_PUSH_ROUTE, REMOTE_STATE_TYPE, REPLAY_TYPE, RESOURCE_CATALOG_ENTRY_TYPE, RemoteAccessSettings, RemoteAccessStateView, RemoteAccessStatus, RemoteChannelScope, RemovedSessionItem, RepositoryCatalogOption, RepositorySelectionChanges, RepositorySelectionValue, RepositorySelectionWriteRequest, RepositorySettingsView, SESSIONS_API_ROUTE, SESSION_COMMAND_TYPE, SESSION_FILE_EXPECTED_SHA256_HEADER, SESSION_FILE_ROUTE, SESSION_FILE_SHA256_HEADER, SETTINGS_CONFIG_API_ROUTE, SETTINGS_IMAGES_API_ROUTE, SETTINGS_MODELS_API_ROUTE, SETTINGS_REPOSITORIES_API_ROUTE, SETTINGS_REPOSITORY_API_ROUTE, SETTINGS_REPOSITORY_SELECTION_API_ROUTE, SETTINGS_VALUE_API_ROUTE, STEP_UP_HEADER, SessionCommandFrame, SessionFrame, SessionGitStatus, SessionMcpClient, SessionMcpConfig, SessionMcpRouting, SessionMcpScope, SessionMcpSkill, SessionMcpTool, SessionNativeComposition, SessionPhase, SessionProfile, SessionSummary, SessionWebComposition, SettingsBatchWriteRequest, SettingsConfigView, SettingsErrorView, SettingsImagesView, SettingsImagesWriteRequest, SettingsKeyScope, SettingsModel, SettingsOrigin, SettingsRepository, SettingsScope, SettingsValueView, SettingsWriteRequest, TRUSTED_DEVICES_ROUTE, TrustedDevicePlatform, TrustedDeviceView, TunnelConfig, TunnelFailure, TunnelKind, TunnelLauncher, TunnelStartInput, TunnelStartResult, WEB_DEV_SERVER_PORT, WORKSPACES_API_ROUTE, WORKSPACE_SANDBOX_STATES, WebServer, WebServerOptions, WorkspaceSandboxState, WorkspaceSummary, bridgeStatus, hubHello, parsePoNotificationEntry, sessionCommand, sessionFileUrl };
@@ -216,6 +216,7 @@ function createPagedTranscript(sessionId, service, onFrame, context, record = ()
216
216
  request("latest");
217
217
  return;
218
218
  }
219
+ if (previous === void 0 && !loading && pages.length > 0) for (const event of state.presentation?.projections ?? []) emit(event.frame, true);
219
220
  for (const event of state.presentation?.events ?? []) {
220
221
  if (!replay && event.sequence > previous && (event.frame.type === "tool_execution_start" || event.frame.type === "tool_execution_end")) onToolFrame?.(sessionId, event.frame, false);
221
222
  if (loading || pages.length === 0) {
@@ -1 +1 @@
1
- {"version":3,"file":"pagedTranscriptStore.cjs","names":["hasSessionProtocol","refreshSessionSelection","bindHistoryReader","bindImageReader"],"sources":["../../../src/web/stores/pagedTranscriptStore.ts"],"sourcesContent":["import type {\n ProtocolEvent,\n SessionLive,\n SessionService,\n SessionServiceState,\n TranscriptPage,\n} from '@agimon-ai/po-core/sessionProtocol';\nimport { type Context } from '@earendil-works/chord';\n\nimport type { BrowserPerformanceEvent } from '../lib/browserTelemetry';\nimport { hasSessionProtocol } from '../lib/sessionProtocolCommands';\nimport { bindImageReader } from './imageRefStore';\nimport {\n applySessionLifecycle,\n bindHistoryReader,\n resetSessionStore,\n refreshSessionSelection,\n beginSessionReplay,\n endSessionReplay,\n releaseProtocolTranscript,\n setHasNewerHistory,\n setSessionStreamed,\n} from './sessionStore';\n\nconst MAX_PAGES = 5;\nconst PAGE_SIZE = 100;\nconst MAX_BUFFER = 512;\ntype Direction = 'older' | 'newer' | 'latest';\n\n/** A bounded history window with a separate live event subscription. */\nexport function createPagedTranscript(\n sessionId: string,\n service: Pick<SessionService, 'readTranscriptPage'>,\n onFrame: (sessionId: string, frame: Record<string, unknown>, replay: boolean) => void,\n context: Context,\n record: (event: BrowserPerformanceEvent) => void = () => {},\n onToolFrame?: typeof onFrame,\n) {\n let pages: TranscriptPage[] = [];\n let revision = 0;\n let loading = false;\n let disposed = false;\n let overflow = false;\n let reloadPending = false;\n let buffered: ProtocolEvent[] = [];\n let latestState: SessionServiceState | undefined;\n const emit = (frame: Record<string, unknown>, replay = false) => onFrame(sessionId, frame, replay);\n const atLatest = () => pages.at(-1)?.newerCursor === null;\n const paged = (id: unknown) =>\n pages.some((page) =>\n page.entries.some((item) => item && typeof item === 'object' && !Array.isArray(item) && item.id === id),\n );\n // `live` holds whole values, so each change folds in as one replacing frame.\n const emitLive = (live: SessionLive | undefined, previous: SessionLive | undefined, replay: boolean) => {\n if (live?.message && live.message !== previous?.message)\n emit({ type: 'message_update', message: live.message }, replay);\n for (const tool of Object.values(live?.tools ?? {})) {\n if (replay)\n emit(\n { type: 'tool_execution_start', toolCallId: tool.toolCallId, toolName: tool.toolName, args: tool.args },\n true,\n );\n if (tool.partialResult && tool.partialResult !== previous?.tools[tool.toolCallId]?.partialResult)\n emit({ type: 'tool_execution_update', toolCallId: tool.toolCallId, partialResult: tool.partialResult }, replay);\n }\n };\n const rebuild = () => {\n const started = performance.now();\n releaseProtocolTranscript(sessionId);\n beginSessionReplay(sessionId);\n try {\n resetSessionStore(sessionId);\n for (const entry of pages[0]?.context ?? []) emit({ type: 'entry_appended', entry }, true);\n for (const page of pages) for (const entry of page.entries) emit({ type: 'entry_appended', entry }, true);\n // Current projections win over historical configuration in the transcript page.\n for (const event of latestState?.presentation?.projections ?? []) emit(event.frame, true);\n if (atLatest()) emitLive(latestState?.live, undefined, true);\n if (latestState?.snapshot.lifecycle) applySessionLifecycle(sessionId, latestState.snapshot.lifecycle);\n else if (latestState?.live?.phase === 'turn') emit({ type: 'agent_start' }, true);\n setHasNewerHistory(sessionId, !atLatest());\n } finally {\n endSessionReplay(sessionId);\n record({\n name: 'web.browser.transcript_render',\n duration_ms: performance.now() - started,\n count: pages.reduce((count, page) => count + page.entries.length, 0),\n });\n }\n };\n const apply = (event: ProtocolEvent) => {\n if (event.sequence <= revision) return;\n if (revision > 0 && event.sequence > revision + 1) {\n request('latest');\n return;\n }\n revision = event.sequence;\n const frame = event.frame;\n if (frame.type === 'navigation_end' || frame.type === 'message_end') {\n if (frame.type === 'message_end') {\n emit(frame);\n // The entry_appended sent just before it already put the committed entry on the page. Only a\n // runtime that sent none, or a page scrolled away from the latest, needs the page read again.\n if (typeof frame.entryId === 'string' && paged(frame.entryId)) return;\n }\n request('latest');\n return;\n }\n if (\n !atLatest() &&\n [\n 'message_start',\n 'message_update',\n 'message_end',\n 'entry_appended',\n 'tool_execution_start',\n 'tool_execution_update',\n 'tool_execution_end',\n 'agent_settled',\n ].includes(frame.type)\n )\n return;\n if (\n frame.type === 'entry_appended' &&\n frame.entry &&\n typeof frame.entry === 'object' &&\n !Array.isArray(frame.entry)\n ) {\n const entry = frame.entry;\n if (!paged(entry.id)) {\n let tail = pages.at(-1);\n if (tail && tail.entries.length >= PAGE_SIZE) {\n const identity = [...tail.context, ...tail.entries].findLast(\n (item) =>\n item && typeof item === 'object' && !Array.isArray(item) && item.customType === 'po-profile-identity',\n );\n tail = {\n ...tail,\n context: identity ? [identity] : [],\n entries: [],\n olderCursor: tail.endCursor,\n startCursor: null,\n };\n pages.push(tail);\n if (pages.length > MAX_PAGES) pages.shift();\n }\n if (tail) {\n tail.entries.push(entry);\n tail.endCursor = typeof frame.transcriptCursor === 'string' ? frame.transcriptCursor : tail.endCursor;\n tail.startCursor ??= tail.endCursor;\n }\n }\n }\n emit(frame);\n };\n const load = async (direction: Direction): Promise<void> => {\n loading = true;\n const cursor = direction === 'older' ? pages[0]?.olderCursor : pages.at(-1)?.newerCursor;\n try {\n const started = performance.now();\n const page = await service.readTranscriptPage(\n direction === 'latest' ? {} : { cursor: cursor!, direction },\n context,\n );\n record({\n name: 'web.browser.transcript_page',\n duration_ms: performance.now() - started,\n count: page.entries.length,\n });\n if (disposed) return;\n if (direction === 'latest') pages = [page];\n else if (direction === 'older') {\n pages.unshift(page);\n if (pages.length > MAX_PAGES) {\n pages.pop();\n const tail = pages.at(-1)!;\n tail.newerCursor = tail.endCursor;\n }\n } else {\n pages.push(page);\n if (pages.length > MAX_PAGES) {\n pages.shift();\n pages[0]!.olderCursor = pages[0]!.startCursor;\n }\n }\n if (direction !== 'latest') for (const event of buffered) if (event.sequence <= page.revision) apply(event);\n revision = Math.max(revision, page.revision);\n rebuild();\n setSessionStreamed(sessionId, true);\n if (hasSessionProtocol(sessionId)) void refreshSessionSelection(sessionId);\n } finally {\n loading = false;\n const events = buffered;\n buffered = [];\n if (!disposed) {\n if (overflow || reloadPending) {\n overflow = false;\n reloadPending = false;\n request('latest');\n } else for (const event of events) apply(event);\n }\n }\n };\n const request = (direction: Direction): boolean => {\n if (disposed) return false;\n if (loading) {\n if (direction === 'latest') reloadPending = true;\n return false;\n }\n if (direction === 'older' && !pages[0]?.olderCursor) return false;\n if (direction === 'newer' && !pages.at(-1)?.newerCursor) return false;\n void load(direction).catch((error: unknown) => {\n if (disposed) return;\n if (String(error).includes('STALE_TRANSCRIPT_CURSOR') && direction !== 'latest') request('latest');\n else emit({ type: 'error', message: error instanceof Error ? error.message : String(error) });\n });\n return true;\n };\n const unbind = bindHistoryReader(sessionId, request, () => pages.length > 0);\n const unbindImages = bindImageReader(sessionId, (entryId) => service.readTranscriptPage({ entryId }, context));\n return {\n initialize: () => load('latest'),\n publish(state: SessionServiceState) {\n if (disposed) return;\n const previous = latestState?.presentation?.revision;\n const replay =\n previous === undefined || (state.presentation !== undefined && state.presentation.revision < previous);\n // Completion effects follow the live stream, never the paged transcript's revision or viewport.\n if (replay)\n for (const tool of Object.values(state.live?.tools ?? {}))\n onToolFrame?.(\n sessionId,\n { type: 'tool_execution_start', toolCallId: tool.toolCallId, toolName: tool.toolName, args: tool.args },\n true,\n );\n const fastMode = state.snapshot.fastMode === true;\n if (!latestState || fastMode !== (latestState.snapshot.fastMode === true)) {\n emit({ type: 'fast_mode_changed', enabled: fastMode });\n }\n const locked = state.snapshot.locked === true;\n if (!latestState || locked !== (latestState.snapshot.locked === true)) {\n emit({ type: 'agent_lock_changed', locked });\n }\n const previousLive = latestState?.live;\n latestState = state;\n if (state.snapshot.lifecycle) applySessionLifecycle(sessionId, state.snapshot.lifecycle, previous === undefined);\n if (previous !== undefined && state.presentation && state.presentation.revision < previous) {\n revision = 0;\n request('latest');\n return;\n }\n for (const event of state.presentation?.events ?? []) {\n if (\n !replay &&\n event.sequence > previous &&\n (event.frame.type === 'tool_execution_start' || event.frame.type === 'tool_execution_end')\n )\n onToolFrame?.(sessionId, event.frame, false);\n if (loading || pages.length === 0) {\n if (event.sequence <= revision || event.sequence <= (buffered.at(-1)?.sequence ?? -1)) continue;\n buffered.push(event);\n if (buffered.length > MAX_BUFFER) {\n overflow = true;\n buffered = buffered.slice(-MAX_BUFFER);\n }\n } else apply(event);\n }\n if (!loading && pages.length > 0 && atLatest()) emitLive(state.live, previousLive, false);\n },\n dispose() {\n disposed = true;\n setSessionStreamed(sessionId, false);\n unbind();\n unbindImages();\n pages = [];\n buffered = [];\n },\n };\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"pagedTranscriptStore.cjs","names":["hasSessionProtocol","refreshSessionSelection","bindHistoryReader","bindImageReader"],"sources":["../../../src/web/stores/pagedTranscriptStore.ts"],"sourcesContent":["import type {\n ProtocolEvent,\n SessionLive,\n SessionService,\n SessionServiceState,\n TranscriptPage,\n} from '@agimon-ai/po-core/sessionProtocol';\nimport { type Context } from '@earendil-works/chord';\n\nimport type { BrowserPerformanceEvent } from '../lib/browserTelemetry';\nimport { hasSessionProtocol } from '../lib/sessionProtocolCommands';\nimport { bindImageReader } from './imageRefStore';\nimport {\n applySessionLifecycle,\n bindHistoryReader,\n resetSessionStore,\n refreshSessionSelection,\n beginSessionReplay,\n endSessionReplay,\n releaseProtocolTranscript,\n setHasNewerHistory,\n setSessionStreamed,\n} from './sessionStore';\n\nconst MAX_PAGES = 5;\nconst PAGE_SIZE = 100;\nconst MAX_BUFFER = 512;\ntype Direction = 'older' | 'newer' | 'latest';\n\n/** A bounded history window with a separate live event subscription. */\nexport function createPagedTranscript(\n sessionId: string,\n service: Pick<SessionService, 'readTranscriptPage'>,\n onFrame: (sessionId: string, frame: Record<string, unknown>, replay: boolean) => void,\n context: Context,\n record: (event: BrowserPerformanceEvent) => void = () => {},\n onToolFrame?: typeof onFrame,\n) {\n let pages: TranscriptPage[] = [];\n let revision = 0;\n let loading = false;\n let disposed = false;\n let overflow = false;\n let reloadPending = false;\n let buffered: ProtocolEvent[] = [];\n let latestState: SessionServiceState | undefined;\n const emit = (frame: Record<string, unknown>, replay = false) => onFrame(sessionId, frame, replay);\n const atLatest = () => pages.at(-1)?.newerCursor === null;\n const paged = (id: unknown) =>\n pages.some((page) =>\n page.entries.some((item) => item && typeof item === 'object' && !Array.isArray(item) && item.id === id),\n );\n // `live` holds whole values, so each change folds in as one replacing frame.\n const emitLive = (live: SessionLive | undefined, previous: SessionLive | undefined, replay: boolean) => {\n if (live?.message && live.message !== previous?.message)\n emit({ type: 'message_update', message: live.message }, replay);\n for (const tool of Object.values(live?.tools ?? {})) {\n if (replay)\n emit(\n { type: 'tool_execution_start', toolCallId: tool.toolCallId, toolName: tool.toolName, args: tool.args },\n true,\n );\n if (tool.partialResult && tool.partialResult !== previous?.tools[tool.toolCallId]?.partialResult)\n emit({ type: 'tool_execution_update', toolCallId: tool.toolCallId, partialResult: tool.partialResult }, replay);\n }\n };\n const rebuild = () => {\n const started = performance.now();\n releaseProtocolTranscript(sessionId);\n beginSessionReplay(sessionId);\n try {\n resetSessionStore(sessionId);\n for (const entry of pages[0]?.context ?? []) emit({ type: 'entry_appended', entry }, true);\n for (const page of pages) for (const entry of page.entries) emit({ type: 'entry_appended', entry }, true);\n // Current projections win over historical configuration in the transcript page.\n for (const event of latestState?.presentation?.projections ?? []) emit(event.frame, true);\n if (atLatest()) emitLive(latestState?.live, undefined, true);\n if (latestState?.snapshot.lifecycle) applySessionLifecycle(sessionId, latestState.snapshot.lifecycle);\n else if (latestState?.live?.phase === 'turn') emit({ type: 'agent_start' }, true);\n setHasNewerHistory(sessionId, !atLatest());\n } finally {\n endSessionReplay(sessionId);\n record({\n name: 'web.browser.transcript_render',\n duration_ms: performance.now() - started,\n count: pages.reduce((count, page) => count + page.entries.length, 0),\n });\n }\n };\n const apply = (event: ProtocolEvent) => {\n if (event.sequence <= revision) return;\n if (revision > 0 && event.sequence > revision + 1) {\n request('latest');\n return;\n }\n revision = event.sequence;\n const frame = event.frame;\n if (frame.type === 'navigation_end' || frame.type === 'message_end') {\n if (frame.type === 'message_end') {\n emit(frame);\n // The entry_appended sent just before it already put the committed entry on the page. Only a\n // runtime that sent none, or a page scrolled away from the latest, needs the page read again.\n if (typeof frame.entryId === 'string' && paged(frame.entryId)) return;\n }\n request('latest');\n return;\n }\n if (\n !atLatest() &&\n [\n 'message_start',\n 'message_update',\n 'message_end',\n 'entry_appended',\n 'tool_execution_start',\n 'tool_execution_update',\n 'tool_execution_end',\n 'agent_settled',\n ].includes(frame.type)\n )\n return;\n if (\n frame.type === 'entry_appended' &&\n frame.entry &&\n typeof frame.entry === 'object' &&\n !Array.isArray(frame.entry)\n ) {\n const entry = frame.entry;\n if (!paged(entry.id)) {\n let tail = pages.at(-1);\n if (tail && tail.entries.length >= PAGE_SIZE) {\n const identity = [...tail.context, ...tail.entries].findLast(\n (item) =>\n item && typeof item === 'object' && !Array.isArray(item) && item.customType === 'po-profile-identity',\n );\n tail = {\n ...tail,\n context: identity ? [identity] : [],\n entries: [],\n olderCursor: tail.endCursor,\n startCursor: null,\n };\n pages.push(tail);\n if (pages.length > MAX_PAGES) pages.shift();\n }\n if (tail) {\n tail.entries.push(entry);\n tail.endCursor = typeof frame.transcriptCursor === 'string' ? frame.transcriptCursor : tail.endCursor;\n tail.startCursor ??= tail.endCursor;\n }\n }\n }\n emit(frame);\n };\n const load = async (direction: Direction): Promise<void> => {\n loading = true;\n const cursor = direction === 'older' ? pages[0]?.olderCursor : pages.at(-1)?.newerCursor;\n try {\n const started = performance.now();\n const page = await service.readTranscriptPage(\n direction === 'latest' ? {} : { cursor: cursor!, direction },\n context,\n );\n record({\n name: 'web.browser.transcript_page',\n duration_ms: performance.now() - started,\n count: page.entries.length,\n });\n if (disposed) return;\n if (direction === 'latest') pages = [page];\n else if (direction === 'older') {\n pages.unshift(page);\n if (pages.length > MAX_PAGES) {\n pages.pop();\n const tail = pages.at(-1)!;\n tail.newerCursor = tail.endCursor;\n }\n } else {\n pages.push(page);\n if (pages.length > MAX_PAGES) {\n pages.shift();\n pages[0]!.olderCursor = pages[0]!.startCursor;\n }\n }\n if (direction !== 'latest') for (const event of buffered) if (event.sequence <= page.revision) apply(event);\n revision = Math.max(revision, page.revision);\n rebuild();\n setSessionStreamed(sessionId, true);\n if (hasSessionProtocol(sessionId)) void refreshSessionSelection(sessionId);\n } finally {\n loading = false;\n const events = buffered;\n buffered = [];\n if (!disposed) {\n if (overflow || reloadPending) {\n overflow = false;\n reloadPending = false;\n request('latest');\n } else for (const event of events) apply(event);\n }\n }\n };\n const request = (direction: Direction): boolean => {\n if (disposed) return false;\n if (loading) {\n if (direction === 'latest') reloadPending = true;\n return false;\n }\n if (direction === 'older' && !pages[0]?.olderCursor) return false;\n if (direction === 'newer' && !pages.at(-1)?.newerCursor) return false;\n void load(direction).catch((error: unknown) => {\n if (disposed) return;\n if (String(error).includes('STALE_TRANSCRIPT_CURSOR') && direction !== 'latest') request('latest');\n else emit({ type: 'error', message: error instanceof Error ? error.message : String(error) });\n });\n return true;\n };\n const unbind = bindHistoryReader(sessionId, request, () => pages.length > 0);\n const unbindImages = bindImageReader(sessionId, (entryId) => service.readTranscriptPage({ entryId }, context));\n return {\n initialize: () => load('latest'),\n publish(state: SessionServiceState) {\n if (disposed) return;\n const previous = latestState?.presentation?.revision;\n const replay =\n previous === undefined || (state.presentation !== undefined && state.presentation.revision < previous);\n // Completion effects follow the live stream, never the paged transcript's revision or viewport.\n if (replay)\n for (const tool of Object.values(state.live?.tools ?? {}))\n onToolFrame?.(\n sessionId,\n { type: 'tool_execution_start', toolCallId: tool.toolCallId, toolName: tool.toolName, args: tool.args },\n true,\n );\n const fastMode = state.snapshot.fastMode === true;\n if (!latestState || fastMode !== (latestState.snapshot.fastMode === true)) {\n emit({ type: 'fast_mode_changed', enabled: fastMode });\n }\n const locked = state.snapshot.locked === true;\n if (!latestState || locked !== (latestState.snapshot.locked === true)) {\n emit({ type: 'agent_lock_changed', locked });\n }\n const previousLive = latestState?.live;\n latestState = state;\n if (state.snapshot.lifecycle) applySessionLifecycle(sessionId, state.snapshot.lifecycle, previous === undefined);\n if (previous !== undefined && state.presentation && state.presentation.revision < previous) {\n revision = 0;\n request('latest');\n return;\n }\n // History can finish before the first state. Its revision already covers pending UI events.\n if (previous === undefined && !loading && pages.length > 0)\n for (const event of state.presentation?.projections ?? []) emit(event.frame, true);\n for (const event of state.presentation?.events ?? []) {\n if (\n !replay &&\n event.sequence > previous &&\n (event.frame.type === 'tool_execution_start' || event.frame.type === 'tool_execution_end')\n )\n onToolFrame?.(sessionId, event.frame, false);\n if (loading || pages.length === 0) {\n if (event.sequence <= revision || event.sequence <= (buffered.at(-1)?.sequence ?? -1)) continue;\n buffered.push(event);\n if (buffered.length > MAX_BUFFER) {\n overflow = true;\n buffered = buffered.slice(-MAX_BUFFER);\n }\n } else apply(event);\n }\n if (!loading && pages.length > 0 && atLatest()) emitLive(state.live, previousLive, false);\n },\n dispose() {\n disposed = true;\n setSessionStreamed(sessionId, false);\n unbind();\n unbindImages();\n pages = [];\n buffered = [];\n },\n };\n}\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"pagedTranscriptStore.d.mts","names":[],"sources":["../../../src/web/stores/pagedTranscriptStore.ts"],"mappings":";;;;;wBA8BgB,sBACd,mBACA,SAAS,KAAK,uCACd,UAAU,mBAAmB,OAAO,yBAAyB,0BAC7D,SAAS,SACT,UAAS,OAAO,kCAChB,qBAAqB;EAwLnB,kBAAU;EACV,QAAO,OAAQ;EA+Cf"}
1
+ {"version":3,"file":"pagedTranscriptStore.d.mts","names":[],"sources":["../../../src/web/stores/pagedTranscriptStore.ts"],"mappings":";;;;;wBA8BgB,sBACd,mBACA,SAAS,KAAK,uCACd,UAAU,mBAAmB,OAAO,yBAAyB,0BAC7D,SAAS,SACT,UAAS,OAAO,kCAChB,qBAAqB;EAwLnB,kBAAU;EACV,QAAO,OAAQ;EAkDf"}
@@ -216,6 +216,7 @@ function createPagedTranscript(sessionId, service, onFrame, context, record = ()
216
216
  request("latest");
217
217
  return;
218
218
  }
219
+ if (previous === void 0 && !loading && pages.length > 0) for (const event of state.presentation?.projections ?? []) emit(event.frame, true);
219
220
  for (const event of state.presentation?.events ?? []) {
220
221
  if (!replay && event.sequence > previous && (event.frame.type === "tool_execution_start" || event.frame.type === "tool_execution_end")) onToolFrame?.(sessionId, event.frame, false);
221
222
  if (loading || pages.length === 0) {
@@ -1 +1 @@
1
- {"version":3,"file":"pagedTranscriptStore.mjs","names":[],"sources":["../../../src/web/stores/pagedTranscriptStore.ts"],"sourcesContent":["import type {\n ProtocolEvent,\n SessionLive,\n SessionService,\n SessionServiceState,\n TranscriptPage,\n} from '@agimon-ai/po-core/sessionProtocol';\nimport { type Context } from '@earendil-works/chord';\n\nimport type { BrowserPerformanceEvent } from '../lib/browserTelemetry';\nimport { hasSessionProtocol } from '../lib/sessionProtocolCommands';\nimport { bindImageReader } from './imageRefStore';\nimport {\n applySessionLifecycle,\n bindHistoryReader,\n resetSessionStore,\n refreshSessionSelection,\n beginSessionReplay,\n endSessionReplay,\n releaseProtocolTranscript,\n setHasNewerHistory,\n setSessionStreamed,\n} from './sessionStore';\n\nconst MAX_PAGES = 5;\nconst PAGE_SIZE = 100;\nconst MAX_BUFFER = 512;\ntype Direction = 'older' | 'newer' | 'latest';\n\n/** A bounded history window with a separate live event subscription. */\nexport function createPagedTranscript(\n sessionId: string,\n service: Pick<SessionService, 'readTranscriptPage'>,\n onFrame: (sessionId: string, frame: Record<string, unknown>, replay: boolean) => void,\n context: Context,\n record: (event: BrowserPerformanceEvent) => void = () => {},\n onToolFrame?: typeof onFrame,\n) {\n let pages: TranscriptPage[] = [];\n let revision = 0;\n let loading = false;\n let disposed = false;\n let overflow = false;\n let reloadPending = false;\n let buffered: ProtocolEvent[] = [];\n let latestState: SessionServiceState | undefined;\n const emit = (frame: Record<string, unknown>, replay = false) => onFrame(sessionId, frame, replay);\n const atLatest = () => pages.at(-1)?.newerCursor === null;\n const paged = (id: unknown) =>\n pages.some((page) =>\n page.entries.some((item) => item && typeof item === 'object' && !Array.isArray(item) && item.id === id),\n );\n // `live` holds whole values, so each change folds in as one replacing frame.\n const emitLive = (live: SessionLive | undefined, previous: SessionLive | undefined, replay: boolean) => {\n if (live?.message && live.message !== previous?.message)\n emit({ type: 'message_update', message: live.message }, replay);\n for (const tool of Object.values(live?.tools ?? {})) {\n if (replay)\n emit(\n { type: 'tool_execution_start', toolCallId: tool.toolCallId, toolName: tool.toolName, args: tool.args },\n true,\n );\n if (tool.partialResult && tool.partialResult !== previous?.tools[tool.toolCallId]?.partialResult)\n emit({ type: 'tool_execution_update', toolCallId: tool.toolCallId, partialResult: tool.partialResult }, replay);\n }\n };\n const rebuild = () => {\n const started = performance.now();\n releaseProtocolTranscript(sessionId);\n beginSessionReplay(sessionId);\n try {\n resetSessionStore(sessionId);\n for (const entry of pages[0]?.context ?? []) emit({ type: 'entry_appended', entry }, true);\n for (const page of pages) for (const entry of page.entries) emit({ type: 'entry_appended', entry }, true);\n // Current projections win over historical configuration in the transcript page.\n for (const event of latestState?.presentation?.projections ?? []) emit(event.frame, true);\n if (atLatest()) emitLive(latestState?.live, undefined, true);\n if (latestState?.snapshot.lifecycle) applySessionLifecycle(sessionId, latestState.snapshot.lifecycle);\n else if (latestState?.live?.phase === 'turn') emit({ type: 'agent_start' }, true);\n setHasNewerHistory(sessionId, !atLatest());\n } finally {\n endSessionReplay(sessionId);\n record({\n name: 'web.browser.transcript_render',\n duration_ms: performance.now() - started,\n count: pages.reduce((count, page) => count + page.entries.length, 0),\n });\n }\n };\n const apply = (event: ProtocolEvent) => {\n if (event.sequence <= revision) return;\n if (revision > 0 && event.sequence > revision + 1) {\n request('latest');\n return;\n }\n revision = event.sequence;\n const frame = event.frame;\n if (frame.type === 'navigation_end' || frame.type === 'message_end') {\n if (frame.type === 'message_end') {\n emit(frame);\n // The entry_appended sent just before it already put the committed entry on the page. Only a\n // runtime that sent none, or a page scrolled away from the latest, needs the page read again.\n if (typeof frame.entryId === 'string' && paged(frame.entryId)) return;\n }\n request('latest');\n return;\n }\n if (\n !atLatest() &&\n [\n 'message_start',\n 'message_update',\n 'message_end',\n 'entry_appended',\n 'tool_execution_start',\n 'tool_execution_update',\n 'tool_execution_end',\n 'agent_settled',\n ].includes(frame.type)\n )\n return;\n if (\n frame.type === 'entry_appended' &&\n frame.entry &&\n typeof frame.entry === 'object' &&\n !Array.isArray(frame.entry)\n ) {\n const entry = frame.entry;\n if (!paged(entry.id)) {\n let tail = pages.at(-1);\n if (tail && tail.entries.length >= PAGE_SIZE) {\n const identity = [...tail.context, ...tail.entries].findLast(\n (item) =>\n item && typeof item === 'object' && !Array.isArray(item) && item.customType === 'po-profile-identity',\n );\n tail = {\n ...tail,\n context: identity ? [identity] : [],\n entries: [],\n olderCursor: tail.endCursor,\n startCursor: null,\n };\n pages.push(tail);\n if (pages.length > MAX_PAGES) pages.shift();\n }\n if (tail) {\n tail.entries.push(entry);\n tail.endCursor = typeof frame.transcriptCursor === 'string' ? frame.transcriptCursor : tail.endCursor;\n tail.startCursor ??= tail.endCursor;\n }\n }\n }\n emit(frame);\n };\n const load = async (direction: Direction): Promise<void> => {\n loading = true;\n const cursor = direction === 'older' ? pages[0]?.olderCursor : pages.at(-1)?.newerCursor;\n try {\n const started = performance.now();\n const page = await service.readTranscriptPage(\n direction === 'latest' ? {} : { cursor: cursor!, direction },\n context,\n );\n record({\n name: 'web.browser.transcript_page',\n duration_ms: performance.now() - started,\n count: page.entries.length,\n });\n if (disposed) return;\n if (direction === 'latest') pages = [page];\n else if (direction === 'older') {\n pages.unshift(page);\n if (pages.length > MAX_PAGES) {\n pages.pop();\n const tail = pages.at(-1)!;\n tail.newerCursor = tail.endCursor;\n }\n } else {\n pages.push(page);\n if (pages.length > MAX_PAGES) {\n pages.shift();\n pages[0]!.olderCursor = pages[0]!.startCursor;\n }\n }\n if (direction !== 'latest') for (const event of buffered) if (event.sequence <= page.revision) apply(event);\n revision = Math.max(revision, page.revision);\n rebuild();\n setSessionStreamed(sessionId, true);\n if (hasSessionProtocol(sessionId)) void refreshSessionSelection(sessionId);\n } finally {\n loading = false;\n const events = buffered;\n buffered = [];\n if (!disposed) {\n if (overflow || reloadPending) {\n overflow = false;\n reloadPending = false;\n request('latest');\n } else for (const event of events) apply(event);\n }\n }\n };\n const request = (direction: Direction): boolean => {\n if (disposed) return false;\n if (loading) {\n if (direction === 'latest') reloadPending = true;\n return false;\n }\n if (direction === 'older' && !pages[0]?.olderCursor) return false;\n if (direction === 'newer' && !pages.at(-1)?.newerCursor) return false;\n void load(direction).catch((error: unknown) => {\n if (disposed) return;\n if (String(error).includes('STALE_TRANSCRIPT_CURSOR') && direction !== 'latest') request('latest');\n else emit({ type: 'error', message: error instanceof Error ? error.message : String(error) });\n });\n return true;\n };\n const unbind = bindHistoryReader(sessionId, request, () => pages.length > 0);\n const unbindImages = bindImageReader(sessionId, (entryId) => service.readTranscriptPage({ entryId }, context));\n return {\n initialize: () => load('latest'),\n publish(state: SessionServiceState) {\n if (disposed) return;\n const previous = latestState?.presentation?.revision;\n const replay =\n previous === undefined || (state.presentation !== undefined && state.presentation.revision < previous);\n // Completion effects follow the live stream, never the paged transcript's revision or viewport.\n if (replay)\n for (const tool of Object.values(state.live?.tools ?? {}))\n onToolFrame?.(\n sessionId,\n { type: 'tool_execution_start', toolCallId: tool.toolCallId, toolName: tool.toolName, args: tool.args },\n true,\n );\n const fastMode = state.snapshot.fastMode === true;\n if (!latestState || fastMode !== (latestState.snapshot.fastMode === true)) {\n emit({ type: 'fast_mode_changed', enabled: fastMode });\n }\n const locked = state.snapshot.locked === true;\n if (!latestState || locked !== (latestState.snapshot.locked === true)) {\n emit({ type: 'agent_lock_changed', locked });\n }\n const previousLive = latestState?.live;\n latestState = state;\n if (state.snapshot.lifecycle) applySessionLifecycle(sessionId, state.snapshot.lifecycle, previous === undefined);\n if (previous !== undefined && state.presentation && state.presentation.revision < previous) {\n revision = 0;\n request('latest');\n return;\n }\n for (const event of state.presentation?.events ?? []) {\n if (\n !replay &&\n event.sequence > previous &&\n (event.frame.type === 'tool_execution_start' || event.frame.type === 'tool_execution_end')\n )\n onToolFrame?.(sessionId, event.frame, false);\n if (loading || pages.length === 0) {\n if (event.sequence <= revision || event.sequence <= (buffered.at(-1)?.sequence ?? -1)) continue;\n buffered.push(event);\n if (buffered.length > MAX_BUFFER) {\n overflow = true;\n buffered = buffered.slice(-MAX_BUFFER);\n }\n } else apply(event);\n }\n if (!loading && pages.length > 0 && atLatest()) emitLive(state.live, previousLive, false);\n },\n dispose() {\n disposed = true;\n setSessionStreamed(sessionId, false);\n unbind();\n unbindImages();\n pages = [];\n buffered = [];\n },\n };\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"pagedTranscriptStore.mjs","names":[],"sources":["../../../src/web/stores/pagedTranscriptStore.ts"],"sourcesContent":["import type {\n ProtocolEvent,\n SessionLive,\n SessionService,\n SessionServiceState,\n TranscriptPage,\n} from '@agimon-ai/po-core/sessionProtocol';\nimport { type Context } from '@earendil-works/chord';\n\nimport type { BrowserPerformanceEvent } from '../lib/browserTelemetry';\nimport { hasSessionProtocol } from '../lib/sessionProtocolCommands';\nimport { bindImageReader } from './imageRefStore';\nimport {\n applySessionLifecycle,\n bindHistoryReader,\n resetSessionStore,\n refreshSessionSelection,\n beginSessionReplay,\n endSessionReplay,\n releaseProtocolTranscript,\n setHasNewerHistory,\n setSessionStreamed,\n} from './sessionStore';\n\nconst MAX_PAGES = 5;\nconst PAGE_SIZE = 100;\nconst MAX_BUFFER = 512;\ntype Direction = 'older' | 'newer' | 'latest';\n\n/** A bounded history window with a separate live event subscription. */\nexport function createPagedTranscript(\n sessionId: string,\n service: Pick<SessionService, 'readTranscriptPage'>,\n onFrame: (sessionId: string, frame: Record<string, unknown>, replay: boolean) => void,\n context: Context,\n record: (event: BrowserPerformanceEvent) => void = () => {},\n onToolFrame?: typeof onFrame,\n) {\n let pages: TranscriptPage[] = [];\n let revision = 0;\n let loading = false;\n let disposed = false;\n let overflow = false;\n let reloadPending = false;\n let buffered: ProtocolEvent[] = [];\n let latestState: SessionServiceState | undefined;\n const emit = (frame: Record<string, unknown>, replay = false) => onFrame(sessionId, frame, replay);\n const atLatest = () => pages.at(-1)?.newerCursor === null;\n const paged = (id: unknown) =>\n pages.some((page) =>\n page.entries.some((item) => item && typeof item === 'object' && !Array.isArray(item) && item.id === id),\n );\n // `live` holds whole values, so each change folds in as one replacing frame.\n const emitLive = (live: SessionLive | undefined, previous: SessionLive | undefined, replay: boolean) => {\n if (live?.message && live.message !== previous?.message)\n emit({ type: 'message_update', message: live.message }, replay);\n for (const tool of Object.values(live?.tools ?? {})) {\n if (replay)\n emit(\n { type: 'tool_execution_start', toolCallId: tool.toolCallId, toolName: tool.toolName, args: tool.args },\n true,\n );\n if (tool.partialResult && tool.partialResult !== previous?.tools[tool.toolCallId]?.partialResult)\n emit({ type: 'tool_execution_update', toolCallId: tool.toolCallId, partialResult: tool.partialResult }, replay);\n }\n };\n const rebuild = () => {\n const started = performance.now();\n releaseProtocolTranscript(sessionId);\n beginSessionReplay(sessionId);\n try {\n resetSessionStore(sessionId);\n for (const entry of pages[0]?.context ?? []) emit({ type: 'entry_appended', entry }, true);\n for (const page of pages) for (const entry of page.entries) emit({ type: 'entry_appended', entry }, true);\n // Current projections win over historical configuration in the transcript page.\n for (const event of latestState?.presentation?.projections ?? []) emit(event.frame, true);\n if (atLatest()) emitLive(latestState?.live, undefined, true);\n if (latestState?.snapshot.lifecycle) applySessionLifecycle(sessionId, latestState.snapshot.lifecycle);\n else if (latestState?.live?.phase === 'turn') emit({ type: 'agent_start' }, true);\n setHasNewerHistory(sessionId, !atLatest());\n } finally {\n endSessionReplay(sessionId);\n record({\n name: 'web.browser.transcript_render',\n duration_ms: performance.now() - started,\n count: pages.reduce((count, page) => count + page.entries.length, 0),\n });\n }\n };\n const apply = (event: ProtocolEvent) => {\n if (event.sequence <= revision) return;\n if (revision > 0 && event.sequence > revision + 1) {\n request('latest');\n return;\n }\n revision = event.sequence;\n const frame = event.frame;\n if (frame.type === 'navigation_end' || frame.type === 'message_end') {\n if (frame.type === 'message_end') {\n emit(frame);\n // The entry_appended sent just before it already put the committed entry on the page. Only a\n // runtime that sent none, or a page scrolled away from the latest, needs the page read again.\n if (typeof frame.entryId === 'string' && paged(frame.entryId)) return;\n }\n request('latest');\n return;\n }\n if (\n !atLatest() &&\n [\n 'message_start',\n 'message_update',\n 'message_end',\n 'entry_appended',\n 'tool_execution_start',\n 'tool_execution_update',\n 'tool_execution_end',\n 'agent_settled',\n ].includes(frame.type)\n )\n return;\n if (\n frame.type === 'entry_appended' &&\n frame.entry &&\n typeof frame.entry === 'object' &&\n !Array.isArray(frame.entry)\n ) {\n const entry = frame.entry;\n if (!paged(entry.id)) {\n let tail = pages.at(-1);\n if (tail && tail.entries.length >= PAGE_SIZE) {\n const identity = [...tail.context, ...tail.entries].findLast(\n (item) =>\n item && typeof item === 'object' && !Array.isArray(item) && item.customType === 'po-profile-identity',\n );\n tail = {\n ...tail,\n context: identity ? [identity] : [],\n entries: [],\n olderCursor: tail.endCursor,\n startCursor: null,\n };\n pages.push(tail);\n if (pages.length > MAX_PAGES) pages.shift();\n }\n if (tail) {\n tail.entries.push(entry);\n tail.endCursor = typeof frame.transcriptCursor === 'string' ? frame.transcriptCursor : tail.endCursor;\n tail.startCursor ??= tail.endCursor;\n }\n }\n }\n emit(frame);\n };\n const load = async (direction: Direction): Promise<void> => {\n loading = true;\n const cursor = direction === 'older' ? pages[0]?.olderCursor : pages.at(-1)?.newerCursor;\n try {\n const started = performance.now();\n const page = await service.readTranscriptPage(\n direction === 'latest' ? {} : { cursor: cursor!, direction },\n context,\n );\n record({\n name: 'web.browser.transcript_page',\n duration_ms: performance.now() - started,\n count: page.entries.length,\n });\n if (disposed) return;\n if (direction === 'latest') pages = [page];\n else if (direction === 'older') {\n pages.unshift(page);\n if (pages.length > MAX_PAGES) {\n pages.pop();\n const tail = pages.at(-1)!;\n tail.newerCursor = tail.endCursor;\n }\n } else {\n pages.push(page);\n if (pages.length > MAX_PAGES) {\n pages.shift();\n pages[0]!.olderCursor = pages[0]!.startCursor;\n }\n }\n if (direction !== 'latest') for (const event of buffered) if (event.sequence <= page.revision) apply(event);\n revision = Math.max(revision, page.revision);\n rebuild();\n setSessionStreamed(sessionId, true);\n if (hasSessionProtocol(sessionId)) void refreshSessionSelection(sessionId);\n } finally {\n loading = false;\n const events = buffered;\n buffered = [];\n if (!disposed) {\n if (overflow || reloadPending) {\n overflow = false;\n reloadPending = false;\n request('latest');\n } else for (const event of events) apply(event);\n }\n }\n };\n const request = (direction: Direction): boolean => {\n if (disposed) return false;\n if (loading) {\n if (direction === 'latest') reloadPending = true;\n return false;\n }\n if (direction === 'older' && !pages[0]?.olderCursor) return false;\n if (direction === 'newer' && !pages.at(-1)?.newerCursor) return false;\n void load(direction).catch((error: unknown) => {\n if (disposed) return;\n if (String(error).includes('STALE_TRANSCRIPT_CURSOR') && direction !== 'latest') request('latest');\n else emit({ type: 'error', message: error instanceof Error ? error.message : String(error) });\n });\n return true;\n };\n const unbind = bindHistoryReader(sessionId, request, () => pages.length > 0);\n const unbindImages = bindImageReader(sessionId, (entryId) => service.readTranscriptPage({ entryId }, context));\n return {\n initialize: () => load('latest'),\n publish(state: SessionServiceState) {\n if (disposed) return;\n const previous = latestState?.presentation?.revision;\n const replay =\n previous === undefined || (state.presentation !== undefined && state.presentation.revision < previous);\n // Completion effects follow the live stream, never the paged transcript's revision or viewport.\n if (replay)\n for (const tool of Object.values(state.live?.tools ?? {}))\n onToolFrame?.(\n sessionId,\n { type: 'tool_execution_start', toolCallId: tool.toolCallId, toolName: tool.toolName, args: tool.args },\n true,\n );\n const fastMode = state.snapshot.fastMode === true;\n if (!latestState || fastMode !== (latestState.snapshot.fastMode === true)) {\n emit({ type: 'fast_mode_changed', enabled: fastMode });\n }\n const locked = state.snapshot.locked === true;\n if (!latestState || locked !== (latestState.snapshot.locked === true)) {\n emit({ type: 'agent_lock_changed', locked });\n }\n const previousLive = latestState?.live;\n latestState = state;\n if (state.snapshot.lifecycle) applySessionLifecycle(sessionId, state.snapshot.lifecycle, previous === undefined);\n if (previous !== undefined && state.presentation && state.presentation.revision < previous) {\n revision = 0;\n request('latest');\n return;\n }\n // History can finish before the first state. Its revision already covers pending UI events.\n if (previous === undefined && !loading && pages.length > 0)\n for (const event of state.presentation?.projections ?? []) emit(event.frame, true);\n for (const event of state.presentation?.events ?? []) {\n if (\n !replay &&\n event.sequence > previous &&\n (event.frame.type === 'tool_execution_start' || event.frame.type === 'tool_execution_end')\n )\n onToolFrame?.(sessionId, event.frame, false);\n if (loading || pages.length === 0) {\n if (event.sequence <= revision || event.sequence <= (buffered.at(-1)?.sequence ?? -1)) continue;\n buffered.push(event);\n if (buffered.length > MAX_BUFFER) {\n overflow = true;\n buffered = buffered.slice(-MAX_BUFFER);\n }\n } else apply(event);\n }\n if (!loading && pages.length > 0 && atLatest()) emitLive(state.live, previousLive, false);\n },\n dispose() {\n disposed = true;\n setSessionStreamed(sessionId, false);\n unbind();\n unbindImages();\n pages = [];\n buffered = [];\n },\n };\n}\n"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agimon-ai/po-web-dashboard",
3
- "version": "0.0.0-alpha.97",
3
+ "version": "0.0.0-alpha.99",
4
4
  "description": "Shared browser state, actions and optional views for Po dashboard templates.",
5
5
  "keywords": [
6
6
  "ai",
@@ -61,9 +61,9 @@
61
61
  "access": "public"
62
62
  },
63
63
  "dependencies": {
64
- "@agimon-ai/po-core": "0.0.0-alpha.97",
65
- "@agimon-ai/po-web-components": "0.0.0-alpha.97",
66
- "@agimon-ai/po-web-security": "0.0.0-alpha.97",
64
+ "@agimon-ai/po-core": "0.0.0-alpha.99",
65
+ "@agimon-ai/po-web-components": "0.0.0-alpha.99",
66
+ "@agimon-ai/po-web-security": "0.0.0-alpha.99",
67
67
  "@earendil-works/chord": "1.4.0",
68
68
  "@simplewebauthn/browser": "^14.0.0",
69
69
  "@tanstack/react-router": "1.170.45",
@@ -73,7 +73,7 @@
73
73
  "qrcode-generator": "^2.0.4"
74
74
  },
75
75
  "devDependencies": {
76
- "@agimon-ai/vibe-lint-plugin-po-web": "0.0.0-alpha.97",
76
+ "@agimon-ai/vibe-lint-plugin-po-web": "0.0.0-alpha.99",
77
77
  "@types/node": "26.6.5",
78
78
  "@types/react": "19.3.0",
79
79
  "@types/react-dom": "19.3.0",