@stigmer/react 3.12.3 → 3.12.5
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/agent/steps/IdentityStep.d.ts.map +1 -1
- package/agent/steps/IdentityStep.js +2 -1
- package/agent/steps/IdentityStep.js.map +1 -1
- package/agent-instance/AgentInstanceDetailPanel.d.ts.map +1 -1
- package/agent-instance/AgentInstanceDetailPanel.js +2 -1
- package/agent-instance/AgentInstanceDetailPanel.js.map +1 -1
- package/api-key/CreateApiKeyForm.d.ts.map +1 -1
- package/api-key/CreateApiKeyForm.js +2 -1
- package/api-key/CreateApiKeyForm.js.map +1 -1
- package/attachment/AttachmentChipList.js +16 -6
- package/attachment/AttachmentChipList.js.map +1 -1
- package/attachment/index.d.ts +1 -1
- package/attachment/index.d.ts.map +1 -1
- package/attachment/index.js.map +1 -1
- package/attachment/useAttachments.d.ts +51 -8
- package/attachment/useAttachments.d.ts.map +1 -1
- package/attachment/useAttachments.js +74 -3
- package/attachment/useAttachments.js.map +1 -1
- package/channel/ChannelConversationsDialog.d.ts.map +1 -1
- package/channel/ChannelConversationsDialog.js +2 -1
- package/channel/ChannelConversationsDialog.js.map +1 -1
- package/channel/ChannelTemplatesDialog.d.ts.map +1 -1
- package/channel/ChannelTemplatesDialog.js +2 -1
- package/channel/ChannelTemplatesDialog.js.map +1 -1
- package/channel/ConnectSlackDialog.d.ts.map +1 -1
- package/channel/ConnectSlackDialog.js +2 -1
- package/channel/ConnectSlackDialog.js.map +1 -1
- package/channel/connect/ServingAppSection.d.ts.map +1 -1
- package/channel/connect/ServingAppSection.js +2 -1
- package/channel/connect/ServingAppSection.js.map +1 -1
- package/channel-app/CreateChannelAppForm.d.ts.map +1 -1
- package/channel-app/CreateChannelAppForm.js +2 -1
- package/channel-app/CreateChannelAppForm.js.map +1 -1
- package/composer/SessionComposer.d.ts.map +1 -1
- package/composer/SessionComposer.js +17 -10
- package/composer/SessionComposer.js.map +1 -1
- package/conversation/ConversationComposer.d.ts +19 -3
- package/conversation/ConversationComposer.d.ts.map +1 -1
- package/conversation/ConversationComposer.js +4 -4
- package/conversation/ConversationComposer.js.map +1 -1
- package/conversation/ConversationListPane.d.ts.map +1 -1
- package/conversation/ConversationListPane.js +2 -1
- package/conversation/ConversationListPane.js.map +1 -1
- package/conversation/ConversationTemplatePickerDialog.d.ts +63 -0
- package/conversation/ConversationTemplatePickerDialog.d.ts.map +1 -0
- package/conversation/ConversationTemplatePickerDialog.js +151 -0
- package/conversation/ConversationTemplatePickerDialog.js.map +1 -0
- package/conversation/ConversationTimelineView.d.ts.map +1 -1
- package/conversation/ConversationTimelineView.js +2 -1
- package/conversation/ConversationTimelineView.js.map +1 -1
- package/conversation/ConversationsWorkbench.d.ts.map +1 -1
- package/conversation/ConversationsWorkbench.js +16 -5
- package/conversation/ConversationsWorkbench.js.map +1 -1
- package/conversation/index.d.ts +3 -1
- package/conversation/index.d.ts.map +1 -1
- package/conversation/index.js +1 -0
- package/conversation/index.js.map +1 -1
- package/conversation/useConversationParticipation.d.ts +41 -4
- package/conversation/useConversationParticipation.d.ts.map +1 -1
- package/conversation/useConversationParticipation.js +13 -2
- package/conversation/useConversationParticipation.js.map +1 -1
- package/cursor-accounts/CursorAccountsConsole.d.ts.map +1 -1
- package/cursor-accounts/CursorAccountsConsole.js +2 -1
- package/cursor-accounts/CursorAccountsConsole.js.map +1 -1
- package/cursor-accounts/MemberKeysPanel.d.ts.map +1 -1
- package/cursor-accounts/MemberKeysPanel.js +2 -1
- package/cursor-accounts/MemberKeysPanel.js.map +1 -1
- package/dashboard/DashboardFailedRuns.d.ts.map +1 -1
- package/dashboard/DashboardFailedRuns.js +2 -1
- package/dashboard/DashboardFailedRuns.js.map +1 -1
- package/dependency-graph/DependencyGraph.d.ts.map +1 -1
- package/dependency-graph/DependencyGraph.js +2 -1
- package/dependency-graph/DependencyGraph.js.map +1 -1
- package/dependency-graph/DependencyTreeNode.d.ts.map +1 -1
- package/dependency-graph/DependencyTreeNode.js +2 -1
- package/dependency-graph/DependencyTreeNode.js.map +1 -1
- package/environment/EnvironmentPicker.d.ts.map +1 -1
- package/environment/EnvironmentPicker.js +2 -1
- package/environment/EnvironmentPicker.js.map +1 -1
- package/error/SecretFlowErrorGuide.d.ts.map +1 -1
- package/error/SecretFlowErrorGuide.js +2 -1
- package/error/SecretFlowErrorGuide.js.map +1 -1
- package/execution/ArtifactContentBody.d.ts.map +1 -1
- package/execution/ArtifactContentBody.js +2 -1
- package/execution/ArtifactContentBody.js.map +1 -1
- package/execution/ArtifactsWidget.d.ts.map +1 -1
- package/execution/ArtifactsWidget.js +2 -1
- package/execution/ArtifactsWidget.js.map +1 -1
- package/execution/FileChangeProgressBar.d.ts.map +1 -1
- package/execution/FileChangeProgressBar.js +2 -1
- package/execution/FileChangeProgressBar.js.map +1 -1
- package/execution/TodoList.d.ts.map +1 -1
- package/execution/TodoList.js +2 -1
- package/execution/TodoList.js.map +1 -1
- package/execution/WriteBacksWidget.d.ts.map +1 -1
- package/execution/WriteBacksWidget.js +2 -1
- package/execution/WriteBacksWidget.js.map +1 -1
- package/execution/tool-categories.d.ts +5 -22
- package/execution/tool-categories.d.ts.map +1 -1
- package/execution/tool-categories.js +8 -38
- package/execution/tool-categories.js.map +1 -1
- package/iam-policy/PeopleWithAccess.d.ts.map +1 -1
- package/iam-policy/PeopleWithAccess.js +2 -1
- package/iam-policy/PeopleWithAccess.js.map +1 -1
- package/iam-policy/PrincipalPicker.d.ts.map +1 -1
- package/iam-policy/PrincipalPicker.js +2 -1
- package/iam-policy/PrincipalPicker.js.map +1 -1
- package/iam-policy/RoleSelector.d.ts.map +1 -1
- package/iam-policy/RoleSelector.js +2 -1
- package/iam-policy/RoleSelector.js.map +1 -1
- package/identity-account/AccountPreferencesPanel.d.ts +35 -0
- package/identity-account/AccountPreferencesPanel.d.ts.map +1 -0
- package/identity-account/AccountPreferencesPanel.js +187 -0
- package/identity-account/AccountPreferencesPanel.js.map +1 -0
- package/identity-account/index.d.ts +8 -0
- package/identity-account/index.d.ts.map +1 -1
- package/identity-account/index.js +4 -0
- package/identity-account/index.js.map +1 -1
- package/identity-account/useAccountExecutionDefaults.d.ts +36 -0
- package/identity-account/useAccountExecutionDefaults.d.ts.map +1 -0
- package/identity-account/useAccountExecutionDefaults.js +46 -0
- package/identity-account/useAccountExecutionDefaults.js.map +1 -0
- package/identity-account/useMyIdentityAccount.d.ts +55 -0
- package/identity-account/useMyIdentityAccount.d.ts.map +1 -0
- package/identity-account/useMyIdentityAccount.js +37 -0
- package/identity-account/useMyIdentityAccount.js.map +1 -0
- package/identity-account/useUpdateIdentityAccount.d.ts +42 -0
- package/identity-account/useUpdateIdentityAccount.d.ts.map +1 -0
- package/identity-account/useUpdateIdentityAccount.js +53 -0
- package/identity-account/useUpdateIdentityAccount.js.map +1 -0
- package/identity-provider/CreateIdentityProviderForm.d.ts.map +1 -1
- package/identity-provider/CreateIdentityProviderForm.js +2 -1
- package/identity-provider/CreateIdentityProviderForm.js.map +1 -1
- package/identity-provider/IdentityProviderDetailPanel.d.ts.map +1 -1
- package/identity-provider/IdentityProviderDetailPanel.js +2 -1
- package/identity-provider/IdentityProviderDetailPanel.js.map +1 -1
- package/identity-provider/IdentityProviderWizard.d.ts.map +1 -1
- package/identity-provider/IdentityProviderWizard.js +2 -1
- package/identity-provider/IdentityProviderWizard.js.map +1 -1
- package/index.d.ts +14 -10
- package/index.d.ts.map +1 -1
- package/index.js +11 -5
- package/index.js.map +1 -1
- package/internal/StandingContextField.d.ts +37 -0
- package/internal/StandingContextField.d.ts.map +1 -0
- package/internal/StandingContextField.js +24 -0
- package/internal/StandingContextField.js.map +1 -0
- package/internal/element-resets.d.ts +17 -0
- package/internal/element-resets.d.ts.map +1 -0
- package/internal/element-resets.js +32 -0
- package/internal/element-resets.js.map +1 -0
- package/internal/file-tree/FileTreeNode.d.ts.map +1 -1
- package/internal/file-tree/FileTreeNode.js +2 -1
- package/internal/file-tree/FileTreeNode.js.map +1 -1
- package/internal/markdown-components.d.ts +7 -0
- package/internal/markdown-components.d.ts.map +1 -1
- package/internal/markdown-components.js +15 -5
- package/internal/markdown-components.js.map +1 -1
- package/invitation/InvitationManager.d.ts.map +1 -1
- package/invitation/InvitationManager.js +2 -1
- package/invitation/InvitationManager.js.map +1 -1
- package/library/InstanceVisibilitySelector.d.ts.map +1 -1
- package/library/InstanceVisibilitySelector.js +9 -2
- package/library/InstanceVisibilitySelector.js.map +1 -1
- package/library/ResourceVisibilityControl.d.ts +13 -3
- package/library/ResourceVisibilityControl.d.ts.map +1 -1
- package/library/ResourceVisibilityControl.js +33 -5
- package/library/ResourceVisibilityControl.js.map +1 -1
- package/library/VisibilityOptionRow.d.ts +6 -0
- package/library/VisibilityOptionRow.d.ts.map +1 -1
- package/library/VisibilityOptionRow.js +11 -1
- package/library/VisibilityOptionRow.js.map +1 -1
- package/library/VisibilitySelector.d.ts.map +1 -1
- package/library/VisibilitySelector.js +14 -2
- package/library/VisibilitySelector.js.map +1 -1
- package/library/index.d.ts +4 -2
- package/library/index.d.ts.map +1 -1
- package/library/index.js +2 -1
- package/library/index.js.map +1 -1
- package/library/useCanSetPublicVisibility.d.ts +30 -0
- package/library/useCanSetPublicVisibility.d.ts.map +1 -0
- package/library/useCanSetPublicVisibility.js +41 -0
- package/library/useCanSetPublicVisibility.js.map +1 -0
- package/library/visibilityLevels.d.ts +32 -1
- package/library/visibilityLevels.d.ts.map +1 -1
- package/library/visibilityLevels.js +34 -14
- package/library/visibilityLevels.js.map +1 -1
- package/manifest/ApplyManifestDialog.d.ts.map +1 -1
- package/manifest/ApplyManifestDialog.js +2 -1
- package/manifest/ApplyManifestDialog.js.map +1 -1
- package/mcp-server/steps/IdentityTransportStep.d.ts.map +1 -1
- package/mcp-server/steps/IdentityTransportStep.js +2 -1
- package/mcp-server/steps/IdentityTransportStep.js.map +1 -1
- package/mcp-server/useMcpServerConnect.d.ts +8 -5
- package/mcp-server/useMcpServerConnect.d.ts.map +1 -1
- package/mcp-server/useMcpServerConnect.js +2 -1
- package/mcp-server/useMcpServerConnect.js.map +1 -1
- package/mcp-server/useMcpServerOAuthConnect.d.ts.map +1 -1
- package/mcp-server/useMcpServerOAuthConnect.js +7 -2
- package/mcp-server/useMcpServerOAuthConnect.js.map +1 -1
- package/oauth-app/CreateOAuthAppForm.d.ts +2 -2
- package/oauth-app/CreateOAuthAppForm.d.ts.map +1 -1
- package/oauth-app/CreateOAuthAppForm.js +13 -4
- package/oauth-app/CreateOAuthAppForm.js.map +1 -1
- package/oauth-app/OAuthAppDetailPanel.d.ts.map +1 -1
- package/oauth-app/OAuthAppDetailPanel.js +32 -5
- package/oauth-app/OAuthAppDetailPanel.js.map +1 -1
- package/organization/OrgPreferencesPanel.d.ts +32 -0
- package/organization/OrgPreferencesPanel.d.ts.map +1 -0
- package/organization/OrgPreferencesPanel.js +90 -0
- package/organization/OrgPreferencesPanel.js.map +1 -0
- package/organization/OrgProfilePanel.d.ts.map +1 -1
- package/organization/OrgProfilePanel.js +5 -4
- package/organization/OrgProfilePanel.js.map +1 -1
- package/organization/index.d.ts +2 -0
- package/organization/index.d.ts.map +1 -1
- package/organization/index.js +1 -0
- package/organization/index.js.map +1 -1
- package/package.json +4 -4
- package/platform-client/CreatePlatformClientForm.d.ts.map +1 -1
- package/platform-client/CreatePlatformClientForm.js +2 -1
- package/platform-client/CreatePlatformClientForm.js.map +1 -1
- package/platform-client/PlatformClientDetailPanel.d.ts.map +1 -1
- package/platform-client/PlatformClientDetailPanel.js +2 -1
- package/platform-client/PlatformClientDetailPanel.js.map +1 -1
- package/pricing-governance/BaselineEditor.d.ts.map +1 -1
- package/pricing-governance/BaselineEditor.js +2 -1
- package/pricing-governance/BaselineEditor.js.map +1 -1
- package/pricing-governance/PricingGovernanceConsole.d.ts.map +1 -1
- package/pricing-governance/PricingGovernanceConsole.js +2 -1
- package/pricing-governance/PricingGovernanceConsole.js.map +1 -1
- package/provider-standing/ProviderStandingAccessNotice.d.ts +11 -0
- package/provider-standing/ProviderStandingAccessNotice.d.ts.map +1 -0
- package/provider-standing/ProviderStandingAccessNotice.js +14 -0
- package/provider-standing/ProviderStandingAccessNotice.js.map +1 -0
- package/provider-standing/ProviderStandingConsole.d.ts +24 -0
- package/provider-standing/ProviderStandingConsole.d.ts.map +1 -0
- package/provider-standing/ProviderStandingConsole.js +98 -0
- package/provider-standing/ProviderStandingConsole.js.map +1 -0
- package/provider-standing/index.d.ts +6 -0
- package/provider-standing/index.d.ts.map +1 -0
- package/provider-standing/index.js +6 -0
- package/provider-standing/index.js.map +1 -0
- package/provider-standing/useProviderStanding.d.ts +34 -0
- package/provider-standing/useProviderStanding.d.ts.map +1 -0
- package/provider-standing/useProviderStanding.js +26 -0
- package/provider-standing/useProviderStanding.js.map +1 -0
- package/provider.d.ts +12 -0
- package/provider.d.ts.map +1 -1
- package/provider.js +12 -0
- package/provider.js.map +1 -1
- package/resource-creation/StepIndicator.d.ts.map +1 -1
- package/resource-creation/StepIndicator.js +2 -1
- package/resource-creation/StepIndicator.js.map +1 -1
- package/schedule/ScheduleDetailView.d.ts.map +1 -1
- package/schedule/ScheduleDetailView.js +3 -2
- package/schedule/ScheduleDetailView.js.map +1 -1
- package/schedule/ScheduleRunsTable.d.ts.map +1 -1
- package/schedule/ScheduleRunsTable.js +2 -1
- package/schedule/ScheduleRunsTable.js.map +1 -1
- package/session/NewSessionViewer.d.ts +10 -1
- package/session/NewSessionViewer.d.ts.map +1 -1
- package/session/NewSessionViewer.js +2 -1
- package/session/NewSessionViewer.js.map +1 -1
- package/session/facets/ArtifactsTab.d.ts.map +1 -1
- package/session/facets/ArtifactsTab.js +2 -1
- package/session/facets/ArtifactsTab.js.map +1 -1
- package/session/facets/ChangesTab.d.ts.map +1 -1
- package/session/facets/ChangesTab.js +2 -1
- package/session/facets/ChangesTab.js.map +1 -1
- package/session/facets/UsageTab.d.ts +10 -3
- package/session/facets/UsageTab.d.ts.map +1 -1
- package/session/facets/UsageTab.js +42 -6
- package/session/facets/UsageTab.js.map +1 -1
- package/session/index.d.ts +1 -1
- package/session/index.d.ts.map +1 -1
- package/session/index.js.map +1 -1
- package/session/useNewSessionFlow.d.ts +27 -1
- package/session/useNewSessionFlow.d.ts.map +1 -1
- package/session/useNewSessionFlow.js +45 -8
- package/session/useNewSessionFlow.js.map +1 -1
- package/session/useSessionUsage.d.ts +25 -0
- package/session/useSessionUsage.d.ts.map +1 -1
- package/session/useSessionUsage.js +11 -0
- package/session/useSessionUsage.js.map +1 -1
- package/settings/AccountPreferencesSection.d.ts +3 -0
- package/settings/AccountPreferencesSection.d.ts.map +1 -0
- package/settings/AccountPreferencesSection.js +10 -0
- package/settings/AccountPreferencesSection.js.map +1 -0
- package/settings/OrgPreferencesSection.d.ts +3 -0
- package/settings/OrgPreferencesSection.d.ts.map +1 -0
- package/settings/OrgPreferencesSection.js +13 -0
- package/settings/OrgPreferencesSection.js.map +1 -0
- package/settings/index.d.ts +2 -0
- package/settings/index.d.ts.map +1 -1
- package/settings/index.js +2 -0
- package/settings/index.js.map +1 -1
- package/settings/settings-nav.d.ts.map +1 -1
- package/settings/settings-nav.js +23 -1
- package/settings/settings-nav.js.map +1 -1
- package/settings/useSettingsNavGroups.d.ts.map +1 -1
- package/settings/useSettingsNavGroups.js +4 -1
- package/settings/useSettingsNavGroups.js.map +1 -1
- package/sharing/ShareAgentDialog.d.ts.map +1 -1
- package/sharing/ShareAgentDialog.js +2 -1
- package/sharing/ShareAgentDialog.js.map +1 -1
- package/sidebar/WorkspaceSidebar.d.ts.map +1 -1
- package/sidebar/WorkspaceSidebar.js +2 -1
- package/sidebar/WorkspaceSidebar.js.map +1 -1
- package/skill/SkillFileBrowser.d.ts.map +1 -1
- package/skill/SkillFileBrowser.js +2 -1
- package/skill/SkillFileBrowser.js.map +1 -1
- package/skill/internal/fetchAndUnpackArtifact.d.ts +1 -1
- package/skill/internal/fetchAndUnpackArtifact.d.ts.map +1 -1
- package/skill/internal/fetchAndUnpackArtifact.js +47 -3
- package/skill/internal/fetchAndUnpackArtifact.js.map +1 -1
- package/skill/useSkillDiff.d.ts.map +1 -1
- package/skill/useSkillDiff.js +7 -1
- package/skill/useSkillDiff.js.map +1 -1
- package/skill/useSkillUpload.d.ts.map +1 -1
- package/skill/useSkillUpload.js +22 -4
- package/skill/useSkillUpload.js.map +1 -1
- package/src/__tests__/bare-host-resets.layout.test.tsx +184 -0
- package/src/agent/steps/IdentityStep.tsx +2 -1
- package/src/agent-instance/AgentInstanceDetailPanel.tsx +2 -1
- package/src/api-key/CreateApiKeyForm.tsx +2 -1
- package/src/attachment/AttachmentChipList.tsx +19 -8
- package/src/attachment/__tests__/AttachmentChipList.test.tsx +12 -0
- package/src/attachment/__tests__/useAttachments.test.ts +293 -0
- package/src/attachment/index.ts +1 -0
- package/src/attachment/useAttachments.ts +143 -11
- package/src/channel/ChannelConversationsDialog.tsx +2 -1
- package/src/channel/ChannelTemplatesDialog.tsx +2 -1
- package/src/channel/ConnectSlackDialog.tsx +2 -1
- package/src/channel/connect/ServingAppSection.tsx +2 -1
- package/src/channel-app/CreateChannelAppForm.tsx +2 -1
- package/src/composer/SessionComposer.tsx +23 -14
- package/src/conversation/ConversationComposer.tsx +38 -4
- package/src/conversation/ConversationListPane.tsx +2 -5
- package/src/conversation/ConversationTemplatePickerDialog.tsx +441 -0
- package/src/conversation/ConversationTimelineView.tsx +2 -1
- package/src/conversation/ConversationsWorkbench.tsx +40 -4
- package/src/conversation/__tests__/ConversationComposer.test.tsx +56 -1
- package/src/conversation/__tests__/ConversationTemplatePickerDialog.test.tsx +224 -0
- package/src/conversation/__tests__/useConversationParticipation.test.tsx +45 -4
- package/src/conversation/index.ts +4 -0
- package/src/conversation/useConversationParticipation.ts +58 -6
- package/src/cursor-accounts/CursorAccountsConsole.tsx +2 -1
- package/src/cursor-accounts/MemberKeysPanel.tsx +2 -1
- package/src/dashboard/DashboardFailedRuns.tsx +2 -1
- package/src/dependency-graph/DependencyGraph.tsx +2 -1
- package/src/dependency-graph/DependencyTreeNode.tsx +2 -1
- package/src/environment/EnvironmentPicker.tsx +2 -1
- package/src/error/SecretFlowErrorGuide.tsx +3 -2
- package/src/execution/ArtifactContentBody.tsx +2 -1
- package/src/execution/ArtifactsWidget.tsx +2 -1
- package/src/execution/FileChangeProgressBar.tsx +2 -1
- package/src/execution/TodoList.tsx +2 -1
- package/src/execution/WriteBacksWidget.tsx +2 -1
- package/src/execution/tool-categories.ts +17 -41
- package/src/iam-policy/PeopleWithAccess.tsx +2 -1
- package/src/iam-policy/PrincipalPicker.tsx +2 -0
- package/src/iam-policy/RoleSelector.tsx +2 -1
- package/src/identity-account/AccountPreferencesPanel.tsx +446 -0
- package/src/identity-account/__tests__/AccountPreferencesPanel.test.tsx +233 -0
- package/src/identity-account/__tests__/useAccountExecutionDefaults.test.tsx +116 -0
- package/src/identity-account/__tests__/useMyIdentityAccount.test.tsx +121 -0
- package/src/identity-account/index.ts +11 -0
- package/src/identity-account/useAccountExecutionDefaults.ts +63 -0
- package/src/identity-account/useMyIdentityAccount.ts +75 -0
- package/src/identity-account/useUpdateIdentityAccount.ts +73 -0
- package/src/identity-provider/CreateIdentityProviderForm.tsx +2 -1
- package/src/identity-provider/IdentityProviderDetailPanel.tsx +2 -1
- package/src/identity-provider/IdentityProviderWizard.tsx +2 -1
- package/src/index.ts +37 -2
- package/src/internal/StandingContextField.tsx +92 -0
- package/src/internal/element-resets.ts +33 -0
- package/src/internal/file-tree/FileTreeNode.tsx +2 -1
- package/src/internal/markdown-components.tsx +15 -5
- package/src/invitation/InvitationManager.tsx +3 -2
- package/src/library/InstanceVisibilitySelector.tsx +9 -2
- package/src/library/ResourceVisibilityControl.tsx +46 -13
- package/src/library/VisibilityOptionRow.tsx +28 -6
- package/src/library/VisibilitySelector.tsx +14 -2
- package/src/library/__tests__/VisibilitySelector.test.tsx +48 -1
- package/src/library/__tests__/visibilityLevels.test.ts +67 -1
- package/src/library/index.ts +6 -1
- package/src/library/useCanSetPublicVisibility.ts +56 -0
- package/src/library/visibilityLevels.ts +65 -14
- package/src/manifest/ApplyManifestDialog.tsx +2 -1
- package/src/mcp-server/__tests__/useMcpServerConnect.asyncLane.test.tsx +117 -0
- package/src/mcp-server/steps/IdentityTransportStep.tsx +3 -2
- package/src/mcp-server/useMcpServerConnect.ts +9 -6
- package/src/mcp-server/useMcpServerOAuthConnect.ts +7 -2
- package/src/oauth-app/CreateOAuthAppForm.tsx +58 -3
- package/src/oauth-app/OAuthAppDetailPanel.tsx +84 -3
- package/src/organization/OrgPreferencesPanel.tsx +221 -0
- package/src/organization/OrgProfilePanel.tsx +5 -4
- package/src/organization/__tests__/OrgPreferencesPanel.test.tsx +145 -0
- package/src/organization/__tests__/OrgProfilePanel.test.tsx +108 -0
- package/src/organization/index.ts +2 -0
- package/src/platform-client/CreatePlatformClientForm.tsx +4 -3
- package/src/platform-client/PlatformClientDetailPanel.tsx +4 -3
- package/src/pricing-governance/BaselineEditor.tsx +3 -2
- package/src/pricing-governance/PricingGovernanceConsole.tsx +2 -1
- package/src/provider-standing/ProviderStandingAccessNotice.tsx +36 -0
- package/src/provider-standing/ProviderStandingConsole.tsx +216 -0
- package/src/provider-standing/__tests__/ProviderStandingConsole.test.tsx +143 -0
- package/src/provider-standing/index.ts +8 -0
- package/src/provider-standing/useProviderStanding.ts +50 -0
- package/src/provider.tsx +12 -0
- package/src/resource-creation/StepIndicator.tsx +2 -1
- package/src/schedule/ScheduleDetailView.tsx +3 -2
- package/src/schedule/ScheduleRunsTable.tsx +2 -1
- package/src/session/NewSessionViewer.tsx +12 -0
- package/src/session/__tests__/UsageTab.test.tsx +136 -0
- package/src/session/__tests__/useNewSessionFlow.test.tsx +151 -0
- package/src/session/__tests__/useSessionUsage.test.ts +19 -0
- package/src/session/facets/ArtifactsTab.tsx +2 -1
- package/src/session/facets/ChangesTab.tsx +2 -1
- package/src/session/facets/UsageTab.tsx +98 -6
- package/src/session/index.ts +1 -0
- package/src/session/useNewSessionFlow.ts +76 -9
- package/src/session/useSessionUsage.ts +37 -0
- package/src/settings/AccountPreferencesSection.tsx +25 -0
- package/src/settings/OrgPreferencesSection.tsx +35 -0
- package/src/settings/__tests__/settings-nav.test.ts +27 -0
- package/src/settings/__tests__/useSettingsNavGroups.test.tsx +11 -1
- package/src/settings/index.ts +2 -0
- package/src/settings/settings-nav.ts +25 -0
- package/src/settings/useSettingsNavGroups.ts +8 -1
- package/src/sharing/ShareAgentDialog.tsx +2 -1
- package/src/sidebar/WorkspaceSidebar.tsx +2 -1
- package/src/skill/SkillFileBrowser.tsx +2 -1
- package/src/skill/__tests__/SkillFileBrowser.test.tsx +10 -2
- package/src/skill/__tests__/fetchAndUnpackArtifact.test.ts +90 -0
- package/src/skill/__tests__/useSkillUpload.test.ts +69 -0
- package/src/skill/internal/fetchAndUnpackArtifact.ts +54 -4
- package/src/skill/useSkillDiff.ts +7 -1
- package/src/skill/useSkillUpload.ts +25 -6
- package/src/workflow/ApprovalFormBuilder.tsx +5 -27
- package/src/workflow/FailedRunsWidget.tsx +2 -1
- package/src/workflow/PendingApprovalsWidget.tsx +2 -1
- package/src/workflow/facets/WorkflowArtifactsTab.tsx +2 -1
- package/src/workflow/facets/WorkflowUsageTab.tsx +2 -1
- package/src/workflow/inspector/WorkflowSummaryPanel.tsx +2 -1
- package/src/workflow/inspector/tabs/BranchesTab.tsx +2 -1
- package/src/workflow/inspector/tabs/IterationTab.tsx +2 -1
- package/src/workflow/instance/WorkflowInstanceDetailPanel.tsx +2 -1
- package/src/workspace/ExplorerTree.tsx +2 -1
- package/src/workspace/WorkspaceContentSearch.tsx +2 -1
- package/src/workspace/WorkspaceFileSearch.tsx +2 -1
- package/src/workspace/WorkspaceSummary.tsx +2 -1
- package/styles.css +1 -1
- package/workflow/ApprovalFormBuilder.d.ts.map +1 -1
- package/workflow/ApprovalFormBuilder.js +8 -5
- package/workflow/ApprovalFormBuilder.js.map +1 -1
- package/workflow/FailedRunsWidget.d.ts.map +1 -1
- package/workflow/FailedRunsWidget.js +2 -1
- package/workflow/FailedRunsWidget.js.map +1 -1
- package/workflow/PendingApprovalsWidget.d.ts.map +1 -1
- package/workflow/PendingApprovalsWidget.js +2 -1
- package/workflow/PendingApprovalsWidget.js.map +1 -1
- package/workflow/facets/WorkflowArtifactsTab.d.ts.map +1 -1
- package/workflow/facets/WorkflowArtifactsTab.js +2 -1
- package/workflow/facets/WorkflowArtifactsTab.js.map +1 -1
- package/workflow/facets/WorkflowUsageTab.d.ts.map +1 -1
- package/workflow/facets/WorkflowUsageTab.js +2 -1
- package/workflow/facets/WorkflowUsageTab.js.map +1 -1
- package/workflow/inspector/WorkflowSummaryPanel.d.ts.map +1 -1
- package/workflow/inspector/WorkflowSummaryPanel.js +2 -1
- package/workflow/inspector/WorkflowSummaryPanel.js.map +1 -1
- package/workflow/inspector/tabs/BranchesTab.d.ts.map +1 -1
- package/workflow/inspector/tabs/BranchesTab.js +2 -1
- package/workflow/inspector/tabs/BranchesTab.js.map +1 -1
- package/workflow/inspector/tabs/IterationTab.d.ts.map +1 -1
- package/workflow/inspector/tabs/IterationTab.js +2 -1
- package/workflow/inspector/tabs/IterationTab.js.map +1 -1
- package/workflow/instance/WorkflowInstanceDetailPanel.d.ts.map +1 -1
- package/workflow/instance/WorkflowInstanceDetailPanel.js +2 -1
- package/workflow/instance/WorkflowInstanceDetailPanel.js.map +1 -1
- package/workspace/ExplorerTree.d.ts.map +1 -1
- package/workspace/ExplorerTree.js +2 -1
- package/workspace/ExplorerTree.js.map +1 -1
- package/workspace/WorkspaceContentSearch.d.ts.map +1 -1
- package/workspace/WorkspaceContentSearch.js +2 -1
- package/workspace/WorkspaceContentSearch.js.map +1 -1
- package/workspace/WorkspaceFileSearch.d.ts.map +1 -1
- package/workspace/WorkspaceFileSearch.js +2 -1
- package/workspace/WorkspaceFileSearch.js.map +1 -1
- package/workspace/WorkspaceSummary.d.ts.map +1 -1
- package/workspace/WorkspaceSummary.js +2 -1
- package/workspace/WorkspaceSummary.js.map +1 -1
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
import { describe, it, expect, vi, afterEach } from "vitest";
|
|
2
|
+
import { cleanup, fireEvent, render, screen, waitFor } from "@testing-library/react";
|
|
3
|
+
import { create } from "@bufbuild/protobuf";
|
|
4
|
+
import {
|
|
5
|
+
OrganizationSchema,
|
|
6
|
+
type Organization,
|
|
7
|
+
} from "@stigmer/protos/ai/stigmer/tenancy/organization/v1/api_pb";
|
|
8
|
+
import type { OrganizationInput } from "@stigmer/sdk";
|
|
9
|
+
import { StigmerContext } from "../../context";
|
|
10
|
+
import { DeploymentModeContext } from "../../deployment-mode";
|
|
11
|
+
import { OrgProfilePanel } from "../OrgProfilePanel";
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Regression suite for the full-spec-replace wipe bug (oss#293 Phase 1):
|
|
15
|
+
* `organization.update()` wholesale replaces the stored spec, so a profile
|
|
16
|
+
* save that sends only the edited fields silently wipes every other mutable
|
|
17
|
+
* spec field — most visibly `spec.preferences.standing_context` set via the
|
|
18
|
+
* CLI or the preferences page. The panel must spread the complete mapped
|
|
19
|
+
* input and override only what it edits.
|
|
20
|
+
*/
|
|
21
|
+
|
|
22
|
+
const ORG: Organization = create(OrganizationSchema, {
|
|
23
|
+
metadata: {
|
|
24
|
+
id: "acme",
|
|
25
|
+
name: "Acme Corp",
|
|
26
|
+
slug: "acme",
|
|
27
|
+
org: "acme",
|
|
28
|
+
},
|
|
29
|
+
spec: {
|
|
30
|
+
description: "We make everything.",
|
|
31
|
+
logoUrl: "https://acme.example/logo.png",
|
|
32
|
+
preferences: { standingContext: "We deploy to us-east-1." },
|
|
33
|
+
},
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
function createMockStigmer(overrides?: {
|
|
37
|
+
update?: ReturnType<typeof vi.fn>;
|
|
38
|
+
}) {
|
|
39
|
+
return {
|
|
40
|
+
organization: {
|
|
41
|
+
get: vi.fn(async () => ORG),
|
|
42
|
+
update: overrides?.update ?? vi.fn(async () => ORG),
|
|
43
|
+
},
|
|
44
|
+
} as never;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
// Deployment mode "local" keeps the IdentityProvidersSummary sub-panel
|
|
48
|
+
// inert (identity_provider is cloud-only), so no extra client stubs are
|
|
49
|
+
// needed — the suite tests the form, not the summary.
|
|
50
|
+
function renderPanel(client: unknown) {
|
|
51
|
+
return render(
|
|
52
|
+
<StigmerContext.Provider value={client as never}>
|
|
53
|
+
<DeploymentModeContext.Provider value="local">
|
|
54
|
+
<OrgProfilePanel orgId="acme" />
|
|
55
|
+
</DeploymentModeContext.Provider>
|
|
56
|
+
</StigmerContext.Provider>,
|
|
57
|
+
);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
afterEach(cleanup);
|
|
61
|
+
|
|
62
|
+
describe("OrgProfilePanel save payload", () => {
|
|
63
|
+
it("round-trips unedited spec fields — preferences survive a profile save", async () => {
|
|
64
|
+
const update = vi.fn(async (_input: OrganizationInput) => ORG);
|
|
65
|
+
const client = createMockStigmer({ update });
|
|
66
|
+
renderPanel(client);
|
|
67
|
+
|
|
68
|
+
// Wait for the server-sync effect to fill the form before editing —
|
|
69
|
+
// interacting on first appearance races the sync.
|
|
70
|
+
const description = await screen.findByLabelText("Description");
|
|
71
|
+
await waitFor(() =>
|
|
72
|
+
expect(description).toHaveProperty("value", "We make everything."),
|
|
73
|
+
);
|
|
74
|
+
fireEvent.change(description, { target: { value: "New description" } });
|
|
75
|
+
fireEvent.click(screen.getByRole("button", { name: "Save changes" }));
|
|
76
|
+
|
|
77
|
+
await waitFor(() => expect(update).toHaveBeenCalledTimes(1));
|
|
78
|
+
const input = update.mock.calls[0]![0];
|
|
79
|
+
|
|
80
|
+
// The edited field.
|
|
81
|
+
expect(input.description).toBe("New description");
|
|
82
|
+
// The unedited fields the form does not render — the wipe-bug guard.
|
|
83
|
+
expect(input.preferences).toEqual({
|
|
84
|
+
standingContext: "We deploy to us-east-1.",
|
|
85
|
+
});
|
|
86
|
+
expect(input.logoUrl).toBe("https://acme.example/logo.png");
|
|
87
|
+
// Addressing fields for the update pipeline's org+slug lookup.
|
|
88
|
+
expect(input.org).toBe("acme");
|
|
89
|
+
expect(input.slug).toBe("acme");
|
|
90
|
+
expect(input.name).toBe("Acme Corp");
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
it("sends the edited name and keeps discard/dirty semantics intact", async () => {
|
|
94
|
+
const update = vi.fn(async (_input: OrganizationInput) => ORG);
|
|
95
|
+
renderPanel(createMockStigmer({ update }));
|
|
96
|
+
|
|
97
|
+
const name = await screen.findByLabelText("Name");
|
|
98
|
+
await waitFor(() => expect(name).toHaveProperty("value", "Acme Corp"));
|
|
99
|
+
fireEvent.change(name, { target: { value: "Acme Corporation" } });
|
|
100
|
+
fireEvent.click(screen.getByRole("button", { name: "Save changes" }));
|
|
101
|
+
|
|
102
|
+
await waitFor(() => expect(update).toHaveBeenCalledTimes(1));
|
|
103
|
+
expect(update.mock.calls[0]![0].name).toBe("Acme Corporation");
|
|
104
|
+
expect(update.mock.calls[0]![0].preferences).toEqual({
|
|
105
|
+
standingContext: "We deploy to us-east-1.",
|
|
106
|
+
});
|
|
107
|
+
});
|
|
108
|
+
});
|
|
@@ -16,5 +16,7 @@ export { CreateOrganizationForm } from "./CreateOrganizationForm.js";
|
|
|
16
16
|
export type { CreateOrganizationFormProps } from "./CreateOrganizationForm.js";
|
|
17
17
|
export { OrgProfilePanel } from "./OrgProfilePanel.js";
|
|
18
18
|
export type { OrgProfilePanelProps } from "./OrgProfilePanel.js";
|
|
19
|
+
export { OrgPreferencesPanel } from "./OrgPreferencesPanel.js";
|
|
20
|
+
export type { OrgPreferencesPanelProps } from "./OrgPreferencesPanel.js";
|
|
19
21
|
export { OrgSwitcher } from "./OrgSwitcher.js";
|
|
20
22
|
export type { OrgSwitcherProps } from "./OrgSwitcher.js";
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
import { type FormEvent, type KeyboardEvent, useCallback, useId, useState } from "react";
|
|
4
4
|
import { cn } from "@stigmer/theme";
|
|
5
|
+
import { UNSTYLED_FIELDSET } from "../internal/element-resets.js";
|
|
5
6
|
import { getUserMessage } from "@stigmer/sdk";
|
|
6
7
|
import { IamRole } from "@stigmer/protos/ai/stigmer/iam/v1/enum_pb";
|
|
7
8
|
import type { PlatformClientCreateResponse } from "@stigmer/protos/ai/stigmer/iam/platformclient/v1/io_pb";
|
|
@@ -167,7 +168,7 @@ export function CreatePlatformClientForm({
|
|
|
167
168
|
/>
|
|
168
169
|
|
|
169
170
|
{/* Expiry */}
|
|
170
|
-
<fieldset className="stg:space-y-2" disabled={isCreating}>
|
|
171
|
+
<fieldset className={cn(UNSTYLED_FIELDSET, "stg:space-y-2")} disabled={isCreating}>
|
|
171
172
|
<legend className="stg:text-xs stg:font-medium stg:text-foreground">
|
|
172
173
|
Expiry
|
|
173
174
|
</legend>
|
|
@@ -202,7 +203,7 @@ export function CreatePlatformClientForm({
|
|
|
202
203
|
</fieldset>
|
|
203
204
|
|
|
204
205
|
{/* JIT provisioning */}
|
|
205
|
-
<fieldset className="stg:space-y-2.5" disabled={isCreating}>
|
|
206
|
+
<fieldset className={cn(UNSTYLED_FIELDSET, "stg:space-y-2.5")} disabled={isCreating}>
|
|
206
207
|
<hr className="stg:border-border-muted" />
|
|
207
208
|
<legend className="stg:text-xs stg:font-medium stg:text-foreground">
|
|
208
209
|
JIT provisioning
|
|
@@ -263,7 +264,7 @@ export function CreatePlatformClientForm({
|
|
|
263
264
|
</fieldset>
|
|
264
265
|
|
|
265
266
|
{/* Allowed origins */}
|
|
266
|
-
<fieldset className="stg:space-y-2" disabled={isCreating}>
|
|
267
|
+
<fieldset className={cn(UNSTYLED_FIELDSET, "stg:space-y-2")} disabled={isCreating}>
|
|
267
268
|
<hr className="stg:border-border-muted" />
|
|
268
269
|
<legend className="stg:text-xs stg:font-medium stg:text-foreground">
|
|
269
270
|
Allowed origins
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
import { type FormEvent, type KeyboardEvent, useCallback, useId, useState } from "react";
|
|
4
4
|
import { cn } from "@stigmer/theme";
|
|
5
|
+
import { UNSTYLED_FIELDSET } from "../internal/element-resets.js";
|
|
5
6
|
import { getUserMessage } from "@stigmer/sdk";
|
|
6
7
|
import { IamRole } from "@stigmer/protos/ai/stigmer/iam/v1/enum_pb";
|
|
7
8
|
import { timestampDate, type Timestamp } from "@bufbuild/protobuf/wkt";
|
|
@@ -302,7 +303,7 @@ export function PlatformClientDetailPanel({
|
|
|
302
303
|
</div>
|
|
303
304
|
|
|
304
305
|
{/* Expiry */}
|
|
305
|
-
<fieldset className="stg:space-y-2" disabled={isUpdating}>
|
|
306
|
+
<fieldset className={cn(UNSTYLED_FIELDSET, "stg:space-y-2")} disabled={isUpdating}>
|
|
306
307
|
<legend className="stg:text-xs stg:font-medium stg:text-foreground">
|
|
307
308
|
Expiry
|
|
308
309
|
</legend>
|
|
@@ -337,7 +338,7 @@ export function PlatformClientDetailPanel({
|
|
|
337
338
|
</fieldset>
|
|
338
339
|
|
|
339
340
|
{/* JIT provisioning */}
|
|
340
|
-
<fieldset className="stg:space-y-2.5" disabled={isUpdating}>
|
|
341
|
+
<fieldset className={cn(UNSTYLED_FIELDSET, "stg:space-y-2.5")} disabled={isUpdating}>
|
|
341
342
|
<hr className="stg:border-border-muted" />
|
|
342
343
|
<legend className="stg:text-xs stg:font-medium stg:text-foreground">
|
|
343
344
|
JIT provisioning
|
|
@@ -393,7 +394,7 @@ export function PlatformClientDetailPanel({
|
|
|
393
394
|
</fieldset>
|
|
394
395
|
|
|
395
396
|
{/* Allowed origins */}
|
|
396
|
-
<fieldset className="stg:space-y-2" disabled={isUpdating}>
|
|
397
|
+
<fieldset className={cn(UNSTYLED_FIELDSET, "stg:space-y-2")} disabled={isUpdating}>
|
|
397
398
|
<hr className="stg:border-border-muted" />
|
|
398
399
|
<legend className="stg:text-xs stg:font-medium stg:text-foreground">
|
|
399
400
|
Allowed origins
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
|
|
3
3
|
import { useCallback, useState, type FormEvent } from "react";
|
|
4
|
+
import { UNSTYLED_FIELDSET } from "../internal/element-resets.js";
|
|
4
5
|
import { create } from "@bufbuild/protobuf";
|
|
5
6
|
import { getUserMessage } from "@stigmer/sdk";
|
|
6
7
|
import {
|
|
@@ -546,7 +547,7 @@ export function BaselineEditor({
|
|
|
546
547
|
Featured (appears in the curated default picker list)
|
|
547
548
|
</label>
|
|
548
549
|
|
|
549
|
-
<fieldset className=
|
|
550
|
+
<fieldset className={`${UNSTYLED_FIELDSET} stg:space-y-2`}>
|
|
550
551
|
<legend className="stg:text-xs stg:font-medium stg:text-foreground">
|
|
551
552
|
Rates ($ per million tokens)
|
|
552
553
|
</legend>
|
|
@@ -565,7 +566,7 @@ export function BaselineEditor({
|
|
|
565
566
|
</div>
|
|
566
567
|
</fieldset>
|
|
567
568
|
|
|
568
|
-
<fieldset className=
|
|
569
|
+
<fieldset className={`${UNSTYLED_FIELDSET} stg:space-y-2`}>
|
|
569
570
|
<legend className="stg:text-xs stg:font-medium stg:text-foreground">Pricing variants</legend>
|
|
570
571
|
{form.variants.map((variant, index) => (
|
|
571
572
|
<div key={index} className="stg:space-y-2 stg:rounded-md stg:border stg:border-border-muted stg:px-2.5 stg:py-2">
|
|
@@ -11,6 +11,7 @@ import { RetireConfirm } from "./RetireConfirm.js";
|
|
|
11
11
|
import { ModelGovernanceDetail } from "./ModelGovernanceDetail.js";
|
|
12
12
|
import { OperatorAccessNotice } from "./OperatorAccessNotice.js";
|
|
13
13
|
import { GovernanceBadge, PendingOverrideCard, RateCell } from "./governance-primitives.js";
|
|
14
|
+
import { UNSTYLED_LIST } from "../internal/element-resets.js";
|
|
14
15
|
import { INPUT_CLASSES } from "../internal/form-primitives.js";
|
|
15
16
|
import { TruncatedText } from "../internal/truncated-text.js";
|
|
16
17
|
import { ZERO } from "./pricing-format.js";
|
|
@@ -328,7 +329,7 @@ function ModelsTab({
|
|
|
328
329
|
: "The catalog is empty — has the baseline seed migration run?"}
|
|
329
330
|
</p>
|
|
330
331
|
) : (
|
|
331
|
-
<ul role="list" aria-label="Models" className=
|
|
332
|
+
<ul role="list" aria-label="Models" className={UNSTYLED_LIST}>
|
|
332
333
|
{view.models.map((row) => (
|
|
333
334
|
<ModelRow key={row.key} row={row} onOpen={() => view.openDetail(row.key)} />
|
|
334
335
|
))}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import { cn } from "@stigmer/theme";
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* The access-denied state for the provider-standing operator surface.
|
|
7
|
+
* Server-side authorization (`can_view_provider_standing` on
|
|
8
|
+
* `platform:stigmer`) is the real gate — this is the honest, designed
|
|
9
|
+
* face of that denial for anyone who navigates to the operator route
|
|
10
|
+
* without the permission, instead of a raw RPC error string.
|
|
11
|
+
*/
|
|
12
|
+
export function ProviderStandingAccessNotice({
|
|
13
|
+
className,
|
|
14
|
+
}: {
|
|
15
|
+
readonly className?: string;
|
|
16
|
+
}) {
|
|
17
|
+
return (
|
|
18
|
+
<div
|
|
19
|
+
className={cn(
|
|
20
|
+
"stg:rounded-lg stg:border stg:border-border stg:bg-card stg:px-4 stg:py-6 stg:text-center",
|
|
21
|
+
className,
|
|
22
|
+
)}
|
|
23
|
+
role="status"
|
|
24
|
+
>
|
|
25
|
+
<p className="stg:text-xs stg:font-semibold stg:text-foreground">
|
|
26
|
+
Platform operator access required
|
|
27
|
+
</p>
|
|
28
|
+
<p className="stg:mx-auto stg:mt-1 stg:max-w-md stg:text-xs stg:text-muted-foreground">
|
|
29
|
+
Provider standing reports the health of the platform's own LLM
|
|
30
|
+
provider accounts, which is Stigmer-internal. It needs the platform
|
|
31
|
+
operator role — organization roles do not grant it. If you believe
|
|
32
|
+
you should have access, contact a platform operator.
|
|
33
|
+
</p>
|
|
34
|
+
</div>
|
|
35
|
+
);
|
|
36
|
+
}
|
|
@@ -0,0 +1,216 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import { cn } from "@stigmer/theme";
|
|
4
|
+
import { getUserMessage, isPermissionDenied } from "@stigmer/sdk";
|
|
5
|
+
import type { Timestamp } from "@bufbuild/protobuf/wkt";
|
|
6
|
+
import type { ProviderStandingEntry } from "@stigmer/protos/ai/stigmer/platform/providerstanding/v1/io_pb";
|
|
7
|
+
import { Button } from "../button/index.js";
|
|
8
|
+
import { ProviderStandingAccessNotice } from "./ProviderStandingAccessNotice.js";
|
|
9
|
+
import { useProviderStanding } from "./useProviderStanding.js";
|
|
10
|
+
|
|
11
|
+
/** Props for {@link ProviderStandingConsole}. */
|
|
12
|
+
export interface ProviderStandingConsoleProps {
|
|
13
|
+
/** Additional CSS class names. */
|
|
14
|
+
readonly className?: string;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
// BigInt literals (0n) require an ES2020 target, which not every consuming
|
|
18
|
+
// app's tsconfig guarantees — the constructor form is target-agnostic (the
|
|
19
|
+
// cursor-account-format precedent).
|
|
20
|
+
const ZERO = BigInt(0);
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* A probe verdict older than this is flagged stale — the probe-silence
|
|
24
|
+
* alert's UI twin: the probe runs hourly and the alert fires at 3h (the
|
|
25
|
+
* 60m interval plus generous grace), so the console goes amber on the
|
|
26
|
+
* same clock operators are paged on.
|
|
27
|
+
*/
|
|
28
|
+
const STALE_AFTER_MS = 3 * 60 * 60 * 1000;
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Display metadata for the probe's closed status vocabulary (the
|
|
32
|
+
* lowercase labels StandingStatus persists). An unknown future label
|
|
33
|
+
* degrades to a muted badge showing the raw label — the wire contract is
|
|
34
|
+
* a string precisely so consoles never fail to decode a new status.
|
|
35
|
+
*/
|
|
36
|
+
const STATUS_DISPLAY: Record<string, { label: string; tone: "ok" | "warn" | "muted" }> = {
|
|
37
|
+
healthy: { label: "Healthy", tone: "ok" },
|
|
38
|
+
platform_billing: { label: "Billing rejected", tone: "warn" },
|
|
39
|
+
platform_auth: { label: "Auth rejected", tone: "warn" },
|
|
40
|
+
unclassified_error: { label: "Erroring", tone: "warn" },
|
|
41
|
+
unreachable: { label: "Unreachable", tone: "warn" },
|
|
42
|
+
not_configured: { label: "Not configured", tone: "muted" },
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* The platform-operator console page for provider standing: one card per
|
|
47
|
+
* platform LLM provider account with the latest canary-probe verdict —
|
|
48
|
+
* status, round-trip latency, upstream HTTP status, a bounded error
|
|
49
|
+
* summary, and when the probe last ran (flagged when stale).
|
|
50
|
+
*
|
|
51
|
+
* Read-only by design: the detection core (hourly probe, standing store,
|
|
52
|
+
* degraded/silence alerts) lives server-side; this surface only makes it
|
|
53
|
+
* visible where operators already look. Requires
|
|
54
|
+
* `can_view_provider_standing` on `platform:stigmer` — non-operators see
|
|
55
|
+
* the designed access notice.
|
|
56
|
+
*
|
|
57
|
+
* @example
|
|
58
|
+
* ```tsx
|
|
59
|
+
* <ProviderStandingConsole />
|
|
60
|
+
* ```
|
|
61
|
+
*/
|
|
62
|
+
export function ProviderStandingConsole({ className }: ProviderStandingConsoleProps) {
|
|
63
|
+
const { standing, isLoading, isRefetching, error, refetch } = useProviderStanding();
|
|
64
|
+
|
|
65
|
+
if (isLoading) {
|
|
66
|
+
return (
|
|
67
|
+
<div className={cn("stg:space-y-2", className)} aria-busy="true">
|
|
68
|
+
<div className="stg:h-4 stg:w-40 stg:animate-pulse stg:rounded stg:bg-muted-subtle" />
|
|
69
|
+
{Array.from({ length: 2 }, (_, i) => (
|
|
70
|
+
<div key={i} className="stg:h-16 stg:animate-pulse stg:rounded-lg stg:bg-muted-subtle" />
|
|
71
|
+
))}
|
|
72
|
+
</div>
|
|
73
|
+
);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
if (error) {
|
|
77
|
+
// A non-operator landing here is expected (the route is reachable by
|
|
78
|
+
// URL) — show the designed access notice, not a raw RPC error.
|
|
79
|
+
if (isPermissionDenied(error)) {
|
|
80
|
+
return <ProviderStandingAccessNotice className={className} />;
|
|
81
|
+
}
|
|
82
|
+
return (
|
|
83
|
+
<p className={cn("stg:text-destructive stg:text-xs", className)} role="alert">
|
|
84
|
+
{getUserMessage(error)}
|
|
85
|
+
</p>
|
|
86
|
+
);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
const providers = standing?.providers ?? [];
|
|
90
|
+
|
|
91
|
+
return (
|
|
92
|
+
<div className={cn("stg:space-y-3", className)}>
|
|
93
|
+
<div className="stg:flex stg:items-center stg:justify-between">
|
|
94
|
+
<p className="stg:text-xs stg:text-muted-foreground">
|
|
95
|
+
Latest canary verdict per platform provider account, probed hourly.
|
|
96
|
+
</p>
|
|
97
|
+
<Button
|
|
98
|
+
variant="outline"
|
|
99
|
+
size="sm"
|
|
100
|
+
onClick={refetch}
|
|
101
|
+
disabled={isRefetching}
|
|
102
|
+
>
|
|
103
|
+
{isRefetching ? "Refreshing…" : "Refresh"}
|
|
104
|
+
</Button>
|
|
105
|
+
</div>
|
|
106
|
+
|
|
107
|
+
{providers.length === 0 ? (
|
|
108
|
+
<p className="stg:rounded-lg stg:border stg:border-border stg:bg-card stg:px-4 stg:py-6 stg:text-center stg:text-xs stg:text-muted-foreground">
|
|
109
|
+
No probe verdicts recorded yet — the standing probe has not
|
|
110
|
+
completed a pass since this deployment came up.
|
|
111
|
+
</p>
|
|
112
|
+
) : (
|
|
113
|
+
<ul className="stg:m-0 stg:grid stg:list-none stg:gap-2 stg:p-0 sm:stg:grid-cols-2">
|
|
114
|
+
{providers.map((entry) => (
|
|
115
|
+
<StandingCard key={entry.provider} entry={entry} />
|
|
116
|
+
))}
|
|
117
|
+
</ul>
|
|
118
|
+
)}
|
|
119
|
+
</div>
|
|
120
|
+
);
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
function StandingCard({ entry }: { readonly entry: ProviderStandingEntry }) {
|
|
124
|
+
const display = STATUS_DISPLAY[entry.status] ?? {
|
|
125
|
+
label: entry.status || "unknown",
|
|
126
|
+
tone: "muted" as const,
|
|
127
|
+
};
|
|
128
|
+
const stale = isStale(entry.checkedAt);
|
|
129
|
+
|
|
130
|
+
return (
|
|
131
|
+
<li className="stg:rounded-lg stg:border stg:border-border stg:bg-card stg:p-3">
|
|
132
|
+
<div className="stg:flex stg:items-center stg:justify-between stg:gap-2">
|
|
133
|
+
<span className="stg:text-sm stg:font-semibold stg:capitalize stg:text-foreground">
|
|
134
|
+
{entry.provider}
|
|
135
|
+
</span>
|
|
136
|
+
<StatusBadge tone={display.tone} label={display.label} />
|
|
137
|
+
</div>
|
|
138
|
+
|
|
139
|
+
<dl className="stg:mt-2 stg:flex stg:flex-wrap stg:gap-x-4 stg:gap-y-1 stg:text-xs stg:text-muted-foreground">
|
|
140
|
+
{entry.latencyMs > ZERO && (
|
|
141
|
+
<div className="stg:flex stg:gap-1">
|
|
142
|
+
<dt>Latency</dt>
|
|
143
|
+
<dd className="stg:m-0 stg:text-foreground">{`${entry.latencyMs}ms`}</dd>
|
|
144
|
+
</div>
|
|
145
|
+
)}
|
|
146
|
+
{entry.httpStatus > 0 && (
|
|
147
|
+
<div className="stg:flex stg:gap-1">
|
|
148
|
+
<dt>HTTP</dt>
|
|
149
|
+
<dd className="stg:m-0 stg:text-foreground">{entry.httpStatus}</dd>
|
|
150
|
+
</div>
|
|
151
|
+
)}
|
|
152
|
+
<div className="stg:flex stg:gap-1">
|
|
153
|
+
<dt>Probed</dt>
|
|
154
|
+
<dd
|
|
155
|
+
className={cn(
|
|
156
|
+
"stg:m-0",
|
|
157
|
+
stale ? "stg:font-medium stg:text-destructive" : "stg:text-foreground",
|
|
158
|
+
)}
|
|
159
|
+
>
|
|
160
|
+
{formatProbeTime(entry.checkedAt)}
|
|
161
|
+
{stale ? " — stale" : ""}
|
|
162
|
+
</dd>
|
|
163
|
+
</div>
|
|
164
|
+
</dl>
|
|
165
|
+
|
|
166
|
+
{entry.errorSummary && (
|
|
167
|
+
<p className="stg:mt-2 stg:break-words stg:rounded stg:bg-muted-subtle stg:px-2 stg:py-1 stg:text-[11px] stg:text-muted-foreground">
|
|
168
|
+
{entry.errorSummary}
|
|
169
|
+
</p>
|
|
170
|
+
)}
|
|
171
|
+
</li>
|
|
172
|
+
);
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
/**
|
|
176
|
+
* Small tonal status badge — the cursor-accounts StateBadge shape, local
|
|
177
|
+
* to this module (the two operator surfaces evolve independently).
|
|
178
|
+
*/
|
|
179
|
+
function StatusBadge({
|
|
180
|
+
tone,
|
|
181
|
+
label,
|
|
182
|
+
}: {
|
|
183
|
+
readonly tone: "ok" | "warn" | "muted";
|
|
184
|
+
readonly label: string;
|
|
185
|
+
}) {
|
|
186
|
+
return (
|
|
187
|
+
<span
|
|
188
|
+
className={cn(
|
|
189
|
+
"stg:inline-block stg:rounded stg:px-1.5 stg:py-0.5 stg:text-[10px] stg:font-medium",
|
|
190
|
+
tone === "ok" && "stg:bg-accent stg:text-primary",
|
|
191
|
+
tone === "warn" && "stg:bg-muted-subtle stg:text-destructive",
|
|
192
|
+
tone === "muted" && "stg:bg-muted-subtle stg:text-muted-foreground",
|
|
193
|
+
)}
|
|
194
|
+
>
|
|
195
|
+
{label}
|
|
196
|
+
</span>
|
|
197
|
+
);
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
function isStale(ts: Timestamp | undefined): boolean {
|
|
201
|
+
if (!ts || ts.seconds === ZERO) return true;
|
|
202
|
+
return Date.now() - Number(ts.seconds) * 1000 > STALE_AFTER_MS;
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
/** Proto Timestamp to a compact local date-time (e.g. "Jul 22, 14:05"). */
|
|
206
|
+
function formatProbeTime(ts: Timestamp | undefined): string {
|
|
207
|
+
if (!ts || ts.seconds === ZERO) {
|
|
208
|
+
return "never";
|
|
209
|
+
}
|
|
210
|
+
return new Date(Number(ts.seconds) * 1000).toLocaleString(undefined, {
|
|
211
|
+
month: "short",
|
|
212
|
+
day: "numeric",
|
|
213
|
+
hour: "2-digit",
|
|
214
|
+
minute: "2-digit",
|
|
215
|
+
});
|
|
216
|
+
}
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
import { describe, it, expect, vi, afterEach } from "vitest";
|
|
2
|
+
import { cleanup, render, screen, waitFor } from "@testing-library/react";
|
|
3
|
+
import type { ReactNode } from "react";
|
|
4
|
+
import { create } from "@bufbuild/protobuf";
|
|
5
|
+
import { timestampFromDate } from "@bufbuild/protobuf/wkt";
|
|
6
|
+
import { StigmerError } from "@stigmer/sdk";
|
|
7
|
+
import {
|
|
8
|
+
ProviderStandingEntrySchema,
|
|
9
|
+
ProviderStandingViewSchema,
|
|
10
|
+
} from "@stigmer/protos/ai/stigmer/platform/providerstanding/v1/io_pb";
|
|
11
|
+
import { StigmerContext } from "../../context";
|
|
12
|
+
import { FetchCacheContext } from "../../internal/FetchCacheProvider";
|
|
13
|
+
import { ProviderStandingConsole } from "../ProviderStandingConsole";
|
|
14
|
+
|
|
15
|
+
function createMockStigmer(getStandingView: ReturnType<typeof vi.fn>) {
|
|
16
|
+
return {
|
|
17
|
+
providerStanding: { getStandingView },
|
|
18
|
+
} as never;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
function wrapper(client: unknown) {
|
|
22
|
+
return function Wrapper({ children }: { children: ReactNode }) {
|
|
23
|
+
return (
|
|
24
|
+
<FetchCacheContext.Provider value={null}>
|
|
25
|
+
<StigmerContext.Provider value={client as never}>
|
|
26
|
+
{children}
|
|
27
|
+
</StigmerContext.Provider>
|
|
28
|
+
</FetchCacheContext.Provider>
|
|
29
|
+
);
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
function entry(overrides: Record<string, unknown> = {}) {
|
|
34
|
+
return create(ProviderStandingEntrySchema, {
|
|
35
|
+
provider: "anthropic",
|
|
36
|
+
status: "healthy",
|
|
37
|
+
httpStatus: 200,
|
|
38
|
+
latencyMs: BigInt(842),
|
|
39
|
+
errorSummary: "",
|
|
40
|
+
checkedAt: timestampFromDate(new Date()),
|
|
41
|
+
...overrides,
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
function view(entries: ReturnType<typeof entry>[]) {
|
|
46
|
+
return create(ProviderStandingViewSchema, { providers: entries });
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
afterEach(() => {
|
|
50
|
+
cleanup();
|
|
51
|
+
vi.restoreAllMocks();
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
describe("ProviderStandingConsole", () => {
|
|
55
|
+
it("renders one card per provider with status, latency, and probe time", async () => {
|
|
56
|
+
const client = createMockStigmer(
|
|
57
|
+
vi.fn().mockResolvedValue(
|
|
58
|
+
view([
|
|
59
|
+
entry(),
|
|
60
|
+
entry({
|
|
61
|
+
provider: "openai",
|
|
62
|
+
status: "platform_billing",
|
|
63
|
+
httpStatus: 429,
|
|
64
|
+
latencyMs: BigInt(0),
|
|
65
|
+
errorSummary: "insufficient_quota: billing hard limit reached",
|
|
66
|
+
}),
|
|
67
|
+
]),
|
|
68
|
+
),
|
|
69
|
+
);
|
|
70
|
+
render(<ProviderStandingConsole />, { wrapper: wrapper(client) });
|
|
71
|
+
|
|
72
|
+
await waitFor(() => {
|
|
73
|
+
expect(screen.getByText("anthropic")).toBeTruthy();
|
|
74
|
+
});
|
|
75
|
+
expect(screen.getByText("Healthy")).toBeTruthy();
|
|
76
|
+
expect(screen.getByText("842ms")).toBeTruthy();
|
|
77
|
+
|
|
78
|
+
expect(screen.getByText("openai")).toBeTruthy();
|
|
79
|
+
expect(screen.getByText("Billing rejected")).toBeTruthy();
|
|
80
|
+
expect(screen.getByText("429")).toBeTruthy();
|
|
81
|
+
expect(
|
|
82
|
+
screen.getByText("insufficient_quota: billing hard limit reached"),
|
|
83
|
+
).toBeTruthy();
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
it("flags a verdict older than the probe-silence window as stale", async () => {
|
|
87
|
+
const fourHoursAgo = new Date(Date.now() - 4 * 60 * 60 * 1000);
|
|
88
|
+
const client = createMockStigmer(
|
|
89
|
+
vi.fn().mockResolvedValue(
|
|
90
|
+
view([entry({ checkedAt: timestampFromDate(fourHoursAgo) })]),
|
|
91
|
+
),
|
|
92
|
+
);
|
|
93
|
+
render(<ProviderStandingConsole />, { wrapper: wrapper(client) });
|
|
94
|
+
|
|
95
|
+
await waitFor(() => {
|
|
96
|
+
expect(screen.getByText(/— stale/)).toBeTruthy();
|
|
97
|
+
});
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
it("degrades an unknown future status label to a muted badge with the raw label", async () => {
|
|
101
|
+
const client = createMockStigmer(
|
|
102
|
+
vi.fn().mockResolvedValue(view([entry({ status: "rate_limited" })])),
|
|
103
|
+
);
|
|
104
|
+
render(<ProviderStandingConsole />, { wrapper: wrapper(client) });
|
|
105
|
+
|
|
106
|
+
await waitFor(() => {
|
|
107
|
+
expect(screen.getByText("rate_limited")).toBeTruthy();
|
|
108
|
+
});
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
it("shows the designed access notice on permission denied, not a raw RPC error", async () => {
|
|
112
|
+
const client = createMockStigmer(
|
|
113
|
+
vi.fn().mockRejectedValue(
|
|
114
|
+
new StigmerError("permission-denied", "only platform operators can view provider standing", 7),
|
|
115
|
+
),
|
|
116
|
+
);
|
|
117
|
+
render(<ProviderStandingConsole />, { wrapper: wrapper(client) });
|
|
118
|
+
|
|
119
|
+
await waitFor(() => {
|
|
120
|
+
expect(screen.getByText("Platform operator access required")).toBeTruthy();
|
|
121
|
+
});
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
it("shows the error message for non-permission failures", async () => {
|
|
125
|
+
const client = createMockStigmer(
|
|
126
|
+
vi.fn().mockRejectedValue(new StigmerError("internal", "standing lookup failed", 13)),
|
|
127
|
+
);
|
|
128
|
+
render(<ProviderStandingConsole />, { wrapper: wrapper(client) });
|
|
129
|
+
|
|
130
|
+
await waitFor(() => {
|
|
131
|
+
expect(screen.getByRole("alert")).toBeTruthy();
|
|
132
|
+
});
|
|
133
|
+
});
|
|
134
|
+
|
|
135
|
+
it("explains the empty state before the probe's first pass", async () => {
|
|
136
|
+
const client = createMockStigmer(vi.fn().mockResolvedValue(view([])));
|
|
137
|
+
render(<ProviderStandingConsole />, { wrapper: wrapper(client) });
|
|
138
|
+
|
|
139
|
+
await waitFor(() => {
|
|
140
|
+
expect(screen.getByText(/No probe verdicts recorded yet/)).toBeTruthy();
|
|
141
|
+
});
|
|
142
|
+
});
|
|
143
|
+
});
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
// Data hooks
|
|
2
|
+
export { useProviderStanding } from "./useProviderStanding.js";
|
|
3
|
+
export type { UseProviderStandingReturn } from "./useProviderStanding.js";
|
|
4
|
+
|
|
5
|
+
// Styled components
|
|
6
|
+
export { ProviderStandingConsole } from "./ProviderStandingConsole.js";
|
|
7
|
+
export type { ProviderStandingConsoleProps } from "./ProviderStandingConsole.js";
|
|
8
|
+
export { ProviderStandingAccessNotice } from "./ProviderStandingAccessNotice.js";
|