@stigmer/react 3.2.3 → 3.4.0
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/ReviewStep.d.ts.map +1 -1
- package/agent/steps/ReviewStep.js +2 -3
- package/agent/steps/ReviewStep.js.map +1 -1
- package/billing/index.d.ts.map +1 -1
- package/billing/index.js +4 -0
- package/billing/index.js.map +1 -1
- package/channel/AgentChannelsPanel.d.ts.map +1 -1
- package/channel/AgentChannelsPanel.js +11 -5
- package/channel/AgentChannelsPanel.js.map +1 -1
- package/composer/SessionComposer.d.ts +1 -1
- package/cursor-accounts/CursorAccountEditor.d.ts +34 -0
- package/cursor-accounts/CursorAccountEditor.d.ts.map +1 -0
- package/cursor-accounts/CursorAccountEditor.js +67 -0
- package/cursor-accounts/CursorAccountEditor.js.map +1 -0
- package/cursor-accounts/CursorAccountsAccessNotice.d.ts +11 -0
- package/cursor-accounts/CursorAccountsAccessNotice.d.ts.map +1 -0
- package/cursor-accounts/CursorAccountsAccessNotice.js +14 -0
- package/cursor-accounts/CursorAccountsAccessNotice.js.map +1 -0
- package/cursor-accounts/CursorAccountsConsole.d.ts +32 -0
- package/cursor-accounts/CursorAccountsConsole.d.ts.map +1 -0
- package/cursor-accounts/CursorAccountsConsole.js +169 -0
- package/cursor-accounts/CursorAccountsConsole.js.map +1 -0
- package/cursor-accounts/MemberCoverageTable.d.ts +29 -0
- package/cursor-accounts/MemberCoverageTable.d.ts.map +1 -0
- package/cursor-accounts/MemberCoverageTable.js +150 -0
- package/cursor-accounts/MemberCoverageTable.js.map +1 -0
- package/cursor-accounts/MemberKeysPanel.d.ts +25 -0
- package/cursor-accounts/MemberKeysPanel.d.ts.map +1 -0
- package/cursor-accounts/MemberKeysPanel.js +115 -0
- package/cursor-accounts/MemberKeysPanel.js.map +1 -0
- package/cursor-accounts/badges.d.ts +9 -0
- package/cursor-accounts/badges.d.ts.map +1 -0
- package/cursor-accounts/badges.js +10 -0
- package/cursor-accounts/badges.js.map +1 -0
- package/cursor-accounts/cursor-account-coverage.d.ts +41 -0
- package/cursor-accounts/cursor-account-coverage.d.ts.map +1 -0
- package/cursor-accounts/cursor-account-coverage.js +26 -0
- package/cursor-accounts/cursor-account-coverage.js.map +1 -0
- package/cursor-accounts/cursor-account-format.d.ts +23 -0
- package/cursor-accounts/cursor-account-format.d.ts.map +1 -0
- package/cursor-accounts/cursor-account-format.js +41 -0
- package/cursor-accounts/cursor-account-format.js.map +1 -0
- package/cursor-accounts/index.d.ts +18 -0
- package/cursor-accounts/index.d.ts.map +1 -0
- package/cursor-accounts/index.js +13 -0
- package/cursor-accounts/index.js.map +1 -0
- package/cursor-accounts/useCursorAccountView.d.ts +30 -0
- package/cursor-accounts/useCursorAccountView.d.ts.map +1 -0
- package/cursor-accounts/useCursorAccountView.js +25 -0
- package/cursor-accounts/useCursorAccountView.js.map +1 -0
- package/cursor-accounts/useCursorAccounts.d.ts +33 -0
- package/cursor-accounts/useCursorAccounts.d.ts.map +1 -0
- package/cursor-accounts/useCursorAccounts.js +25 -0
- package/cursor-accounts/useCursorAccounts.js.map +1 -0
- package/cursor-accounts/useCursorMemberKeyActions.d.ts +49 -0
- package/cursor-accounts/useCursorMemberKeyActions.d.ts.map +1 -0
- package/cursor-accounts/useCursorMemberKeyActions.js +38 -0
- package/cursor-accounts/useCursorMemberKeyActions.js.map +1 -0
- package/cursor-accounts/useDeleteCursorAccount.d.ts +30 -0
- package/cursor-accounts/useDeleteCursorAccount.d.ts.map +1 -0
- package/cursor-accounts/useDeleteCursorAccount.js +32 -0
- package/cursor-accounts/useDeleteCursorAccount.js.map +1 -0
- package/cursor-accounts/useSyncCursorAccount.d.ts +23 -0
- package/cursor-accounts/useSyncCursorAccount.d.ts.map +1 -0
- package/cursor-accounts/useSyncCursorAccount.js +31 -0
- package/cursor-accounts/useSyncCursorAccount.js.map +1 -0
- package/cursor-accounts/useUpsertCursorAccount.d.ts +26 -0
- package/cursor-accounts/useUpsertCursorAccount.d.ts.map +1 -0
- package/cursor-accounts/useUpsertCursorAccount.js +34 -0
- package/cursor-accounts/useUpsertCursorAccount.js.map +1 -0
- package/datastore/CollectionRecordsBrowser.d.ts +34 -0
- package/datastore/CollectionRecordsBrowser.d.ts.map +1 -0
- package/datastore/CollectionRecordsBrowser.js +223 -0
- package/datastore/CollectionRecordsBrowser.js.map +1 -0
- package/datastore/CollectionSchemaView.d.ts +29 -0
- package/datastore/CollectionSchemaView.d.ts.map +1 -0
- package/datastore/CollectionSchemaView.js +93 -0
- package/datastore/CollectionSchemaView.js.map +1 -0
- package/datastore/DatastoreDetailView.d.ts +44 -0
- package/datastore/DatastoreDetailView.d.ts.map +1 -0
- package/datastore/DatastoreDetailView.js +76 -0
- package/datastore/DatastoreDetailView.js.map +1 -0
- package/datastore/DatastoreSyncReport.d.ts +19 -0
- package/datastore/DatastoreSyncReport.d.ts.map +1 -0
- package/datastore/DatastoreSyncReport.js +45 -0
- package/datastore/DatastoreSyncReport.js.map +1 -0
- package/datastore/DeleteDatastoreDialog.d.ts +35 -0
- package/datastore/DeleteDatastoreDialog.d.ts.map +1 -0
- package/datastore/DeleteDatastoreDialog.js +90 -0
- package/datastore/DeleteDatastoreDialog.js.map +1 -0
- package/datastore/FieldValueControl.d.ts +55 -0
- package/datastore/FieldValueControl.d.ts.map +1 -0
- package/datastore/FieldValueControl.js +138 -0
- package/datastore/FieldValueControl.js.map +1 -0
- package/datastore/RecordFilterBuilder.d.ts +37 -0
- package/datastore/RecordFilterBuilder.d.ts.map +1 -0
- package/datastore/RecordFilterBuilder.js +122 -0
- package/datastore/RecordFilterBuilder.js.map +1 -0
- package/datastore/RecordFormPanel.d.ts +45 -0
- package/datastore/RecordFormPanel.d.ts.map +1 -0
- package/datastore/RecordFormPanel.js +215 -0
- package/datastore/RecordFormPanel.js.map +1 -0
- package/datastore/index.d.ts +43 -0
- package/datastore/index.d.ts.map +1 -0
- package/datastore/index.js +22 -0
- package/datastore/index.js.map +1 -0
- package/datastore/recordFilter.d.ts +62 -0
- package/datastore/recordFilter.d.ts.map +1 -0
- package/datastore/recordFilter.js +104 -0
- package/datastore/recordFilter.js.map +1 -0
- package/datastore/recordValues.d.ts +85 -0
- package/datastore/recordValues.d.ts.map +1 -0
- package/datastore/recordValues.js +282 -0
- package/datastore/recordValues.js.map +1 -0
- package/datastore/useDatastore.d.ts +39 -0
- package/datastore/useDatastore.d.ts.map +1 -0
- package/datastore/useDatastore.js +44 -0
- package/datastore/useDatastore.js.map +1 -0
- package/datastore/useDatastoreCount.d.ts +48 -0
- package/datastore/useDatastoreCount.d.ts.map +1 -0
- package/datastore/useDatastoreCount.js +27 -0
- package/datastore/useDatastoreCount.js.map +1 -0
- package/datastore/useDatastoreDescription.d.ts +54 -0
- package/datastore/useDatastoreDescription.d.ts.map +1 -0
- package/datastore/useDatastoreDescription.js +50 -0
- package/datastore/useDatastoreDescription.js.map +1 -0
- package/datastore/useDatastoreList.d.ts +57 -0
- package/datastore/useDatastoreList.d.ts.map +1 -0
- package/datastore/useDatastoreList.js +29 -0
- package/datastore/useDatastoreList.js.map +1 -0
- package/datastore/useDatastoreSearch.d.ts +19 -0
- package/datastore/useDatastoreSearch.d.ts.map +1 -0
- package/datastore/useDatastoreSearch.js +22 -0
- package/datastore/useDatastoreSearch.js.map +1 -0
- package/datastore/useDeleteDatastore.d.ts +53 -0
- package/datastore/useDeleteDatastore.d.ts.map +1 -0
- package/datastore/useDeleteDatastore.js +40 -0
- package/datastore/useDeleteDatastore.js.map +1 -0
- package/datastore/useDeleteRecord.d.ts +34 -0
- package/datastore/useDeleteRecord.d.ts.map +1 -0
- package/datastore/useDeleteRecord.js +43 -0
- package/datastore/useDeleteRecord.js.map +1 -0
- package/datastore/useInsertRecord.d.ts +50 -0
- package/datastore/useInsertRecord.d.ts.map +1 -0
- package/datastore/useInsertRecord.js +55 -0
- package/datastore/useInsertRecord.js.map +1 -0
- package/datastore/useRecordCollection.d.ts +104 -0
- package/datastore/useRecordCollection.d.ts.map +1 -0
- package/datastore/useRecordCollection.js +136 -0
- package/datastore/useRecordCollection.js.map +1 -0
- package/datastore/useRecordList.d.ts +66 -0
- package/datastore/useRecordList.d.ts.map +1 -0
- package/datastore/useRecordList.js +58 -0
- package/datastore/useRecordList.js.map +1 -0
- package/datastore/useUpdateRecord.d.ts +52 -0
- package/datastore/useUpdateRecord.d.ts.map +1 -0
- package/datastore/useUpdateRecord.js +55 -0
- package/datastore/useUpdateRecord.js.map +1 -0
- package/environment/EnvironmentListPanel.d.ts.map +1 -1
- package/environment/EnvironmentListPanel.js +12 -7
- package/environment/EnvironmentListPanel.js.map +1 -1
- package/execution/ExecutionProgress.d.ts.map +1 -1
- package/execution/ExecutionProgress.js +13 -4
- package/execution/ExecutionProgress.js.map +1 -1
- package/execution/MessageThread.d.ts.map +1 -1
- package/execution/MessageThread.js +10 -2
- package/execution/MessageThread.js.map +1 -1
- package/execution/useCreateAgentExecution.d.ts +31 -1
- package/execution/useCreateAgentExecution.d.ts.map +1 -1
- package/execution/useCreateAgentExecution.js +2 -0
- package/execution/useCreateAgentExecution.js.map +1 -1
- package/iam-policy/index.d.ts +1 -1
- package/iam-policy/index.d.ts.map +1 -1
- package/iam-policy/index.js.map +1 -1
- package/iam-policy/useCheckPermission.d.ts +32 -11
- package/iam-policy/useCheckPermission.d.ts.map +1 -1
- package/iam-policy/useCheckPermission.js +24 -19
- package/iam-policy/useCheckPermission.js.map +1 -1
- package/index.d.ts +12 -4
- package/index.d.ts.map +1 -1
- package/index.js +18 -3
- package/index.js.map +1 -1
- package/internal/form-primitives.d.ts +10 -0
- package/internal/form-primitives.d.ts.map +1 -0
- package/internal/form-primitives.js +15 -0
- package/internal/form-primitives.js.map +1 -0
- package/library/index.d.ts +0 -7
- package/library/index.d.ts.map +1 -1
- package/library/index.js +0 -4
- package/library/index.js.map +1 -1
- package/library/useApplyResource.d.ts +12 -12
- package/library/useApplyResource.d.ts.map +1 -1
- package/library/useApplyResource.js +16 -25
- package/library/useApplyResource.js.map +1 -1
- package/library/useExportResource.d.ts +13 -9
- package/library/useExportResource.d.ts.map +1 -1
- package/library/useExportResource.js +18 -36
- package/library/useExportResource.js.map +1 -1
- package/manifest/ApplyManifestDialog.d.ts +48 -0
- package/manifest/ApplyManifestDialog.d.ts.map +1 -0
- package/manifest/ApplyManifestDialog.js +135 -0
- package/manifest/ApplyManifestDialog.js.map +1 -0
- package/manifest/EditResourceYamlDialog.d.ts +51 -0
- package/manifest/EditResourceYamlDialog.d.ts.map +1 -0
- package/manifest/EditResourceYamlDialog.js +104 -0
- package/manifest/EditResourceYamlDialog.js.map +1 -0
- package/manifest/RedactedSecretsNotice.d.ts +14 -0
- package/manifest/RedactedSecretsNotice.d.ts.map +1 -0
- package/manifest/RedactedSecretsNotice.js +14 -0
- package/manifest/RedactedSecretsNotice.js.map +1 -0
- package/manifest/YamlEditor.d.ts +44 -0
- package/manifest/YamlEditor.d.ts.map +1 -0
- package/manifest/YamlEditor.js +216 -0
- package/manifest/YamlEditor.js.map +1 -0
- package/manifest/index.d.ts +13 -0
- package/manifest/index.d.ts.map +1 -0
- package/manifest/index.js +13 -0
- package/manifest/index.js.map +1 -0
- package/manifest/useApplyManifest.d.ts +82 -0
- package/manifest/useApplyManifest.d.ts.map +1 -0
- package/manifest/useApplyManifest.js +180 -0
- package/manifest/useApplyManifest.js.map +1 -0
- package/manifest/useEditResourceYaml.d.ts +106 -0
- package/manifest/useEditResourceYaml.d.ts.map +1 -0
- package/manifest/useEditResourceYaml.js +168 -0
- package/manifest/useEditResourceYaml.js.map +1 -0
- package/mcp-server/steps/ReviewStep.d.ts.map +1 -1
- package/mcp-server/steps/ReviewStep.js +2 -3
- package/mcp-server/steps/ReviewStep.js.map +1 -1
- package/package.json +4 -4
- package/pricing-governance/BaselineEditor.d.ts +9 -0
- package/pricing-governance/BaselineEditor.d.ts.map +1 -0
- package/pricing-governance/BaselineEditor.js +270 -0
- package/pricing-governance/BaselineEditor.js.map +1 -0
- package/pricing-governance/ModelCatalogPanel.d.ts +28 -0
- package/pricing-governance/ModelCatalogPanel.d.ts.map +1 -0
- package/pricing-governance/ModelCatalogPanel.js +102 -0
- package/pricing-governance/ModelCatalogPanel.js.map +1 -0
- package/pricing-governance/ModelGovernanceDetail.d.ts +8 -0
- package/pricing-governance/ModelGovernanceDetail.d.ts.map +1 -0
- package/pricing-governance/ModelGovernanceDetail.js +64 -0
- package/pricing-governance/ModelGovernanceDetail.js.map +1 -0
- package/pricing-governance/OperatorAccessNotice.d.ts +12 -0
- package/pricing-governance/OperatorAccessNotice.d.ts.map +1 -0
- package/pricing-governance/OperatorAccessNotice.js +15 -0
- package/pricing-governance/OperatorAccessNotice.js.map +1 -0
- package/pricing-governance/PricingGovernanceConsole.d.ts +57 -0
- package/pricing-governance/PricingGovernanceConsole.d.ts.map +1 -0
- package/pricing-governance/PricingGovernanceConsole.js +164 -0
- package/pricing-governance/PricingGovernanceConsole.js.map +1 -0
- package/pricing-governance/PricingGovernancePanel.d.ts +26 -0
- package/pricing-governance/PricingGovernancePanel.d.ts.map +1 -0
- package/pricing-governance/PricingGovernancePanel.js +64 -0
- package/pricing-governance/PricingGovernancePanel.js.map +1 -0
- package/pricing-governance/RetireConfirm.d.ts +9 -0
- package/pricing-governance/RetireConfirm.d.ts.map +1 -0
- package/pricing-governance/RetireConfirm.js +19 -0
- package/pricing-governance/RetireConfirm.js.map +1 -0
- package/pricing-governance/governance-primitives.d.ts +33 -0
- package/pricing-governance/governance-primitives.d.ts.map +1 -0
- package/pricing-governance/governance-primitives.js +43 -0
- package/pricing-governance/governance-primitives.js.map +1 -0
- package/pricing-governance/index.d.ts +19 -0
- package/pricing-governance/index.d.ts.map +1 -0
- package/pricing-governance/index.js +20 -0
- package/pricing-governance/index.js.map +1 -0
- package/pricing-governance/pricing-format.d.ts +12 -0
- package/pricing-governance/pricing-format.d.ts.map +1 -0
- package/pricing-governance/pricing-format.js +50 -0
- package/pricing-governance/pricing-format.js.map +1 -0
- package/pricing-governance/useDecidePricingOverride.d.ts +46 -0
- package/pricing-governance/useDecidePricingOverride.d.ts.map +1 -0
- package/pricing-governance/useDecidePricingOverride.js +44 -0
- package/pricing-governance/useDecidePricingOverride.js.map +1 -0
- package/pricing-governance/useModelGovernanceView.d.ts +103 -0
- package/pricing-governance/useModelGovernanceView.d.ts.map +1 -0
- package/pricing-governance/useModelGovernanceView.js +144 -0
- package/pricing-governance/useModelGovernanceView.js.map +1 -0
- package/pricing-governance/useModelPricingBaselines.d.ts +40 -0
- package/pricing-governance/useModelPricingBaselines.d.ts.map +1 -0
- package/pricing-governance/useModelPricingBaselines.js +32 -0
- package/pricing-governance/useModelPricingBaselines.js.map +1 -0
- package/pricing-governance/usePricingGovernance.d.ts +39 -0
- package/pricing-governance/usePricingGovernance.d.ts.map +1 -0
- package/pricing-governance/usePricingGovernance.js +31 -0
- package/pricing-governance/usePricingGovernance.js.map +1 -0
- package/pricing-governance/useRetireModelPricingBaseline.d.ts +31 -0
- package/pricing-governance/useRetireModelPricingBaseline.d.ts.map +1 -0
- package/pricing-governance/useRetireModelPricingBaseline.js +36 -0
- package/pricing-governance/useRetireModelPricingBaseline.js.map +1 -0
- package/pricing-governance/useUpsertModelPricingBaseline.d.ts +38 -0
- package/pricing-governance/useUpsertModelPricingBaseline.d.ts.map +1 -0
- package/pricing-governance/useUpsertModelPricingBaseline.js +37 -0
- package/pricing-governance/useUpsertModelPricingBaseline.js.map +1 -0
- package/resource-creation/templates/workflow-templates.js +4 -4
- package/session/useCreateSession.d.ts +28 -0
- package/session/useCreateSession.d.ts.map +1 -1
- package/session/useCreateSession.js +2 -1
- package/session/useCreateSession.js.map +1 -1
- package/session/useEditSessionPrep.js +3 -3
- package/session/useEditSessionPrep.js.map +1 -1
- package/session/useNewSessionFlow.d.ts +30 -0
- package/session/useNewSessionFlow.d.ts.map +1 -1
- package/session/useNewSessionFlow.js +7 -1
- package/session/useNewSessionFlow.js.map +1 -1
- package/session/useUpdateSession.d.ts +29 -10
- package/session/useUpdateSession.d.ts.map +1 -1
- package/session/useUpdateSession.js +29 -10
- package/session/useUpdateSession.js.map +1 -1
- package/settings/index.d.ts +2 -1
- package/settings/index.d.ts.map +1 -1
- package/settings/index.js +2 -1
- package/settings/index.js.map +1 -1
- package/settings/settings-nav.d.ts +22 -0
- package/settings/settings-nav.d.ts.map +1 -1
- package/settings/settings-nav.js +32 -1
- package/settings/settings-nav.js.map +1 -1
- package/settings/useSettingsNavGroups.d.ts +29 -0
- package/settings/useSettingsNavGroups.d.ts.map +1 -0
- package/settings/useSettingsNavGroups.js +61 -0
- package/settings/useSettingsNavGroups.js.map +1 -0
- package/src/agent/steps/ReviewStep.tsx +2 -3
- package/src/billing/index.ts +5 -0
- package/src/channel/AgentChannelsPanel.tsx +27 -1
- package/src/composer/SessionComposer.tsx +1 -1
- package/src/cursor-accounts/CursorAccountEditor.tsx +229 -0
- package/src/cursor-accounts/CursorAccountsAccessNotice.tsx +36 -0
- package/src/cursor-accounts/CursorAccountsConsole.tsx +454 -0
- package/src/cursor-accounts/MemberCoverageTable.tsx +439 -0
- package/src/cursor-accounts/MemberKeysPanel.tsx +278 -0
- package/src/cursor-accounts/__tests__/CursorAccountsConsole.test.tsx +680 -0
- package/src/cursor-accounts/__tests__/cursor-account-coverage.test.ts +73 -0
- package/src/cursor-accounts/badges.tsx +26 -0
- package/src/cursor-accounts/cursor-account-coverage.ts +71 -0
- package/src/cursor-accounts/cursor-account-format.ts +45 -0
- package/src/cursor-accounts/index.ts +29 -0
- package/src/cursor-accounts/useCursorAccountView.ts +49 -0
- package/src/cursor-accounts/useCursorAccounts.ts +49 -0
- package/src/cursor-accounts/useCursorMemberKeyActions.ts +106 -0
- package/src/cursor-accounts/useDeleteCursorAccount.ts +62 -0
- package/src/cursor-accounts/useSyncCursorAccount.ts +54 -0
- package/src/cursor-accounts/useUpsertCursorAccount.ts +57 -0
- package/src/datastore/CollectionRecordsBrowser.tsx +570 -0
- package/src/datastore/CollectionSchemaView.tsx +247 -0
- package/src/datastore/DatastoreDetailView.tsx +201 -0
- package/src/datastore/DatastoreSyncReport.tsx +105 -0
- package/src/datastore/DeleteDatastoreDialog.tsx +202 -0
- package/src/datastore/FieldValueControl.tsx +289 -0
- package/src/datastore/RecordFilterBuilder.tsx +422 -0
- package/src/datastore/RecordFormPanel.tsx +432 -0
- package/src/datastore/__tests__/CollectionRecordsBrowser.test.tsx +245 -0
- package/src/datastore/__tests__/DeleteDatastoreDialog.test.tsx +133 -0
- package/src/datastore/__tests__/FieldValueControl.test.tsx +160 -0
- package/src/datastore/__tests__/RecordFilterBuilder.test.tsx +155 -0
- package/src/datastore/__tests__/RecordFormPanel.test.tsx +227 -0
- package/src/datastore/__tests__/recordFilter.test.ts +169 -0
- package/src/datastore/__tests__/recordMutations.test.tsx +195 -0
- package/src/datastore/__tests__/recordValues.test.ts +359 -0
- package/src/datastore/__tests__/schemaAndSyncViews.test.tsx +142 -0
- package/src/datastore/__tests__/useDatastoreDescription.test.tsx +143 -0
- package/src/datastore/__tests__/useRecordCollection.test.tsx +250 -0
- package/src/datastore/__tests__/useRecordList.test.tsx +85 -0
- package/src/datastore/index.ts +111 -0
- package/src/datastore/recordFilter.ts +154 -0
- package/src/datastore/recordValues.ts +327 -0
- package/src/datastore/useDatastore.ts +67 -0
- package/src/datastore/useDatastoreCount.ts +67 -0
- package/src/datastore/useDatastoreDescription.ts +90 -0
- package/src/datastore/useDatastoreList.ts +79 -0
- package/src/datastore/useDatastoreSearch.ts +39 -0
- package/src/datastore/useDeleteDatastore.ts +87 -0
- package/src/datastore/useDeleteRecord.ts +77 -0
- package/src/datastore/useInsertRecord.ts +92 -0
- package/src/datastore/useRecordCollection.ts +256 -0
- package/src/datastore/useRecordList.ts +131 -0
- package/src/datastore/useUpdateRecord.ts +95 -0
- package/src/environment/EnvironmentListPanel.tsx +24 -0
- package/src/execution/ExecutionProgress.tsx +14 -4
- package/src/execution/MessageThread.tsx +10 -2
- package/src/execution/__tests__/ExecutionProgress.test.tsx +67 -0
- package/src/execution/__tests__/MessageThread.test.tsx +44 -0
- package/src/execution/__tests__/useArtifactInspection.test.tsx +12 -2
- package/src/execution/__tests__/useCreateAgentExecution.test.tsx +86 -0
- package/src/execution/useCreateAgentExecution.ts +41 -6
- package/src/iam-policy/__tests__/useCheckPermission.test.tsx +221 -0
- package/src/iam-policy/index.ts +1 -0
- package/src/iam-policy/useCheckPermission.ts +45 -19
- package/src/index.ts +172 -14
- package/src/internal/form-primitives.tsx +40 -0
- package/src/library/index.ts +0 -20
- package/src/library/useApplyResource.ts +27 -34
- package/src/library/useExportResource.ts +21 -40
- package/src/manifest/ApplyManifestDialog.tsx +315 -0
- package/src/manifest/EditResourceYamlDialog.tsx +265 -0
- package/src/manifest/RedactedSecretsNotice.tsx +30 -0
- package/src/manifest/YamlEditor.tsx +272 -0
- package/src/manifest/__tests__/EditResourceYamlDialog.test.tsx +118 -0
- package/src/manifest/__tests__/useApplyManifest.test.tsx +237 -0
- package/src/manifest/__tests__/useEditResourceYaml.test.tsx +252 -0
- package/src/manifest/index.ts +33 -0
- package/src/manifest/useApplyManifest.ts +270 -0
- package/src/manifest/useEditResourceYaml.ts +273 -0
- package/src/mcp-server/steps/ReviewStep.tsx +2 -3
- package/src/pricing-governance/BaselineEditor.tsx +652 -0
- package/src/pricing-governance/ModelCatalogPanel.tsx +283 -0
- package/src/pricing-governance/ModelGovernanceDetail.tsx +289 -0
- package/src/pricing-governance/OperatorAccessNotice.tsx +32 -0
- package/src/pricing-governance/PricingGovernanceConsole.tsx +465 -0
- package/src/pricing-governance/PricingGovernancePanel.tsx +166 -0
- package/src/pricing-governance/RetireConfirm.tsx +82 -0
- package/src/pricing-governance/__tests__/ModelCatalogPanel.test.tsx +253 -0
- package/src/pricing-governance/__tests__/PricingGovernanceConsole.test.tsx +410 -0
- package/src/pricing-governance/__tests__/useModelGovernanceView.test.tsx +308 -0
- package/src/pricing-governance/governance-primitives.tsx +133 -0
- package/src/pricing-governance/index.ts +50 -0
- package/src/pricing-governance/pricing-format.ts +53 -0
- package/src/pricing-governance/useDecidePricingOverride.ts +78 -0
- package/src/pricing-governance/useModelGovernanceView.ts +290 -0
- package/src/pricing-governance/useModelPricingBaselines.ts +69 -0
- package/src/pricing-governance/usePricingGovernance.ts +57 -0
- package/src/pricing-governance/useRetireModelPricingBaseline.ts +65 -0
- package/src/pricing-governance/useUpsertModelPricingBaseline.ts +72 -0
- package/src/resource-creation/templates/workflow-templates.ts +4 -4
- package/src/session/__tests__/useCreateSession.test.tsx +94 -0
- package/src/session/__tests__/useNewSessionFlow.test.tsx +33 -0
- package/src/session/useCreateSession.ts +30 -0
- package/src/session/useEditSessionPrep.ts +3 -3
- package/src/session/useNewSessionFlow.ts +45 -1
- package/src/session/useUpdateSession.ts +29 -10
- package/src/settings/__tests__/useSettingsNavGroups.test.tsx +138 -0
- package/src/settings/index.ts +5 -1
- package/src/settings/settings-nav.ts +43 -0
- package/src/settings/useSettingsNavGroups.ts +81 -0
- package/src/workflow/WorkflowYamlEditor.tsx +6 -270
- package/styles.css +1 -1
- package/workflow/CanvasTransitionEdge.d.ts +1 -1
- package/workflow/WorkflowYamlEditor.d.ts +2 -42
- package/workflow/WorkflowYamlEditor.d.ts.map +1 -1
- package/workflow/WorkflowYamlEditor.js +5 -214
- package/workflow/WorkflowYamlEditor.js.map +1 -1
- package/library/ImportResourceDialog.d.ts +0 -43
- package/library/ImportResourceDialog.d.ts.map +0 -1
- package/library/ImportResourceDialog.js +0 -90
- package/library/ImportResourceDialog.js.map +0 -1
- package/library/parse-resource-yaml.d.ts +0 -63
- package/library/parse-resource-yaml.d.ts.map +0 -1
- package/library/parse-resource-yaml.js +0 -407
- package/library/parse-resource-yaml.js.map +0 -1
- package/library/serialize-resource-yaml.d.ts +0 -103
- package/library/serialize-resource-yaml.d.ts.map +0 -1
- package/library/serialize-resource-yaml.js +0 -565
- package/library/serialize-resource-yaml.js.map +0 -1
- package/library/useImportResource.d.ts +0 -84
- package/library/useImportResource.d.ts.map +0 -1
- package/library/useImportResource.js +0 -188
- package/library/useImportResource.js.map +0 -1
- package/src/library/ImportResourceDialog.tsx +0 -227
- package/src/library/parse-resource-yaml.ts +0 -630
- package/src/library/serialize-resource-yaml.ts +0 -756
- package/src/library/useImportResource.ts +0 -253
|
@@ -334,6 +334,39 @@ describe("useNewSessionFlow", () => {
|
|
|
334
334
|
expect(execInput.sessionSpec.harness).toBe("cursor");
|
|
335
335
|
});
|
|
336
336
|
|
|
337
|
+
it("forwards metadata and sessionContext verbatim in the sessionSpec", async () => {
|
|
338
|
+
// The typed-wins merge onto the reserved key happens downstream in
|
|
339
|
+
// useCreateAgentExecution (covered by its own tests); the flow's job
|
|
340
|
+
// is faithful forwarding.
|
|
341
|
+
const opts = {
|
|
342
|
+
...defaultOptions(),
|
|
343
|
+
metadata: { "acme/tenant": "t-1" },
|
|
344
|
+
sessionContext: "Role: platform admin",
|
|
345
|
+
};
|
|
346
|
+
const { result } = renderHook(() => useNewSessionFlow(opts), { wrapper: createWrapper() });
|
|
347
|
+
|
|
348
|
+
await act(async () => {
|
|
349
|
+
await result.current.submit("Hello");
|
|
350
|
+
});
|
|
351
|
+
|
|
352
|
+
const execInput = mockCreateExecution.mock.calls[0][0];
|
|
353
|
+
expect(execInput.sessionSpec.metadata).toEqual({ "acme/tenant": "t-1" });
|
|
354
|
+
expect(execInput.sessionSpec.sessionContext).toBe("Role: platform admin");
|
|
355
|
+
});
|
|
356
|
+
|
|
357
|
+
it("leaves metadata and sessionContext undefined when not provided", async () => {
|
|
358
|
+
const opts = defaultOptions();
|
|
359
|
+
const { result } = renderHook(() => useNewSessionFlow(opts), { wrapper: createWrapper() });
|
|
360
|
+
|
|
361
|
+
await act(async () => {
|
|
362
|
+
await result.current.submit("Hello");
|
|
363
|
+
});
|
|
364
|
+
|
|
365
|
+
const execInput = mockCreateExecution.mock.calls[0][0];
|
|
366
|
+
expect(execInput.sessionSpec.metadata).toBeUndefined();
|
|
367
|
+
expect(execInput.sessionSpec.sessionContext).toBeUndefined();
|
|
368
|
+
});
|
|
369
|
+
|
|
337
370
|
it("calls onSessionCreated with the server-assigned session id", async () => {
|
|
338
371
|
const opts = defaultOptions();
|
|
339
372
|
const { result } = renderHook(() => useNewSessionFlow(opts), { wrapper: createWrapper() });
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
import { useCallback, useState } from "react";
|
|
4
4
|
import {
|
|
5
5
|
PENDING_SUBJECT,
|
|
6
|
+
mergeSessionContext,
|
|
6
7
|
type McpServerUsageInput,
|
|
7
8
|
type ResourceRef,
|
|
8
9
|
type WorkspaceEntryInput,
|
|
@@ -25,6 +26,34 @@ export interface SharedSessionFields {
|
|
|
25
26
|
readonly mcpServerUsages?: McpServerUsageInput[];
|
|
26
27
|
/** Skill references to enable for executions in this session. */
|
|
27
28
|
readonly skillRefs?: ResourceRef[];
|
|
29
|
+
/**
|
|
30
|
+
* Custom key-value pairs stored on `SessionSpec.metadata`.
|
|
31
|
+
*
|
|
32
|
+
* A passthrough for embedder-owned keys (correlation IDs, tenant tags)
|
|
33
|
+
* and for platform-reserved `stigmer.ai/*` keys set explicitly. For the
|
|
34
|
+
* common case — standing user context injected into the agent's prompt —
|
|
35
|
+
* prefer the typed {@link sessionContext} field, which maps onto the
|
|
36
|
+
* reserved `stigmer.ai/session-context` key and wins over a raw entry
|
|
37
|
+
* under that key when both are provided.
|
|
38
|
+
*/
|
|
39
|
+
readonly metadata?: Record<string, string>;
|
|
40
|
+
/**
|
|
41
|
+
* Standing, per-user context the agent receives on every turn but the
|
|
42
|
+
* conversation UI never renders — who the caller is, their experience
|
|
43
|
+
* level, their standing instructions (stigmer/stigmer#286).
|
|
44
|
+
*
|
|
45
|
+
* Stored on `SessionSpec.metadata` under `stigmer.ai/session-context`;
|
|
46
|
+
* the agent runner injects it into the system prompt as already-known
|
|
47
|
+
* background, so agents can greet the user by name and calibrate
|
|
48
|
+
* depth/defaults from the first turn without a visible context preamble.
|
|
49
|
+
*
|
|
50
|
+
* Personalization, not authorization: anyone who can create the session
|
|
51
|
+
* can set this (the same trust level as authoring the first message).
|
|
52
|
+
* Hidden from the conversation thread, not from the API — `session.get`
|
|
53
|
+
* returns it, so never put secrets here; secrets belong in `runtimeEnv`
|
|
54
|
+
* or Environment resources. Large values bloat every prompt.
|
|
55
|
+
*/
|
|
56
|
+
readonly sessionContext?: string;
|
|
28
57
|
/**
|
|
29
58
|
* Execution harness for this session.
|
|
30
59
|
*
|
|
@@ -172,6 +201,7 @@ export function useCreateSession(): UseCreateSessionReturn {
|
|
|
172
201
|
workspaceEntries: input.workspaceEntries,
|
|
173
202
|
mcpServerUsages: input.mcpServerUsages,
|
|
174
203
|
skillRefs: input.skillRefs,
|
|
204
|
+
metadata: mergeSessionContext(input.metadata, input.sessionContext),
|
|
175
205
|
agentInstanceId: resolvedInstanceId,
|
|
176
206
|
harness: input.harness ? toProtoHarness(input.harness) : undefined,
|
|
177
207
|
executionTarget: resolvedTarget
|
|
@@ -7,7 +7,7 @@ import { useStigmer } from "../hooks.js";
|
|
|
7
7
|
import { useAgent } from "../agent/index.js";
|
|
8
8
|
import { useMcpServer } from "../mcp-server/index.js";
|
|
9
9
|
import { useSkill } from "../skill/index.js";
|
|
10
|
-
import {
|
|
10
|
+
import { serializeManifest } from "@stigmer/sdk";
|
|
11
11
|
import type { DraftResourceType } from "./draft.js";
|
|
12
12
|
|
|
13
13
|
/** Return value of {@link useEditSessionPrep}. */
|
|
@@ -64,7 +64,7 @@ export function useEditSessionPrep(
|
|
|
64
64
|
if (draftType === "agent" && editAgent) {
|
|
65
65
|
built.current = true;
|
|
66
66
|
try {
|
|
67
|
-
const yaml =
|
|
67
|
+
const yaml = serializeManifest(editAgent);
|
|
68
68
|
const slug = editAgent.metadata?.slug ?? "agent";
|
|
69
69
|
setFiles([new File([yaml], `${slug}.yaml`, { type: "text/yaml" })]);
|
|
70
70
|
} catch {
|
|
@@ -75,7 +75,7 @@ export function useEditSessionPrep(
|
|
|
75
75
|
if (draftType === "mcp-server" && editMcpServer) {
|
|
76
76
|
built.current = true;
|
|
77
77
|
try {
|
|
78
|
-
const yaml =
|
|
78
|
+
const yaml = serializeManifest(editMcpServer);
|
|
79
79
|
const slug = editMcpServer.metadata?.slug ?? "mcp-server";
|
|
80
80
|
setFiles([new File([yaml], `${slug}.yaml`, { type: "text/yaml" })]);
|
|
81
81
|
} catch {
|
|
@@ -111,6 +111,36 @@ export interface UseNewSessionFlowOptions {
|
|
|
111
111
|
* @default "integrator"
|
|
112
112
|
*/
|
|
113
113
|
readonly audience?: SessionAudience;
|
|
114
|
+
/**
|
|
115
|
+
* Custom key-value pairs stored on the created session's
|
|
116
|
+
* `SessionSpec.metadata`.
|
|
117
|
+
*
|
|
118
|
+
* A passthrough for embedder-owned keys (correlation IDs, tenant tags)
|
|
119
|
+
* and for platform-reserved `stigmer.ai/*` keys set explicitly. For the
|
|
120
|
+
* common case — standing user context injected into the agent's prompt —
|
|
121
|
+
* prefer the typed {@link sessionContext} option, which maps onto the
|
|
122
|
+
* reserved `stigmer.ai/session-context` key and wins over a raw entry
|
|
123
|
+
* under that key when both are provided.
|
|
124
|
+
*/
|
|
125
|
+
readonly metadata?: Record<string, string>;
|
|
126
|
+
/**
|
|
127
|
+
* Standing, per-user context the agent receives on every turn but the
|
|
128
|
+
* conversation UI never renders — who the caller is, their experience
|
|
129
|
+
* level, their standing instructions (stigmer/stigmer#286).
|
|
130
|
+
*
|
|
131
|
+
* Stored on the created session's `SessionSpec.metadata` under
|
|
132
|
+
* `stigmer.ai/session-context`; the agent runner injects it into the
|
|
133
|
+
* system prompt as already-known background, so agents can greet the
|
|
134
|
+
* user by name and calibrate depth/defaults from the first turn without
|
|
135
|
+
* a visible context preamble.
|
|
136
|
+
*
|
|
137
|
+
* Personalization, not authorization: anyone who can create the session
|
|
138
|
+
* can set this (the same trust level as authoring the first message).
|
|
139
|
+
* Hidden from the conversation thread, not from the API — `session.get`
|
|
140
|
+
* returns it, so never put secrets here; secrets belong in `runtimeEnv`
|
|
141
|
+
* or Environment resources. Large values bloat every prompt.
|
|
142
|
+
*/
|
|
143
|
+
readonly sessionContext?: string;
|
|
114
144
|
}
|
|
115
145
|
|
|
116
146
|
/** Return value of {@link useNewSessionFlow}. */
|
|
@@ -217,7 +247,15 @@ export interface UseNewSessionFlowReturn {
|
|
|
217
247
|
export function useNewSessionFlow(
|
|
218
248
|
options: UseNewSessionFlowOptions,
|
|
219
249
|
): UseNewSessionFlowReturn {
|
|
220
|
-
const {
|
|
250
|
+
const {
|
|
251
|
+
org,
|
|
252
|
+
onSessionCreated,
|
|
253
|
+
onError,
|
|
254
|
+
getRuntimeEnv,
|
|
255
|
+
defaultHarness,
|
|
256
|
+
metadata,
|
|
257
|
+
sessionContext,
|
|
258
|
+
} = options;
|
|
221
259
|
const isGuest = options.audience === "guest";
|
|
222
260
|
const contextTarget = useExecutionTarget();
|
|
223
261
|
const executionTarget = options.executionTarget ?? contextTarget;
|
|
@@ -336,6 +374,10 @@ export function useNewSessionFlow(
|
|
|
336
374
|
: undefined,
|
|
337
375
|
mcpServerUsages: mcpServerUsages.length > 0 ? mcpServerUsages : undefined,
|
|
338
376
|
skillRefs: skillRefs.length > 0 ? skillRefs : undefined,
|
|
377
|
+
// The typed-wins merge happens downstream in useCreateAgentExecution;
|
|
378
|
+
// both fields are forwarded verbatim here.
|
|
379
|
+
metadata,
|
|
380
|
+
sessionContext,
|
|
339
381
|
harness,
|
|
340
382
|
executionTarget,
|
|
341
383
|
};
|
|
@@ -440,6 +482,8 @@ export function useNewSessionFlow(
|
|
|
440
482
|
workspace,
|
|
441
483
|
mcpServerUsages,
|
|
442
484
|
skillRefs,
|
|
485
|
+
metadata,
|
|
486
|
+
sessionContext,
|
|
443
487
|
agentRef,
|
|
444
488
|
resolution,
|
|
445
489
|
defaultAgent,
|
|
@@ -24,28 +24,47 @@ export interface UseUpdateSessionReturn {
|
|
|
24
24
|
* {@link SessionInput} including the session's `name` and `org` (used
|
|
25
25
|
* by the backend to identify the resource) and all spec fields.
|
|
26
26
|
*
|
|
27
|
+
* **Full-replace semantics.** The backend replaces the entire spec with
|
|
28
|
+
* what you send — there is no field mask. Round-trip every spec field
|
|
29
|
+
* you do not intend to change, *including `metadata`*: an update built
|
|
30
|
+
* from a reconstructed partial spec silently wipes the fields it omits
|
|
31
|
+
* (workspace entries, MCP servers, and `stigmer.ai/*` metadata keys such
|
|
32
|
+
* as the embedder session context). To change only the subject, prefer
|
|
33
|
+
* the field-level `session.updateSubject()` RPC instead of this hook.
|
|
34
|
+
*
|
|
27
35
|
* Typically composed into higher-level hooks like
|
|
28
|
-
* {@link useSessionConversation}
|
|
29
|
-
*
|
|
30
|
-
* standalone.
|
|
36
|
+
* {@link useSessionConversation} (whose update path round-trips the
|
|
37
|
+
* fetched spec) rather than used directly. Platform builders who need
|
|
38
|
+
* direct session mutation can use this hook standalone.
|
|
31
39
|
*
|
|
32
40
|
* @example
|
|
33
41
|
* ```tsx
|
|
34
|
-
* function
|
|
35
|
-
* const { update, isUpdating
|
|
42
|
+
* function TagSession({ session }: { session: Session }) {
|
|
43
|
+
* const { update, isUpdating } = useUpdateSession();
|
|
36
44
|
*
|
|
37
|
-
* async function
|
|
45
|
+
* async function handleTag() {
|
|
46
|
+
* const spec = session.spec;
|
|
38
47
|
* await update({
|
|
39
48
|
* name: session.metadata!.name,
|
|
40
49
|
* org: session.metadata!.org,
|
|
41
|
-
*
|
|
42
|
-
*
|
|
50
|
+
* // Full replace: carry over every fetched spec field...
|
|
51
|
+
* agentInstanceId: spec?.agentInstanceId,
|
|
52
|
+
* subject: spec?.subject,
|
|
53
|
+
* harnessStateId: spec?.harnessStateId,
|
|
54
|
+
* harness: spec?.harness,
|
|
55
|
+
* cursorMode: spec?.cursorMode,
|
|
56
|
+
* executionTarget: spec?.executionTarget,
|
|
57
|
+
* // ...including the spec lists (workspaceEntries, mcpServerUsages,
|
|
58
|
+
* // skillRefs), converted from the fetched proto exactly as
|
|
59
|
+
* // useSessionConversation's update path does...
|
|
60
|
+
* // ...then apply the one change on top of the carried metadata.
|
|
61
|
+
* metadata: { ...spec?.metadata, "acme/reviewed": "true" },
|
|
43
62
|
* });
|
|
44
63
|
* }
|
|
45
64
|
*
|
|
46
65
|
* return (
|
|
47
|
-
* <button onClick={
|
|
48
|
-
*
|
|
66
|
+
* <button onClick={handleTag} disabled={isUpdating}>
|
|
67
|
+
* Mark reviewed
|
|
49
68
|
* </button>
|
|
50
69
|
* );
|
|
51
70
|
* }
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
import { describe, it, expect, vi, afterEach } from "vitest";
|
|
2
|
+
import { cleanup, fireEvent, render, screen } from "@testing-library/react";
|
|
3
|
+
import { useRef, useState } from "react";
|
|
4
|
+
import { SETTINGS_NAV_GROUPS, PLATFORM_SETTINGS_NAV_GROUP } from "../settings-nav";
|
|
5
|
+
import { useSettingsNavGroups } from "../useSettingsNavGroups";
|
|
6
|
+
|
|
7
|
+
// Drive the nav gate through the permission hook. The fail-closed
|
|
8
|
+
// semantics themselves are covered by useCheckPermission's own suite —
|
|
9
|
+
// here we assert the nav hook's per-item composition of the verdicts.
|
|
10
|
+
// Verdicts are keyed by relation so each platform permission can be
|
|
11
|
+
// granted independently.
|
|
12
|
+
let verdicts: Record<string, boolean> = {};
|
|
13
|
+
let checkedRelations: string[] = [];
|
|
14
|
+
let lastCheckArgs: readonly unknown[] = [];
|
|
15
|
+
|
|
16
|
+
vi.mock("../../iam-policy/useCheckPermission", () => ({
|
|
17
|
+
useCheckPermission: (
|
|
18
|
+
...args: [unknown, string, { fail?: string } | undefined]
|
|
19
|
+
) => {
|
|
20
|
+
lastCheckArgs = args;
|
|
21
|
+
checkedRelations.push(args[1]);
|
|
22
|
+
return { allowed: verdicts[args[1]] === true, isLoading: false, error: null };
|
|
23
|
+
},
|
|
24
|
+
}));
|
|
25
|
+
|
|
26
|
+
afterEach(() => {
|
|
27
|
+
cleanup();
|
|
28
|
+
verdicts = {};
|
|
29
|
+
checkedRelations = [];
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
function GroupsProbe() {
|
|
33
|
+
const groups = useSettingsNavGroups();
|
|
34
|
+
const platform = groups.find((g) => g.label === PLATFORM_SETTINGS_NAV_GROUP.label);
|
|
35
|
+
return (
|
|
36
|
+
<div
|
|
37
|
+
data-testid="groups"
|
|
38
|
+
data-labels={groups.map((g) => g.label).join(",")}
|
|
39
|
+
data-platform-items={platform?.items.map((i) => i.label).join(",") ?? ""}
|
|
40
|
+
/>
|
|
41
|
+
);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
const BASE_LABELS = SETTINGS_NAV_GROUPS.map((g) => g.label).join(",");
|
|
45
|
+
|
|
46
|
+
describe("useSettingsNavGroups", () => {
|
|
47
|
+
it("appends the full Platform group when the operator holds every platform permission", () => {
|
|
48
|
+
verdicts = {
|
|
49
|
+
can_manage_model_pricing: true,
|
|
50
|
+
can_manage_cursor_accounts: true,
|
|
51
|
+
};
|
|
52
|
+
render(<GroupsProbe />);
|
|
53
|
+
|
|
54
|
+
const el = screen.getByTestId("groups");
|
|
55
|
+
expect(el.getAttribute("data-labels")).toBe(
|
|
56
|
+
`${BASE_LABELS},${PLATFORM_SETTINGS_NAV_GROUP.label}`,
|
|
57
|
+
);
|
|
58
|
+
expect(el.getAttribute("data-platform-items")).toBe(
|
|
59
|
+
"Pricing Governance,Cursor Accounts",
|
|
60
|
+
);
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
it("filters per item: pricing-only operator sees only Pricing Governance", () => {
|
|
64
|
+
verdicts = { can_manage_model_pricing: true };
|
|
65
|
+
render(<GroupsProbe />);
|
|
66
|
+
|
|
67
|
+
expect(screen.getByTestId("groups").getAttribute("data-platform-items")).toBe(
|
|
68
|
+
"Pricing Governance",
|
|
69
|
+
);
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
it("filters per item: cursor-accounts-only operator sees only Cursor Accounts", () => {
|
|
73
|
+
verdicts = { can_manage_cursor_accounts: true };
|
|
74
|
+
render(<GroupsProbe />);
|
|
75
|
+
|
|
76
|
+
expect(screen.getByTestId("groups").getAttribute("data-platform-items")).toBe(
|
|
77
|
+
"Cursor Accounts",
|
|
78
|
+
);
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
it("returns exactly the base groups when not authorized", () => {
|
|
82
|
+
function IdentityProbe() {
|
|
83
|
+
const groups = useSettingsNavGroups();
|
|
84
|
+
return (
|
|
85
|
+
<div
|
|
86
|
+
data-testid="identity"
|
|
87
|
+
data-is-base={String(groups === SETTINGS_NAV_GROUPS)}
|
|
88
|
+
/>
|
|
89
|
+
);
|
|
90
|
+
}
|
|
91
|
+
render(<IdentityProbe />);
|
|
92
|
+
|
|
93
|
+
// Not just equivalent — the same array, no needless copy.
|
|
94
|
+
expect(screen.getByTestId("identity").getAttribute("data-is-base")).toBe("true");
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
it("checks every declared platform permission on platform:stigmer, fail-closed", () => {
|
|
98
|
+
render(<GroupsProbe />);
|
|
99
|
+
|
|
100
|
+
// Exhaustiveness guard: every requiredPermission declared on the
|
|
101
|
+
// platform group must have a corresponding hook check — a new
|
|
102
|
+
// platform surface that forgets to add its check fails here.
|
|
103
|
+
const declared = PLATFORM_SETTINGS_NAV_GROUP.items.map(
|
|
104
|
+
(item) => item.requiredPermission,
|
|
105
|
+
);
|
|
106
|
+
for (const permission of declared) {
|
|
107
|
+
expect(permission, "platform items must declare requiredPermission").toBeDefined();
|
|
108
|
+
expect(checkedRelations).toContain(permission);
|
|
109
|
+
}
|
|
110
|
+
expect(lastCheckArgs[0]).toEqual({ kind: "platform", id: "stigmer" });
|
|
111
|
+
expect(lastCheckArgs[2]).toEqual({ fail: "closed" });
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
it("keeps the array reference stable across re-renders", () => {
|
|
115
|
+
verdicts = {
|
|
116
|
+
can_manage_model_pricing: true,
|
|
117
|
+
can_manage_cursor_accounts: true,
|
|
118
|
+
};
|
|
119
|
+
|
|
120
|
+
function StabilityProbe() {
|
|
121
|
+
const groups = useSettingsNavGroups();
|
|
122
|
+
const first = useRef(groups);
|
|
123
|
+
const [, force] = useState(0);
|
|
124
|
+
return (
|
|
125
|
+
<button
|
|
126
|
+
data-testid="stability"
|
|
127
|
+
data-stable={String(first.current === groups)}
|
|
128
|
+
onClick={() => force((n) => n + 1)}
|
|
129
|
+
/>
|
|
130
|
+
);
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
render(<StabilityProbe />);
|
|
134
|
+
const el = screen.getByTestId("stability");
|
|
135
|
+
fireEvent.click(el);
|
|
136
|
+
expect(el.getAttribute("data-stable")).toBe("true");
|
|
137
|
+
});
|
|
138
|
+
});
|
package/src/settings/index.ts
CHANGED
|
@@ -1,5 +1,9 @@
|
|
|
1
|
-
export {
|
|
1
|
+
export {
|
|
2
|
+
SETTINGS_NAV_GROUPS,
|
|
3
|
+
PLATFORM_SETTINGS_NAV_GROUP,
|
|
4
|
+
} from "./settings-nav.js";
|
|
2
5
|
export type { SettingsNavItem, SettingsNavGroup } from "./settings-nav.js";
|
|
6
|
+
export { useSettingsNavGroups } from "./useSettingsNavGroups.js";
|
|
3
7
|
|
|
4
8
|
export { ApiKeysSection } from "./ApiKeysSection.js";
|
|
5
9
|
export { BillingSection } from "./BillingSection.js";
|
|
@@ -8,7 +8,9 @@ import {
|
|
|
8
8
|
KeyRound,
|
|
9
9
|
Link,
|
|
10
10
|
MessageSquare,
|
|
11
|
+
MousePointerClick,
|
|
11
12
|
Plug,
|
|
13
|
+
Scale,
|
|
12
14
|
ShieldCheck,
|
|
13
15
|
Users,
|
|
14
16
|
} from "lucide-react";
|
|
@@ -24,6 +26,14 @@ export interface SettingsNavItem {
|
|
|
24
26
|
/** Optional CSS class name applied to the icon. */
|
|
25
27
|
className?: string;
|
|
26
28
|
}>;
|
|
29
|
+
/**
|
|
30
|
+
* Platform-level permission (on `platform:stigmer`) required for this
|
|
31
|
+
* entry to appear. Only meaningful inside
|
|
32
|
+
* {@link PLATFORM_SETTINGS_NAV_GROUP} — items in the base groups are
|
|
33
|
+
* visible to every signed-in user and leave this unset.
|
|
34
|
+
* {@link useSettingsNavGroups} checks it fail-closed.
|
|
35
|
+
*/
|
|
36
|
+
readonly requiredPermission?: string;
|
|
27
37
|
}
|
|
28
38
|
|
|
29
39
|
/** Grouping model used to render settings navigation sections. */
|
|
@@ -82,3 +92,36 @@ export const SETTINGS_NAV_GROUPS: readonly SettingsNavGroup[] = [
|
|
|
82
92
|
],
|
|
83
93
|
},
|
|
84
94
|
];
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* Stigmer-internal platform-operator navigation group.
|
|
98
|
+
*
|
|
99
|
+
* Deliberately NOT part of {@link SETTINGS_NAV_GROUPS}: that constant
|
|
100
|
+
* means "groups every signed-in user sees", and its members must never
|
|
101
|
+
* change based on who is looking. This group is appended for platform
|
|
102
|
+
* operators only — use {@link useSettingsNavGroups} to get the
|
|
103
|
+
* permission-aware list instead of composing the two by hand.
|
|
104
|
+
*
|
|
105
|
+
* Every item here declares its `requiredPermission`; the hook filters
|
|
106
|
+
* per item (fail-closed), so an operator holding one platform permission
|
|
107
|
+
* but not another sees exactly their slice of this group.
|
|
108
|
+
*/
|
|
109
|
+
export const PLATFORM_SETTINGS_NAV_GROUP: SettingsNavGroup = {
|
|
110
|
+
label: "Platform",
|
|
111
|
+
description:
|
|
112
|
+
"Stigmer-internal operations. Visible to platform operators only.",
|
|
113
|
+
items: [
|
|
114
|
+
{
|
|
115
|
+
href: "/settings/pricing-governance",
|
|
116
|
+
label: "Pricing Governance",
|
|
117
|
+
icon: Scale,
|
|
118
|
+
requiredPermission: "can_manage_model_pricing",
|
|
119
|
+
},
|
|
120
|
+
{
|
|
121
|
+
href: "/settings/cursor-accounts",
|
|
122
|
+
label: "Cursor Accounts",
|
|
123
|
+
icon: MousePointerClick,
|
|
124
|
+
requiredPermission: "can_manage_cursor_accounts",
|
|
125
|
+
},
|
|
126
|
+
],
|
|
127
|
+
};
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import { useMemo } from "react";
|
|
4
|
+
import { useCheckPermission } from "../iam-policy/useCheckPermission.js";
|
|
5
|
+
import {
|
|
6
|
+
PLATFORM_SETTINGS_NAV_GROUP,
|
|
7
|
+
SETTINGS_NAV_GROUPS,
|
|
8
|
+
type SettingsNavGroup,
|
|
9
|
+
} from "./settings-nav.js";
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* The `platform` singleton — platform-level permissions are always
|
|
13
|
+
* checked against this one resource (mirrors the server-side
|
|
14
|
+
* `resource_id = "stigmer"` RPC config).
|
|
15
|
+
*/
|
|
16
|
+
const PLATFORM_RESOURCE = { kind: "platform", id: "stigmer" } as const;
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Permission-aware settings navigation: {@link SETTINGS_NAV_GROUPS}
|
|
20
|
+
* for everyone, plus the {@link PLATFORM_SETTINGS_NAV_GROUP} items the
|
|
21
|
+
* caller's platform permissions unlock (per-item `requiredPermission`,
|
|
22
|
+
* checked against `platform:stigmer`). The group appears when at least
|
|
23
|
+
* one of its items is visible.
|
|
24
|
+
*
|
|
25
|
+
* The checks run fail-closed — the opposite of the `useCheckPermission`
|
|
26
|
+
* default — because navigation is *discoverability*, not *capability*:
|
|
27
|
+
* an action gate can safely fail open (the server re-checks every
|
|
28
|
+
* request), but an operator-only nav entry must not appear while the
|
|
29
|
+
* check is loading, when it errors, or on deployments where the IAM
|
|
30
|
+
* service (and the surface it points to) does not exist.
|
|
31
|
+
*
|
|
32
|
+
* Implementation note: hooks must be called unconditionally, so each
|
|
33
|
+
* distinct platform permission gets its own static check below. When a
|
|
34
|
+
* new platform surface adds a new permission, add its check to
|
|
35
|
+
* PLATFORM_PERMISSION_CHECKS' shape here — the exhaustiveness guard in
|
|
36
|
+
* the tests catches a forgotten one.
|
|
37
|
+
*
|
|
38
|
+
* @example
|
|
39
|
+
* ```tsx
|
|
40
|
+
* const groups = useSettingsNavGroups();
|
|
41
|
+
* return groups.map((group) => <NavGroup key={group.label} group={group} />);
|
|
42
|
+
* ```
|
|
43
|
+
*/
|
|
44
|
+
export function useSettingsNavGroups(): readonly SettingsNavGroup[] {
|
|
45
|
+
const pricing = useCheckPermission(
|
|
46
|
+
PLATFORM_RESOURCE,
|
|
47
|
+
"can_manage_model_pricing",
|
|
48
|
+
{ fail: "closed" },
|
|
49
|
+
);
|
|
50
|
+
const cursorAccounts = useCheckPermission(
|
|
51
|
+
PLATFORM_RESOURCE,
|
|
52
|
+
"can_manage_cursor_accounts",
|
|
53
|
+
{ fail: "closed" },
|
|
54
|
+
);
|
|
55
|
+
|
|
56
|
+
const pricingAllowed = pricing.allowed;
|
|
57
|
+
const cursorAccountsAllowed = cursorAccounts.allowed;
|
|
58
|
+
|
|
59
|
+
return useMemo(() => {
|
|
60
|
+
const verdicts: Record<string, boolean> = {
|
|
61
|
+
can_manage_model_pricing: pricingAllowed,
|
|
62
|
+
can_manage_cursor_accounts: cursorAccountsAllowed,
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
const visibleItems = PLATFORM_SETTINGS_NAV_GROUP.items.filter(
|
|
66
|
+
// Fail closed on both axes: an item with no declared permission or
|
|
67
|
+
// with a permission this hook does not check yet stays hidden.
|
|
68
|
+
(item) =>
|
|
69
|
+
item.requiredPermission !== undefined &&
|
|
70
|
+
verdicts[item.requiredPermission] === true,
|
|
71
|
+
);
|
|
72
|
+
|
|
73
|
+
if (visibleItems.length === 0) {
|
|
74
|
+
return SETTINGS_NAV_GROUPS;
|
|
75
|
+
}
|
|
76
|
+
return [
|
|
77
|
+
...SETTINGS_NAV_GROUPS,
|
|
78
|
+
{ ...PLATFORM_SETTINGS_NAV_GROUP, items: visibleItems },
|
|
79
|
+
];
|
|
80
|
+
}, [pricingAllowed, cursorAccountsAllowed]);
|
|
81
|
+
}
|