@pie-players/pie-assessment-toolkit 0.3.75 → 1.0.0-beta.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +451 -541
- package/custom-elements.json +1315 -0
- package/dist/attempt/TestSession.d.ts +0 -1
- package/dist/attempt/TestSession.js +10 -5
- package/dist/components/ItemScope.custom-element.js +1 -1
- package/dist/components/ItemToolBar.custom-element.js +1 -1
- package/dist/components/PieAssessmentToolkit.custom-element.js +8 -8
- package/dist/components/SectionToolBar.custom-element.js +1 -1
- package/dist/components/chunks/{ItemToolBar-7tt7v2xp.js → ItemToolBar-3zrc4p3d.js} +4 -4
- package/dist/components/chunks/{ItemToolBar-jx38w99s.js → ItemToolBar-66hcwmfw.js} +2 -2
- package/dist/components/chunks/ItemToolBar-asenkvx6.js +40 -0
- package/dist/components/chunks/ItemToolBar-hzc5wyjp.js +2 -0
- package/dist/components/chunks/{ItemToolBar-97hx60z4.js → ItemToolBar-kkj69ptr.js} +1 -1
- package/dist/components/chunks/sre-engine-bj997w4b.js +1 -0
- package/dist/context/assessment-toolkit-context.d.ts +6 -0
- package/dist/index.d.ts +7 -7
- package/dist/index.js +4 -10
- package/dist/policy/core/PolicySource.d.ts +1 -1
- package/dist/policy/core/ToolPolicyEngine.d.ts +46 -7
- package/dist/policy/core/ToolPolicyEngine.js +73 -16
- package/dist/policy/core/compose-decision.d.ts +3 -3
- package/dist/policy/core/compose-decision.js +32 -30
- package/dist/policy/core/decision-types.d.ts +51 -34
- package/dist/policy/core/feature-decision.d.ts +17 -15
- package/dist/policy/core/feature-decision.js +11 -13
- package/dist/policy/core/pnp-policy-inputs.d.ts +7 -3
- package/dist/policy/core/pnp-policy-inputs.js +17 -33
- package/dist/policy/core/provenance.d.ts +2 -2
- package/dist/policy/core/tool-parameters.d.ts +12 -0
- package/dist/policy/core/tool-parameters.js +27 -0
- package/dist/policy/engine.d.ts +1 -1
- package/dist/policy/sources/PnpPolicySource.d.ts +18 -24
- package/dist/policy/sources/PnpPolicySource.js +57 -29
- package/dist/runtime/SectionControllerBinding.d.ts +6 -2
- package/dist/runtime/SectionControllerBinding.js +21 -15
- package/dist/runtime/adapter/subscriber-fanout.d.ts +0 -1
- package/dist/runtime/adapter/subscriber-fanout.js +1 -4
- package/dist/runtime/composition-emit-scheduler.d.ts +3 -3
- package/dist/runtime/composition-emit-scheduler.js +1 -1
- package/dist/runtime/content-region.d.ts +0 -4
- package/dist/runtime/content-region.js +2 -2
- package/dist/runtime/core/SectionEngineCore.d.ts +0 -2
- package/dist/runtime/core/SectionEngineCore.js +0 -4
- package/dist/runtime/core/cohort.d.ts +0 -5
- package/dist/runtime/core/cohort.js +0 -9
- package/dist/runtime/core/engine-output.d.ts +3 -2
- package/dist/runtime/core/engine-transition.js +3 -2
- package/dist/runtime/registration-events.d.ts +11 -14
- package/dist/runtime/runtime-id.d.ts +1 -1
- package/dist/runtime/runtime-id.js +1 -1
- package/dist/runtime/shell-scope.d.ts +4 -4
- package/dist/runtime/shell-scope.js +15 -9
- package/dist/runtime/tool-host-contract.d.ts +0 -4
- package/dist/runtime/tool-host-contract.js +1 -1
- package/dist/services/AccessibilityCatalogResolver.d.ts +21 -31
- package/dist/services/AccessibilityCatalogResolver.js +29 -42
- package/dist/services/ElementToolStateStore.d.ts +32 -61
- package/dist/services/ElementToolStateStore.js +37 -67
- package/dist/services/HighlightCoordinator.d.ts +9 -21
- package/dist/services/HighlightCoordinator.js +52 -80
- package/dist/services/RangeSerializer.d.ts +4 -35
- package/dist/services/RangeSerializer.js +4 -48
- package/dist/services/SSMLExtractor.d.ts +8 -31
- package/dist/services/SSMLExtractor.js +18 -40
- package/dist/services/TTSService.d.ts +51 -57
- package/dist/services/TTSService.js +323 -284
- package/dist/services/ToolCoordinator.d.ts +6 -49
- package/dist/services/ToolCoordinator.js +25 -61
- package/dist/services/ToolRegistry.d.ts +83 -80
- package/dist/services/ToolRegistry.js +91 -67
- package/dist/services/ToolkitCoordinator.d.ts +83 -81
- package/dist/services/ToolkitCoordinator.js +186 -174
- package/dist/services/framework-error.d.ts +30 -7
- package/dist/services/framework-error.js +10 -13
- package/dist/services/interfaces.d.ts +51 -71
- package/dist/services/section-controller-types.d.ts +7 -7
- package/dist/services/section-session-assignment.js +6 -8
- package/dist/services/spoken-audio-cards.d.ts +2 -4
- package/dist/services/spoken-audio-cards.js +2 -4
- package/dist/services/tool-config-validation.d.ts +5 -7
- package/dist/services/tool-config-validation.js +11 -26
- package/dist/services/tool-context.d.ts +39 -24
- package/dist/services/tool-context.js +158 -92
- package/dist/services/tool-failure.d.ts +30 -0
- package/dist/services/tool-failure.js +11 -0
- package/dist/services/tool-icons.d.ts +1 -2
- package/dist/services/tool-icons.js +2 -2
- package/dist/services/tool-instance-id.d.ts +8 -6
- package/dist/services/tool-instance-id.js +12 -18
- package/dist/services/tool-providers/TTSToolProvider.d.ts +6 -43
- package/dist/services/tool-providers/TTSToolProvider.js +7 -63
- package/dist/services/tool-providers/ToolProviderApi.d.ts +0 -7
- package/dist/services/tool-providers/ToolProviderRegistry.d.ts +7 -42
- package/dist/services/tool-providers/ToolProviderRegistry.js +21 -63
- package/dist/services/tool-request.d.ts +4 -0
- package/dist/services/tool-request.js +7 -2
- package/dist/services/toolbar-decided-tools.d.ts +2 -0
- package/dist/services/toolbar-decided-tools.js +2 -0
- package/dist/services/toolbar-items.js +2 -5
- package/dist/services/tools-config-normalizer.d.ts +18 -9
- package/dist/services/tools-config-normalizer.js +25 -19
- package/dist/services/tts/browser-provider.d.ts +2 -5
- package/dist/services/tts/browser-provider.js +13 -22
- package/dist/services/tts/catalog-span-alignment.js +14 -7
- package/dist/services/tts/flat-tree.d.ts +0 -7
- package/dist/services/tts/flat-tree.js +2 -2
- package/dist/services/tts/generated-speech/dom/to-chunk-inputs.d.ts +2 -2
- package/dist/services/tts/generated-speech/index.d.ts +1 -1
- package/dist/services/tts/generated-speech/index.js +1 -1
- package/dist/services/tts/generated-speech/types.d.ts +1 -1
- package/dist/services/tts/generated-speech/types.js +1 -1
- package/dist/services/tts/highlight-pipeline/create-highlight-plan.js +10 -12
- package/dist/services/tts/highlight-target-resolver.d.ts +12 -0
- package/dist/services/tts/math-aware-text-processing.js +10 -29
- package/dist/services/tts/math-speech.d.ts +1 -1
- package/dist/services/tts/math-speech.js +3 -0
- package/dist/services/tts/mathml-sanitization.d.ts +7 -0
- package/dist/services/tts/mathml-sanitization.js +9 -1
- package/dist/services/tts/provider-options.d.ts +12 -1
- package/dist/services/tts/ssml/spoken-text.js +1 -1
- package/dist/services/tts/start-failure.d.ts +0 -7
- package/dist/services/tts/start-failure.js +1 -1
- package/dist/services/tts/text-segmentation.d.ts +5 -0
- package/dist/services/tts/text-segmentation.js +13 -10
- package/dist/services/tts-runtime-config.d.ts +32 -12
- package/dist/services/tts-runtime-config.js +14 -20
- package/dist/tools/content-capability-resolution.d.ts +2 -2
- package/dist/tools/registration.d.ts +7 -6
- package/dist/tools/registration.js +10 -9
- package/dist/tools/registrations/toolbar-registration-helpers.d.ts +6 -0
- package/dist/tools/registrations/toolbar-registration-helpers.js +6 -0
- package/dist/tools/tool-surface-host.js +1 -8
- package/package.json +8 -6
- package/dist/components/chunks/ItemToolBar-bxwyhr5p.js +0 -2
- package/dist/components/chunks/ItemToolBar-rd2bb4p6.js +0 -40
- package/dist/components/chunks/sre-engine-jd8cc08x.js +0 -1
- package/dist/services/ContextVariableStore.d.ts +0 -113
- package/dist/services/ContextVariableStore.js +0 -206
- package/dist/services/tts-control-events.d.ts +0 -13
- package/dist/services/tts-control-events.js +0 -7
- package/dist/utils/logger.d.ts +0 -6
- package/dist/utils/logger.js +0 -10
package/dist/index.d.ts
CHANGED
|
@@ -16,38 +16,38 @@ export { connectToolRuntimeContext, dispatchCrossBoundaryEvent, } from "./runtim
|
|
|
16
16
|
export type { AccessibilityCatalogResolverApi, ElementToolStateStoreApi, HighlightCoordinatorApi, ToolCoordinatorApi, ToolkitCoordinatorApi, SpeakOptions, TtsServiceApi, ToolState, ToolStateFilter, } from "./services/interfaces.js";
|
|
17
17
|
export type { CatalogCardForm, CatalogChangeEvent, CatalogChangeListener, CatalogChangeReason, CatalogLookupContext, CatalogLookupOptions, CatalogOwnerCard, CatalogOwnerRegistration, CatalogOwnerSnapshot, CatalogOwnerView, CatalogStatistics, CatalogType, ResolvedCatalog, } from "./services/AccessibilityCatalogResolver.js";
|
|
18
18
|
export { AccessibilityCatalogResolver } from "./services/AccessibilityCatalogResolver.js";
|
|
19
|
-
export { ElementToolStateStore } from "./services/ElementToolStateStore.js";
|
|
19
|
+
export { type ElementIdComponents, ElementToolStateStore, } from "./services/ElementToolStateStore.js";
|
|
20
20
|
export type { Annotation } from "./services/HighlightCoordinator.js";
|
|
21
21
|
export { HighlightColor, HighlightCoordinator, HighlightType, } from "./services/HighlightCoordinator.js";
|
|
22
22
|
export type { SerializedRange } from "./services/RangeSerializer.js";
|
|
23
23
|
export type { I18nProvider, InterpolationValues, LocaleCode, MessageKeyInput, PluralOptions, TextDirection, } from "@pie-players/pie-players-shared/i18n";
|
|
24
|
-
export type { ResolvedToolContext, ToolbarContext, ToolContextResolver, ToolContextResolverContext, ToolContextResolverMap, ToolContextResolverResult, ToolActivation, ToolContentDependency, ToolContentDependencyContext, ToolModuleLoader, ToolRegistryChangeEvent, ToolRegistryChangeKind, ToolRegistryChangeListener, ToolSingletonScope, ToolSurfaceRenderContext, ToolSurfaceRenderResult, ToolSurfaceServices, ToolToolbarButtonDefinition, ToolToolbarRenderResult, ToolRegistration, } from "./services/ToolRegistry.js";
|
|
24
|
+
export type { ResolvedToolContext, ToolbarContext, ToolContextResolver, ToolContextResolverContext, ToolContextResolverMap, ToolContextResolverResult, ToolActivation, ToolCallbackFailureHandler, ToolContentDependency, ToolContentDependencyContext, ToolModuleLoader, ToolRegistryChangeEvent, ToolRegistryChangeKind, ToolRegistryChangeListener, ToolSingletonScope, ToolSurfaceRenderContext, ToolSurfaceRenderResult, ToolSurfaceServices, ToolToolbarButtonDefinition, ToolToolbarRenderResult, ToolRegistration, } from "./services/ToolRegistry.js";
|
|
25
25
|
export { ToolRegistry } from "./services/ToolRegistry.js";
|
|
26
26
|
export type { ToolOpenRequest, ToolRequestTarget, } from "./services/tool-request.js";
|
|
27
27
|
export type { AssessmentToolContext, BaseToolContext, ElementToolContext, ItemToolContext, PassageToolContext, RubricToolContext, SectionToolContext, ToolContext, ToolLevel, } from "./services/tool-context.js";
|
|
28
|
-
export { hasReadableText } from "./services/tool-context.js";
|
|
28
|
+
export { hasReadableText, hasSpokenContent, } from "./services/tool-context.js";
|
|
29
29
|
export type { CreateToolsConfigArgs } from "./services/create-tools-config.js";
|
|
30
30
|
export { createToolsConfig } from "./services/create-tools-config.js";
|
|
31
31
|
export type { ToolComponentFactory, ToolComponentFactoryMap, ToolComponentOverrides, ToolTagMap, } from "./tools/tool-tag-map.js";
|
|
32
32
|
export type { ExtractionResult } from "./services/SSMLExtractor.js";
|
|
33
33
|
export { SSMLExtractor } from "./services/SSMLExtractor.js";
|
|
34
|
-
export {
|
|
34
|
+
export { ZIndexLayer } from "./services/ToolCoordinator.js";
|
|
35
35
|
export type { ProviderLifecycleContext, SectionControllerContext, SectionControllerEvent, SectionControllerEventType, SectionItemEvent, SectionItemEventType, SectionControllerFactoryDefaults, SectionControllerHandle, SectionControllerKey, SectionScopedEvent, SectionScopedEventType, SectionSessionPersistenceConfig, SectionItemEventSubscriptionArgs, SectionScopedEventSubscriptionArgs, SectionEventSubscriptionArgs, SectionSessionPersistenceStrategy, SectionControllerLoadedRenderable, SectionControllerRuntimeState, SectionControllerSessionState, SectionPersistenceFactoryDefaults, ToolkitCoordinatorConfig, ToolkitCoordinatorHooks, ToolkitErrorContext, } from "./services/ToolkitCoordinator.js";
|
|
36
36
|
export { ToolkitCoordinator } from "./services/ToolkitCoordinator.js";
|
|
37
37
|
export type { CalculatorToolProviderConfig, CanonicalToolsConfig, ToolPlacementConfig, ToolPlacementLevel, ToolPolicyConfig, ToolProvidersConfig, ToolsConfigInput, TextToSpeechToolProviderConfig, } from "./services/tools-config-normalizer.js";
|
|
38
|
-
export type { FrameworkErrorKind, FrameworkErrorModel, FrameworkErrorScope, FrameworkErrorSeverity, } from "./services/framework-error.js";
|
|
38
|
+
export type { FrameworkErrorCohort, FrameworkErrorKind, FrameworkErrorModel, FrameworkErrorScope, FrameworkErrorSeverity, } from "./services/framework-error.js";
|
|
39
39
|
export { frameworkErrorFromUnknown, toFrameworkErrorModel, } from "./services/framework-error.js";
|
|
40
40
|
export type { FrameworkErrorListener } from "./services/framework-error-bus.js";
|
|
41
|
+
export type { ToolFailurePhase } from "./services/tool-failure.js";
|
|
41
42
|
export type { ToolConfigDiagnostic, ToolConfigDiagnosticSeverity, ToolConfigStrictness, ToolConfigValidationResult, } from "./services/tool-config-validation.js";
|
|
42
43
|
export type { ToolbarButtonItem, ToolbarItem, ToolbarItemBase, ToolbarLinkItem, } from "./services/toolbar-items.js";
|
|
43
44
|
export type { ToolScopeLevel } from "./services/tool-instance-id.js";
|
|
44
45
|
export { createScopedToolId } from "./services/tool-instance-id.js";
|
|
45
|
-
export type { TTSConfig } from "./services/TTSService.js";
|
|
46
46
|
export { PlaybackState, TTSService } from "./services/TTSService.js";
|
|
47
47
|
export { BrowserTTSProvider } from "./services/tts/browser-provider.js";
|
|
48
48
|
export type { SREMathSpeechOptions } from "./services/tts/math-speech.js";
|
|
49
49
|
export type { TTSLayoutMode, TTSRuntimeSettings, TTSSpeedOption, TTSSpeedOptionConfig, } from "./services/tts-runtime-config.js";
|
|
50
|
-
export type { ITTSProvider, ITTSProviderImplementation, TTSSpeechSegment, TTSProviderCapabilities, } from "@pie-players/pie-tts";
|
|
50
|
+
export type { ITTSProvider, ITTSProviderImplementation, TTSConfig, TTSSpeechSegment, TTSProviderCapabilities, } from "@pie-players/pie-tts";
|
|
51
51
|
export type { TestAttemptItemSession, TestAttemptSession, TestAttemptSessionNavigationState, TestAttemptSessionRealization, } from "./attempt/TestSession.js";
|
|
52
52
|
export { createNewTestAttemptSession, setCurrentPosition, toItemSessionsRecord, upsertItemSessionFromPieSessionChange, upsertVisitedItem, } from "./attempt/TestSession.js";
|
|
53
53
|
export type { AssessmentSession, AssessmentSectionSessionState, AssessmentSessionNavigationState, AssessmentSessionRealization, } from "./attempt/AssessmentSession.js";
|
package/dist/index.js
CHANGED
|
@@ -15,25 +15,19 @@ export { createShellEventBridge, } from "./runtime/shell-event-bridge.js";
|
|
|
15
15
|
export { connectToolRuntimeContext, dispatchCrossBoundaryEvent, } from "./runtime/tool-host-contract.js";
|
|
16
16
|
export { AccessibilityCatalogResolver } from "./services/AccessibilityCatalogResolver.js";
|
|
17
17
|
// Element Tool State Store (Element-level ephemeral tool state)
|
|
18
|
-
export { ElementToolStateStore } from "./services/ElementToolStateStore.js";
|
|
18
|
+
export { ElementToolStateStore, } from "./services/ElementToolStateStore.js";
|
|
19
19
|
export { HighlightColor, HighlightCoordinator, HighlightType, } from "./services/HighlightCoordinator.js";
|
|
20
20
|
export { ToolRegistry } from "./services/ToolRegistry.js";
|
|
21
|
-
export { hasReadableText } from "./services/tool-context.js";
|
|
21
|
+
export { hasReadableText, hasSpokenContent, } from "./services/tool-context.js";
|
|
22
22
|
export { createToolsConfig } from "./services/create-tools-config.js";
|
|
23
23
|
export { SSMLExtractor } from "./services/SSMLExtractor.js";
|
|
24
24
|
// Tool Coordinator
|
|
25
|
-
export {
|
|
25
|
+
export { ZIndexLayer } from "./services/ToolCoordinator.js";
|
|
26
26
|
export { ToolkitCoordinator } from "./services/ToolkitCoordinator.js";
|
|
27
27
|
export { frameworkErrorFromUnknown, toFrameworkErrorModel, } from "./services/framework-error.js";
|
|
28
28
|
export { createScopedToolId } from "./services/tool-instance-id.js";
|
|
29
|
+
// Text-to-Speech Service
|
|
29
30
|
export { PlaybackState, TTSService } from "./services/TTSService.js";
|
|
30
31
|
export { BrowserTTSProvider } from "./services/tts/browser-provider.js";
|
|
31
32
|
export { createNewTestAttemptSession, setCurrentPosition, toItemSessionsRecord, upsertItemSessionFromPieSessionChange, upsertVisitedItem, } from "./attempt/TestSession.js";
|
|
32
33
|
export { createNewAssessmentSession, setCurrentSectionPosition, upsertSectionSession, } from "./attempt/AssessmentSession.js";
|
|
33
|
-
// Section Player - Use @pie-players/pie-section-player web component
|
|
34
|
-
// ============================================================================
|
|
35
|
-
// Shared Components
|
|
36
|
-
// ============================================================================
|
|
37
|
-
// ItemToolBar custom element registration helper is exported via package.json exports field
|
|
38
|
-
// Import using: import '@pie-players/pie-assessment-toolkit/components/item-toolbar-element';
|
|
39
|
-
// PieAssessmentToolkit custom element registration helper is exported via package.json exports field
|
|
@@ -36,7 +36,7 @@ export interface PolicySourceProvenanceEntry {
|
|
|
36
36
|
* Custom precedence value used for the decision log. Defaults to
|
|
37
37
|
* `100 + sourceIndex` (engine-assigned) when `undefined`. Sources
|
|
38
38
|
* MAY override only if they know what they are doing — overriding
|
|
39
|
-
* to a value `<=
|
|
39
|
+
* to a value `<= 8` lets the source masquerade as a PNP/profile rule and
|
|
40
40
|
* is generally a bug.
|
|
41
41
|
*/
|
|
42
42
|
precedence?: number;
|
|
@@ -14,13 +14,13 @@
|
|
|
14
14
|
* connectedCallback. `ToolkitCoordinator` owns the instance, and
|
|
15
15
|
* `<pie-item-toolbar>` reads its decisions through the coordinator.
|
|
16
16
|
*/
|
|
17
|
-
import type { AssessmentEntity, ItemSettings } from "@pie-players/pie-players-shared/types";
|
|
18
|
-
import type { CanonicalToolsConfig, ToolPlacementLevel } from "../../services/tools-config-normalizer.js";
|
|
17
|
+
import type { AssessmentEntity, ItemSettings, ToolParametersFor } from "@pie-players/pie-players-shared/types";
|
|
18
|
+
import type { CanonicalToolsConfig, PnpEnforcementMode, ToolPlacementLevel } from "../../services/tools-config-normalizer.js";
|
|
19
19
|
import type { ToolRegistry } from "../../services/ToolRegistry.js";
|
|
20
|
-
import type { ToolPolicyDecision, ToolPolicyDecisionRequest, ToolScope } from "./decision-types.js";
|
|
20
|
+
import type { ToolPolicyDecision, ToolPolicyDecisionRequest, ToolPolicyDiagnostic, ToolScope } from "./decision-types.js";
|
|
21
21
|
import type { PolicySource } from "./PolicySource.js";
|
|
22
22
|
import type { FeaturePolicyDecision } from "./feature-decision.js";
|
|
23
|
-
export type PnpEnforcementMode
|
|
23
|
+
export type { PnpEnforcementMode };
|
|
24
24
|
export interface ToolPolicyEngineInputs {
|
|
25
25
|
tools?: CanonicalToolsConfig | null;
|
|
26
26
|
assessment?: AssessmentEntity | null;
|
|
@@ -29,7 +29,7 @@ export interface ToolPolicyEngineInputs {
|
|
|
29
29
|
* resolves per decision through {@link resolveDefaultPnpEnforcement}: `"on"`
|
|
30
30
|
* when the bound `assessment` carries PNP/profile policy material (PNP,
|
|
31
31
|
* district policy, test administration), and for a decision scoped to an item
|
|
32
|
-
* also when that item's settings
|
|
32
|
+
* also when that item's settings require or restrict a tool;
|
|
33
33
|
* `"off"` otherwise. `tests/policy/pnp-default-on.test.ts` locks the rule.
|
|
34
34
|
*
|
|
35
35
|
* Hosts that want to force a mode pass `"on"` or `"off"`
|
|
@@ -44,6 +44,12 @@ export interface ToolPolicyEngineArgs {
|
|
|
44
44
|
customSources?: readonly PolicySource[];
|
|
45
45
|
/** Stable context label used in provenance trails. Defaults to "tool-policy". */
|
|
46
46
|
contextId?: string;
|
|
47
|
+
/**
|
|
48
|
+
* Whether the host may leave the assessment unbound without that being a
|
|
49
|
+
* misconfiguration; see {@link ResolvedEngineInputs.assessmentExpected}.
|
|
50
|
+
* Defaults to `false`.
|
|
51
|
+
*/
|
|
52
|
+
assessmentOptional?: boolean;
|
|
47
53
|
}
|
|
48
54
|
export interface ToolPolicyChangeEvent {
|
|
49
55
|
/**
|
|
@@ -65,11 +71,26 @@ export interface ResolvedEngineInputs {
|
|
|
65
71
|
pnpEnforcement: PnpEnforcementMode;
|
|
66
72
|
/** The host's override of auto-mode, or `null` in auto-mode. */
|
|
67
73
|
pnpEnforcementOverride: PnpEnforcementMode | null;
|
|
74
|
+
/**
|
|
75
|
+
* Whether an unbound assessment is a misconfiguration: always, unless the
|
|
76
|
+
* engine was built `assessmentOptional`, and then only while enforcement is
|
|
77
|
+
* overridden `"on"`.
|
|
78
|
+
*/
|
|
79
|
+
assessmentExpected: boolean;
|
|
80
|
+
/**
|
|
81
|
+
* Conflicts in the inputs themselves, independent of any decision: a
|
|
82
|
+
* `tool-policy.unknownSupportId` for each id the assessment or a mounted
|
|
83
|
+
* item's settings name that no registered tool carries. Recomputed when the
|
|
84
|
+
* assessment, an item's settings or the registry's tools change.
|
|
85
|
+
*/
|
|
86
|
+
diagnostics: readonly ToolPolicyDiagnostic[];
|
|
68
87
|
}
|
|
69
88
|
export type ToolPolicyChangeListener = (event: ToolPolicyChangeEvent) => void;
|
|
70
89
|
export declare class ToolPolicyEngine {
|
|
71
90
|
private toolRegistry;
|
|
91
|
+
private unsubscribeRegistry;
|
|
72
92
|
private readonly contextId;
|
|
93
|
+
private readonly assessmentOptional;
|
|
73
94
|
private pnpPolicySource;
|
|
74
95
|
private readonly customSources;
|
|
75
96
|
private readonly listeners;
|
|
@@ -81,6 +102,7 @@ export declare class ToolPolicyEngine {
|
|
|
81
102
|
* see {@link registerItemSettings}.
|
|
82
103
|
*/
|
|
83
104
|
private readonly itemSettings;
|
|
105
|
+
private inputDiagnostics;
|
|
84
106
|
private disposed;
|
|
85
107
|
constructor(args: ToolPolicyEngineArgs);
|
|
86
108
|
/**
|
|
@@ -109,8 +131,13 @@ export declare class ToolPolicyEngine {
|
|
|
109
131
|
* Whether some surface is granted `featureId`: a decision with no item scope,
|
|
110
132
|
* or one scoped to a registered item. A provider serves every surface, so its
|
|
111
133
|
* failure denies the accommodation wherever one surface is granted it.
|
|
134
|
+
*
|
|
135
|
+
* `enforced` counts only scopes whose `pnpEnforcement` is on, as a toolbar
|
|
136
|
+
* tool's decisions do; a feature with no placement leaves it unset.
|
|
112
137
|
*/
|
|
113
|
-
grantsFeatureAnywhere(featureId: string
|
|
138
|
+
grantsFeatureAnywhere(featureId: string, options?: {
|
|
139
|
+
enforced?: boolean;
|
|
140
|
+
}): boolean;
|
|
114
141
|
/**
|
|
115
142
|
* File a mounted item's settings under its canonical id. They govern the
|
|
116
143
|
* decisions scoped to that item: its own toolbar, and a feature its content
|
|
@@ -148,7 +175,7 @@ export declare class ToolPolicyEngine {
|
|
|
148
175
|
* `scope` is the surface asking. An item's scope brings in the item's
|
|
149
176
|
* registered settings, as {@link decide} does for the item's toolbar.
|
|
150
177
|
*/
|
|
151
|
-
decideFeature(featureId:
|
|
178
|
+
decideFeature<K extends string>(featureId: K, scope?: ToolScope): FeaturePolicyDecision<ToolParametersFor<K>>;
|
|
152
179
|
/**
|
|
153
180
|
* The host gates that hold for a feature id, or `null` when none fires.
|
|
154
181
|
*
|
|
@@ -195,6 +222,18 @@ export declare class ToolPolicyEngine {
|
|
|
195
222
|
/** The settings that apply to `itemId`: its newest registration's. */
|
|
196
223
|
private itemSettingsFor;
|
|
197
224
|
private emitIfItemSettingsChanged;
|
|
225
|
+
/**
|
|
226
|
+
* Recompute {@link ResolvedEngineInputs.diagnostics} from the bound
|
|
227
|
+
* assessment, every mounted item's settings and the registry. Returns
|
|
228
|
+
* whether they changed.
|
|
229
|
+
*/
|
|
230
|
+
private refreshInputDiagnostics;
|
|
231
|
+
/**
|
|
232
|
+
* Registering a tool into the bound registry, or removing one, can make a
|
|
233
|
+
* named id known or unknown, so it emits an `"inputs"` change when the input
|
|
234
|
+
* diagnostics move.
|
|
235
|
+
*/
|
|
236
|
+
private watchRegistry;
|
|
198
237
|
/**
|
|
199
238
|
* The registered item an item scope names, by its canonical id. A scope
|
|
200
239
|
* of any other level names none.
|
|
@@ -16,8 +16,9 @@
|
|
|
16
16
|
*/
|
|
17
17
|
import { normalizeToolList, normalizeToolsConfig, } from "../../services/tools-config-normalizer.js";
|
|
18
18
|
import { hostFeatureDenial, interpretFeatureResult, } from "./feature-decision.js";
|
|
19
|
-
import { composeDecision } from "./compose-decision.js";
|
|
19
|
+
import { composeDecision, unknownSupportIdDiagnostic, } from "./compose-decision.js";
|
|
20
20
|
import { resolveDefaultPnpEnforcement } from "./pnp-policy-inputs.js";
|
|
21
|
+
import { resolveToolParameters } from "./tool-parameters.js";
|
|
21
22
|
import { structurallyEqual } from "../../utils/structural-equality.js";
|
|
22
23
|
import { PnpPolicySource, } from "../sources/PnpPolicySource.js";
|
|
23
24
|
const DEFAULT_TOOLS = normalizeToolsConfig({
|
|
@@ -27,7 +28,9 @@ const DEFAULT_TOOLS = normalizeToolsConfig({
|
|
|
27
28
|
});
|
|
28
29
|
export class ToolPolicyEngine {
|
|
29
30
|
toolRegistry;
|
|
31
|
+
unsubscribeRegistry;
|
|
30
32
|
contextId;
|
|
33
|
+
assessmentOptional;
|
|
31
34
|
pnpPolicySource;
|
|
32
35
|
customSources;
|
|
33
36
|
listeners = new Set();
|
|
@@ -39,16 +42,20 @@ export class ToolPolicyEngine {
|
|
|
39
42
|
* see {@link registerItemSettings}.
|
|
40
43
|
*/
|
|
41
44
|
itemSettings = new Map();
|
|
45
|
+
inputDiagnostics = Object.freeze([]);
|
|
42
46
|
disposed = false;
|
|
43
47
|
constructor(args) {
|
|
44
48
|
this.toolRegistry = args.toolRegistry;
|
|
45
49
|
this.contextId = args.contextId ?? "tool-policy";
|
|
50
|
+
this.assessmentOptional = args.assessmentOptional === true;
|
|
46
51
|
this.pnpPolicySource = new PnpPolicySource(this.toolRegistry);
|
|
47
52
|
this.customSources = args.customSources ? [...args.customSources] : [];
|
|
48
53
|
const inputs = args.inputs ?? {};
|
|
49
54
|
this.tools = inputs.tools ?? DEFAULT_TOOLS;
|
|
50
55
|
this.assessment = inputs.assessment ?? null;
|
|
51
56
|
this.pnpEnforcementOverride = inputs.pnpEnforcement ?? null;
|
|
57
|
+
this.refreshInputDiagnostics();
|
|
58
|
+
this.unsubscribeRegistry = this.watchRegistry();
|
|
52
59
|
}
|
|
53
60
|
/**
|
|
54
61
|
* Resolve the visible tool set for a given placement level and
|
|
@@ -98,11 +105,18 @@ export class ToolPolicyEngine {
|
|
|
98
105
|
* Whether some surface is granted `featureId`: a decision with no item scope,
|
|
99
106
|
* or one scoped to a registered item. A provider serves every surface, so its
|
|
100
107
|
* failure denies the accommodation wherever one surface is granted it.
|
|
108
|
+
*
|
|
109
|
+
* `enforced` counts only scopes whose `pnpEnforcement` is on, as a toolbar
|
|
110
|
+
* tool's decisions do; a feature with no placement leaves it unset.
|
|
101
111
|
*/
|
|
102
|
-
grantsFeatureAnywhere(featureId) {
|
|
103
|
-
|
|
112
|
+
grantsFeatureAnywhere(featureId, options = {}) {
|
|
113
|
+
const counts = (item) => !options.enforced || this.enforcementFor(item) === "on";
|
|
114
|
+
if (counts() && this.decideFeature(featureId).granted)
|
|
104
115
|
return true;
|
|
105
116
|
for (const id of this.itemSettings.keys()) {
|
|
117
|
+
const settings = this.itemSettingsFor(id);
|
|
118
|
+
if (!counts(settings ? { id, settings } : undefined))
|
|
119
|
+
continue;
|
|
106
120
|
if (this.decideFeature(featureId, { level: "item", scopeId: id }).granted) {
|
|
107
121
|
return true;
|
|
108
122
|
}
|
|
@@ -172,14 +186,15 @@ export class ToolPolicyEngine {
|
|
|
172
186
|
const hostDenial = this.hostFeatureGate(featureId);
|
|
173
187
|
if (hostDenial)
|
|
174
188
|
return hostDenial;
|
|
189
|
+
const item = this.itemForScope(scope);
|
|
175
190
|
return interpretFeatureResult(featureId, this.pnpPolicySource.resolveFeature(featureId, {
|
|
176
191
|
assessment: this.assessment ?? undefined,
|
|
177
|
-
item
|
|
192
|
+
item,
|
|
178
193
|
}),
|
|
179
194
|
// `resolveFeature` takes the assessment as `undefined` either way, so the
|
|
180
195
|
// source cannot tell an unbound host from one whose profile is silent.
|
|
181
196
|
// The engine can.
|
|
182
|
-
{ assessmentBound: this.assessment !== null });
|
|
197
|
+
{ assessmentBound: this.assessment !== null }, resolveToolParameters(featureId, this.assessment, item));
|
|
183
198
|
}
|
|
184
199
|
/**
|
|
185
200
|
* The host gates that hold for a feature id, or `null` when none fires.
|
|
@@ -239,9 +254,12 @@ export class ToolPolicyEngine {
|
|
|
239
254
|
}
|
|
240
255
|
if ("assessment" in patch) {
|
|
241
256
|
const next = patch.assessment ?? null;
|
|
242
|
-
|
|
243
|
-
changed = true;
|
|
257
|
+
const assessmentChanged = !structurallyEqual(this.assessment, next);
|
|
244
258
|
this.assessment = next;
|
|
259
|
+
if (assessmentChanged) {
|
|
260
|
+
changed = true;
|
|
261
|
+
this.refreshInputDiagnostics();
|
|
262
|
+
}
|
|
245
263
|
}
|
|
246
264
|
if ("pnpEnforcement" in patch) {
|
|
247
265
|
const next = patch.pnpEnforcement ?? null;
|
|
@@ -264,9 +282,12 @@ export class ToolPolicyEngine {
|
|
|
264
282
|
*/
|
|
265
283
|
replaceToolRegistry(toolRegistry, tools) {
|
|
266
284
|
this.assertNotDisposed();
|
|
285
|
+
this.unsubscribeRegistry();
|
|
267
286
|
this.toolRegistry = toolRegistry;
|
|
268
287
|
this.pnpPolicySource = new PnpPolicySource(toolRegistry);
|
|
288
|
+
this.unsubscribeRegistry = this.watchRegistry();
|
|
269
289
|
this.tools = tools;
|
|
290
|
+
this.refreshInputDiagnostics();
|
|
270
291
|
this.emit({ reason: "inputs", inputs: this.snapshotInputs() });
|
|
271
292
|
}
|
|
272
293
|
registerPolicySource(source) {
|
|
@@ -278,15 +299,15 @@ export class ToolPolicyEngine {
|
|
|
278
299
|
});
|
|
279
300
|
return () => {
|
|
280
301
|
const idx = this.customSources.indexOf(source);
|
|
281
|
-
if (idx
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
}
|
|
302
|
+
if (idx === -1)
|
|
303
|
+
return;
|
|
304
|
+
this.customSources.splice(idx, 1);
|
|
305
|
+
if (this.disposed)
|
|
306
|
+
return;
|
|
307
|
+
this.emit({
|
|
308
|
+
reason: "policy-source-removed",
|
|
309
|
+
inputs: this.snapshotInputs(),
|
|
310
|
+
});
|
|
290
311
|
};
|
|
291
312
|
}
|
|
292
313
|
onPolicyChange(listener) {
|
|
@@ -302,6 +323,7 @@ export class ToolPolicyEngine {
|
|
|
302
323
|
if (this.disposed)
|
|
303
324
|
return;
|
|
304
325
|
this.disposed = true;
|
|
326
|
+
this.unsubscribeRegistry();
|
|
305
327
|
this.emit({
|
|
306
328
|
reason: "disposed",
|
|
307
329
|
inputs: this.snapshotInputs(),
|
|
@@ -316,6 +338,8 @@ export class ToolPolicyEngine {
|
|
|
316
338
|
assessment: this.assessment,
|
|
317
339
|
pnpEnforcement: this.enforcementFor(),
|
|
318
340
|
pnpEnforcementOverride: this.pnpEnforcementOverride,
|
|
341
|
+
assessmentExpected: !this.assessmentOptional || this.pnpEnforcementOverride === "on",
|
|
342
|
+
diagnostics: this.inputDiagnostics,
|
|
319
343
|
});
|
|
320
344
|
}
|
|
321
345
|
/** The override, else auto-mode over the assessment and `item`'s settings. */
|
|
@@ -333,8 +357,41 @@ export class ToolPolicyEngine {
|
|
|
333
357
|
emitIfItemSettingsChanged(itemId, before) {
|
|
334
358
|
if (structurallyEqual(before, this.itemSettingsFor(itemId)))
|
|
335
359
|
return;
|
|
360
|
+
this.refreshInputDiagnostics();
|
|
336
361
|
this.emit({ reason: "item-settings", inputs: this.snapshotInputs() });
|
|
337
362
|
}
|
|
363
|
+
/**
|
|
364
|
+
* Recompute {@link ResolvedEngineInputs.diagnostics} from the bound
|
|
365
|
+
* assessment, every mounted item's settings and the registry. Returns
|
|
366
|
+
* whether they changed.
|
|
367
|
+
*/
|
|
368
|
+
refreshInputDiagnostics() {
|
|
369
|
+
const items = [];
|
|
370
|
+
for (const id of this.itemSettings.keys()) {
|
|
371
|
+
const settings = this.itemSettingsFor(id);
|
|
372
|
+
if (settings)
|
|
373
|
+
items.push(settings);
|
|
374
|
+
}
|
|
375
|
+
const next = Array.from(this.pnpPolicySource.unknownSupportIds(this.assessment, items), ([supportId, origins]) => unknownSupportIdDiagnostic(supportId, origins));
|
|
376
|
+
if (structurallyEqual(this.inputDiagnostics, next))
|
|
377
|
+
return false;
|
|
378
|
+
this.inputDiagnostics = Object.freeze(next);
|
|
379
|
+
return true;
|
|
380
|
+
}
|
|
381
|
+
/**
|
|
382
|
+
* Registering a tool into the bound registry, or removing one, can make a
|
|
383
|
+
* named id known or unknown, so it emits an `"inputs"` change when the input
|
|
384
|
+
* diagnostics move.
|
|
385
|
+
*/
|
|
386
|
+
watchRegistry() {
|
|
387
|
+
return this.toolRegistry.onRegistryChange(() => {
|
|
388
|
+
if (this.disposed)
|
|
389
|
+
return;
|
|
390
|
+
if (this.refreshInputDiagnostics()) {
|
|
391
|
+
this.emit({ reason: "inputs", inputs: this.snapshotInputs() });
|
|
392
|
+
}
|
|
393
|
+
});
|
|
394
|
+
}
|
|
338
395
|
/**
|
|
339
396
|
* The registered item an item scope names, by its canonical id. A scope
|
|
340
397
|
* of any other level names none.
|
|
@@ -52,7 +52,7 @@ export declare function composeDecision(inputs: ComposeDecisionInputs): ToolPoli
|
|
|
52
52
|
export declare function overrideBlockedDiagnostic(toolId: string, rule: OverrideBlockedDetails["rule"], level?: ToolPlacementLevel): ToolPolicyDiagnostic;
|
|
53
53
|
/**
|
|
54
54
|
* A `tool-policy.unknownSupportId` diagnostic for an id the registry lacks,
|
|
55
|
-
*
|
|
56
|
-
*
|
|
55
|
+
* naming every list that names it. It describes the engine's inputs rather
|
|
56
|
+
* than a decision, so it carries no level.
|
|
57
57
|
*/
|
|
58
|
-
export declare function unknownSupportIdDiagnostic(supportId: string, origins: readonly PnpPolicySourceRule[]
|
|
58
|
+
export declare function unknownSupportIdDiagnostic(supportId: string, origins: readonly PnpPolicySourceRule[]): ToolPolicyDiagnostic;
|
|
@@ -12,6 +12,7 @@
|
|
|
12
12
|
* `tests/policy/compose-decision.test.ts` lock the orchestration in.
|
|
13
13
|
*/
|
|
14
14
|
import { normalizeToolList, } from "../../services/tools-config-normalizer.js";
|
|
15
|
+
import { resolveToolParameters } from "./tool-parameters.js";
|
|
15
16
|
import { ToolPolicyProvenanceBuilder, } from "./provenance.js";
|
|
16
17
|
export function composeDecision(inputs) {
|
|
17
18
|
const { request, tools, pnpPolicy, customSources, contextId } = inputs;
|
|
@@ -66,7 +67,7 @@ export function composeDecision(inputs) {
|
|
|
66
67
|
}
|
|
67
68
|
return true;
|
|
68
69
|
});
|
|
69
|
-
// Step 3 — Host
|
|
70
|
+
// Step 3 — Host allowlist (only when non-empty).
|
|
70
71
|
if (allowed.length > 0) {
|
|
71
72
|
const allowedSet = new Set(allowed);
|
|
72
73
|
candidates = candidates.filter((toolId) => {
|
|
@@ -134,19 +135,12 @@ export function composeDecision(inputs) {
|
|
|
134
135
|
value: decision.value,
|
|
135
136
|
});
|
|
136
137
|
}
|
|
137
|
-
// An id no tool is registered under matches nothing placed, so whatever it
|
|
138
|
-
// names is absent with no trace of why. Reported per decision because the
|
|
139
|
-
// ids arrive with the profile and settings, after the tools config.
|
|
140
|
-
for (const [supportId, origins] of pnpPolicyResult.unmappedSupportIds) {
|
|
141
|
-
diagnostics.push(unknownSupportIdDiagnostic(supportId, origins, request.level));
|
|
142
|
-
}
|
|
143
138
|
for (const [toolId, rule] of pnpPolicyResult.blockedOverrides) {
|
|
144
139
|
diagnostics.push(overrideBlockedDiagnostic(toolId, rule, request.level));
|
|
145
140
|
}
|
|
146
141
|
// 5a — remove PNP/profile-blocked tools from the candidate set.
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
});
|
|
142
|
+
const { blockedToolIds } = pnpPolicyResult;
|
|
143
|
+
candidates = candidates.filter((toolId) => !blockedToolIds.has(toolId));
|
|
150
144
|
// 5b — surface requiredToolBlocked diagnostics ONLY for
|
|
151
145
|
// PNP/profile-mandated tools that the host removed (i.e., the tool was
|
|
152
146
|
// NOT in `postHostCandidates`). Mandated tools removed by
|
|
@@ -154,20 +148,24 @@ export function composeDecision(inputs) {
|
|
|
154
148
|
// blocking a `requiredTools` mandate) are an internal policy
|
|
155
149
|
// resolution and must not be reported as a host conflict — the
|
|
156
150
|
// loser's `block` decision is already in the trail with full
|
|
157
|
-
// provenance.
|
|
151
|
+
// provenance. A mandate names no level, so a tool placed at another
|
|
152
|
+
// level is served there: only placement at no level is a removal.
|
|
158
153
|
//
|
|
159
154
|
// `details` carries `{ rule, hostRule, hostValue }` so consumers
|
|
160
155
|
// can render the conflict as a single sentence without
|
|
161
156
|
// re-deriving the host gate from `provenance.features`. See
|
|
162
157
|
// `RequiredToolBlockedDetails` for the typed shape.
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
if (
|
|
158
|
+
const placedAtAnyLevel = new Set(Object.values(tools.placement).flatMap(normalizeToolList));
|
|
159
|
+
for (const [mandatedToolId, ruleName] of pnpPolicyResult.mandates) {
|
|
160
|
+
if (postHostCandidates.has(mandatedToolId))
|
|
161
|
+
continue;
|
|
162
|
+
if (!placement.includes(mandatedToolId) &&
|
|
163
|
+
placedAtAnyLevel.has(mandatedToolId)) {
|
|
166
164
|
continue;
|
|
167
|
-
|
|
168
|
-
const ruleName = flag?.rule ?? "required-tool";
|
|
165
|
+
}
|
|
169
166
|
const hostGate = detectHostRemovalGate(mandatedToolId, {
|
|
170
|
-
|
|
167
|
+
placedAtAnyLevel,
|
|
168
|
+
allTools: tools.placement,
|
|
171
169
|
allowed,
|
|
172
170
|
blocked,
|
|
173
171
|
providers: tools.providers,
|
|
@@ -181,7 +179,9 @@ export function composeDecision(inputs) {
|
|
|
181
179
|
code: "tool-policy.requiredToolBlocked",
|
|
182
180
|
level: request.level,
|
|
183
181
|
toolId: mandatedToolId,
|
|
184
|
-
message:
|
|
182
|
+
message: hostGate.hostRule === "placement-missing"
|
|
183
|
+
? `Profile policy mandates "${mandatedToolId}" (${ruleName}), but no level of tools.placement lists it.`
|
|
184
|
+
: `Profile policy mandates "${mandatedToolId}" (${ruleName}), but host policy removes it via ${hostGate.hostRule}.`,
|
|
185
185
|
details,
|
|
186
186
|
});
|
|
187
187
|
builder.addDecision({
|
|
@@ -288,7 +288,8 @@ export function composeDecision(inputs) {
|
|
|
288
288
|
toolId,
|
|
289
289
|
required: flag?.required ?? false,
|
|
290
290
|
alwaysAvailable: flag?.alwaysAvailable ?? false,
|
|
291
|
-
|
|
291
|
+
activateAtInit: flag?.activateAtInit ?? false,
|
|
292
|
+
parameters: resolveToolParameters(toolId, pnpPolicy.assessment, pnpPolicy.item),
|
|
292
293
|
};
|
|
293
294
|
});
|
|
294
295
|
builder.reconcileFinalStates(survivingIds);
|
|
@@ -305,10 +306,11 @@ export function composeDecision(inputs) {
|
|
|
305
306
|
* (blocklist) last — so the FIRST gate that would have matched wins,
|
|
306
307
|
* which is the gate the pipeline actually invoked. Subsequent gates
|
|
307
308
|
* never get to evaluate a tool that an earlier step already removed.
|
|
309
|
+
* Step 5b passes only a tool this level places or no level places.
|
|
308
310
|
*/
|
|
309
311
|
function detectHostRemovalGate(toolId, args) {
|
|
310
|
-
if (!args.
|
|
311
|
-
return { hostRule: "placement-missing", hostValue: args.
|
|
312
|
+
if (!args.placedAtAnyLevel.has(toolId)) {
|
|
313
|
+
return { hostRule: "placement-missing", hostValue: args.allTools };
|
|
312
314
|
}
|
|
313
315
|
if (args.providers?.[toolId]?.enabled === false) {
|
|
314
316
|
return { hostRule: "provider-disabled", hostValue: false };
|
|
@@ -322,11 +324,11 @@ function detectHostRemovalGate(toolId, args) {
|
|
|
322
324
|
hostValue: Array.from(args.blocked),
|
|
323
325
|
};
|
|
324
326
|
}
|
|
325
|
-
// Defensive:
|
|
326
|
-
//
|
|
327
|
-
//
|
|
328
|
-
//
|
|
329
|
-
return { hostRule: "placement-missing", hostValue: args.
|
|
327
|
+
// Defensive: at the call site the tool is in `mandates` but not in
|
|
328
|
+
// `postHostCandidates`, so one of the four gates above MUST have
|
|
329
|
+
// fired. If none did, the host pipeline has a bug; surface a
|
|
330
|
+
// best-effort rather than throwing.
|
|
331
|
+
return { hostRule: "placement-missing", hostValue: args.allTools };
|
|
330
332
|
}
|
|
331
333
|
/** Where each PNP/profile rule's ids are authored. */
|
|
332
334
|
const PNP_RULE_FIELDS = {
|
|
@@ -337,6 +339,7 @@ const PNP_RULE_FIELDS = {
|
|
|
337
339
|
"item-requirement": "item settings.requiredTools",
|
|
338
340
|
"district-requirement": "settings.districtPolicy.requiredTools",
|
|
339
341
|
"pnp-support": "personalNeedsProfile.supports",
|
|
342
|
+
"pnp-activate-at-init": "personalNeedsProfile.activateAtInit",
|
|
340
343
|
};
|
|
341
344
|
/**
|
|
342
345
|
* A `tool-policy.overrideBlocked` diagnostic for a tool a `true` test
|
|
@@ -354,14 +357,13 @@ export function overrideBlockedDiagnostic(toolId, rule, level) {
|
|
|
354
357
|
}
|
|
355
358
|
/**
|
|
356
359
|
* A `tool-policy.unknownSupportId` diagnostic for an id the registry lacks,
|
|
357
|
-
*
|
|
358
|
-
*
|
|
360
|
+
* naming every list that names it. It describes the engine's inputs rather
|
|
361
|
+
* than a decision, so it carries no level.
|
|
359
362
|
*/
|
|
360
|
-
export function unknownSupportIdDiagnostic(supportId, origins
|
|
363
|
+
export function unknownSupportIdDiagnostic(supportId, origins) {
|
|
361
364
|
const fields = origins.map((rule) => PNP_RULE_FIELDS[rule]).join(", ");
|
|
362
365
|
return {
|
|
363
366
|
code: "tool-policy.unknownSupportId",
|
|
364
|
-
...(level ? { level } : {}),
|
|
365
367
|
toolId: supportId,
|
|
366
368
|
message: `No tool is registered under "${supportId}", named in ${fields}, so it matches nothing. These lists name tools by tool id.`,
|
|
367
369
|
details: { origins: [...origins] },
|