@ffschrattenecker/tm1-mcp-server 6.0.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/CHANGELOG.md +1211 -0
- package/LICENSE +21 -0
- package/NOTICE +34 -0
- package/README.md +276 -0
- package/dist/config.d.ts +35 -0
- package/dist/config.js +238 -0
- package/dist/http-transport.d.ts +8 -0
- package/dist/http-transport.js +132 -0
- package/dist/index.d.ts +18 -0
- package/dist/index.js +164 -0
- package/dist/lib/callgraph/callGraph.d.ts +124 -0
- package/dist/lib/callgraph/callGraph.js +334 -0
- package/dist/lib/callgraph/choreGraph.d.ts +23 -0
- package/dist/lib/callgraph/choreGraph.js +102 -0
- package/dist/lib/callgraph/dataFlow.d.ts +74 -0
- package/dist/lib/callgraph/dataFlow.js +271 -0
- package/dist/lib/callgraph/datasourceMembership.d.ts +31 -0
- package/dist/lib/callgraph/datasourceMembership.js +142 -0
- package/dist/lib/callgraph/lintTypes.d.ts +28 -0
- package/dist/lib/callgraph/lintTypes.js +2 -0
- package/dist/lib/callgraph/mdxMembers.d.ts +29 -0
- package/dist/lib/callgraph/mdxMembers.js +97 -0
- package/dist/lib/callgraph/referenceIndex.d.ts +179 -0
- package/dist/lib/callgraph/referenceIndex.js +584 -0
- package/dist/lib/callgraph/rulesLinter.d.ts +55 -0
- package/dist/lib/callgraph/rulesLinter.js +776 -0
- package/dist/lib/callgraph/rulesParser.d.ts +26 -0
- package/dist/lib/callgraph/rulesParser.js +71 -0
- package/dist/lib/callgraph/subsetUsage.d.ts +16 -0
- package/dist/lib/callgraph/subsetUsage.js +134 -0
- package/dist/lib/callgraph/tiParser.d.ts +21 -0
- package/dist/lib/callgraph/tiParser.js +672 -0
- package/dist/lib/callgraph/tiSignatures.d.ts +32 -0
- package/dist/lib/callgraph/tiSignatures.js +6185 -0
- package/dist/lib/callgraph/tm1-adapter.d.ts +32 -0
- package/dist/lib/callgraph/tm1-adapter.js +159 -0
- package/dist/lib/callgraph/types.d.ts +53 -0
- package/dist/lib/callgraph/types.js +2 -0
- package/dist/lib/callgraph/variableEnv.d.ts +86 -0
- package/dist/lib/callgraph/variableEnv.js +214 -0
- package/dist/lib/cell-address.d.ts +12 -0
- package/dist/lib/cell-address.js +71 -0
- package/dist/lib/complexity/antipatterns.d.ts +22 -0
- package/dist/lib/complexity/antipatterns.js +302 -0
- package/dist/lib/complexity/comment-classifier.d.ts +24 -0
- package/dist/lib/complexity/comment-classifier.js +43 -0
- package/dist/lib/complexity/cross-process.d.ts +78 -0
- package/dist/lib/complexity/cross-process.js +114 -0
- package/dist/lib/complexity/process-metrics.d.ts +78 -0
- package/dist/lib/complexity/process-metrics.js +278 -0
- package/dist/lib/complexity/rules-metrics.d.ts +31 -0
- package/dist/lib/complexity/rules-metrics.js +99 -0
- package/dist/lib/concurrency.d.ts +11 -0
- package/dist/lib/concurrency.js +27 -0
- package/dist/lib/control-name.d.ts +10 -0
- package/dist/lib/control-name.js +10 -0
- package/dist/lib/coordinate-error.d.ts +3 -0
- package/dist/lib/coordinate-error.js +29 -0
- package/dist/lib/credential-format.d.ts +23 -0
- package/dist/lib/credential-format.js +25 -0
- package/dist/lib/cube-stats/fetcher.d.ts +106 -0
- package/dist/lib/cube-stats/fetcher.js +194 -0
- package/dist/lib/feeders/brackets.d.ts +47 -0
- package/dist/lib/feeders/brackets.js +195 -0
- package/dist/lib/feeders/element-type-cache.d.ts +42 -0
- package/dist/lib/feeders/element-type-cache.js +86 -0
- package/dist/lib/feeders/static-heuristics.d.ts +101 -0
- package/dist/lib/feeders/static-heuristics.js +202 -0
- package/dist/lib/git-process.d.ts +67 -0
- package/dist/lib/git-process.js +243 -0
- package/dist/lib/mask-secrets.d.ts +10 -0
- package/dist/lib/mask-secrets.js +99 -0
- package/dist/lib/mdx.d.ts +3 -0
- package/dist/lib/mdx.js +13 -0
- package/dist/lib/naming/odata-filter.d.ts +15 -0
- package/dist/lib/naming/odata-filter.js +81 -0
- package/dist/lib/naming/rules.d.ts +34 -0
- package/dist/lib/naming/rules.js +215 -0
- package/dist/lib/pro-parser.d.ts +19 -0
- package/dist/lib/pro-parser.js +260 -0
- package/dist/lib/pro-serializer.d.ts +19 -0
- package/dist/lib/pro-serializer.js +170 -0
- package/dist/lib/process-parts-schema.d.ts +45 -0
- package/dist/lib/process-parts-schema.js +46 -0
- package/dist/lib/process-refs.d.ts +88 -0
- package/dist/lib/process-refs.js +441 -0
- package/dist/lib/rules-outline.d.ts +29 -0
- package/dist/lib/rules-outline.js +68 -0
- package/dist/lib/rules-patch.d.ts +6 -0
- package/dist/lib/rules-patch.js +59 -0
- package/dist/lib/safe-regex.d.ts +15 -0
- package/dist/lib/safe-regex.js +37 -0
- package/dist/lib/sample-cells.d.ts +48 -0
- package/dist/lib/sample-cells.js +146 -0
- package/dist/lib/slim-json-schema.d.ts +20 -0
- package/dist/lib/slim-json-schema.js +68 -0
- package/dist/lib/strip-comments.d.ts +23 -0
- package/dist/lib/strip-comments.js +61 -0
- package/dist/lib/tm1-events.d.ts +16 -0
- package/dist/lib/tm1-events.js +29 -0
- package/dist/lib/v12-compat/deprecated-ti.d.ts +17 -0
- package/dist/lib/v12-compat/deprecated-ti.js +257 -0
- package/dist/lib/v12-compat/scanner.d.ts +10 -0
- package/dist/lib/v12-compat/scanner.js +43 -0
- package/dist/lib/variables-ui-data.d.ts +26 -0
- package/dist/lib/variables-ui-data.js +77 -0
- package/dist/load-env.d.ts +2 -0
- package/dist/load-env.js +29 -0
- package/dist/logger.d.ts +4 -0
- package/dist/logger.js +60 -0
- package/dist/prompts/index.d.ts +3 -0
- package/dist/prompts/index.js +141 -0
- package/dist/resources/index.d.ts +5 -0
- package/dist/resources/index.js +237 -0
- package/dist/resources/list-handler.d.ts +40 -0
- package/dist/resources/list-handler.js +86 -0
- package/dist/resources/subscriptions.d.ts +19 -0
- package/dist/resources/subscriptions.js +80 -0
- package/dist/schemas/cells.d.ts +17 -0
- package/dist/schemas/cells.js +13 -0
- package/dist/schemas/common.d.ts +16 -0
- package/dist/schemas/common.js +14 -0
- package/dist/schemas/index.d.ts +10 -0
- package/dist/schemas/index.js +23 -0
- package/dist/schemas/metadata.d.ts +70 -0
- package/dist/schemas/metadata.js +47 -0
- package/dist/schemas/monitoring.d.ts +95 -0
- package/dist/schemas/monitoring.js +69 -0
- package/dist/schemas/processes.d.ts +74 -0
- package/dist/schemas/processes.js +66 -0
- package/dist/schemas/scheduling.d.ts +13 -0
- package/dist/schemas/scheduling.js +13 -0
- package/dist/schemas/security.d.ts +19 -0
- package/dist/schemas/security.js +16 -0
- package/dist/schemas/subsets.d.ts +12 -0
- package/dist/schemas/subsets.js +12 -0
- package/dist/schemas/views.d.ts +9 -0
- package/dist/schemas/views.js +9 -0
- package/dist/session-manager.d.ts +79 -0
- package/dist/session-manager.js +281 -0
- package/dist/tm1-client/connection/profile.d.ts +13 -0
- package/dist/tm1-client/connection/profile.js +99 -0
- package/dist/tm1-client/dispatcher.d.ts +5 -0
- package/dist/tm1-client/dispatcher.js +31 -0
- package/dist/tm1-client/http.d.ts +81 -0
- package/dist/tm1-client/http.js +547 -0
- package/dist/tm1-client/services/batch-service.d.ts +123 -0
- package/dist/tm1-client/services/batch-service.js +455 -0
- package/dist/tm1-client/services/cell-service.d.ts +71 -0
- package/dist/tm1-client/services/cell-service.js +333 -0
- package/dist/tm1-client/services/cellset-transform.d.ts +26 -0
- package/dist/tm1-client/services/cellset-transform.js +80 -0
- package/dist/tm1-client/services/chore-service.d.ts +68 -0
- package/dist/tm1-client/services/chore-service.js +179 -0
- package/dist/tm1-client/services/chore-status.d.ts +11 -0
- package/dist/tm1-client/services/chore-status.js +127 -0
- package/dist/tm1-client/services/cube-service.d.ts +134 -0
- package/dist/tm1-client/services/cube-service.js +294 -0
- package/dist/tm1-client/services/dimension-service.d.ts +118 -0
- package/dist/tm1-client/services/dimension-service.js +249 -0
- package/dist/tm1-client/services/element-service.d.ts +245 -0
- package/dist/tm1-client/services/element-service.js +809 -0
- package/dist/tm1-client/services/fallback.d.ts +44 -0
- package/dist/tm1-client/services/fallback.js +72 -0
- package/dist/tm1-client/services/file-service.d.ts +53 -0
- package/dist/tm1-client/services/file-service.js +218 -0
- package/dist/tm1-client/services/hierarchy-service.d.ts +129 -0
- package/dist/tm1-client/services/hierarchy-service.js +332 -0
- package/dist/tm1-client/services/monitoring-service.d.ts +34 -0
- package/dist/tm1-client/services/monitoring-service.js +123 -0
- package/dist/tm1-client/services/odata-page.d.ts +71 -0
- package/dist/tm1-client/services/odata-page.js +87 -0
- package/dist/tm1-client/services/process-service.d.ts +278 -0
- package/dist/tm1-client/services/process-service.js +874 -0
- package/dist/tm1-client/services/process-status.d.ts +21 -0
- package/dist/tm1-client/services/process-status.js +89 -0
- package/dist/tm1-client/services/security-service.d.ts +50 -0
- package/dist/tm1-client/services/security-service.js +93 -0
- package/dist/tm1-client/services/server-service.d.ts +116 -0
- package/dist/tm1-client/services/server-service.js +504 -0
- package/dist/tm1-client/services/subset-service.d.ts +37 -0
- package/dist/tm1-client/services/subset-service.js +122 -0
- package/dist/tm1-client/services/view-service.d.ts +46 -0
- package/dist/tm1-client/services/view-service.js +287 -0
- package/dist/tm1-client.d.ts +56 -0
- package/dist/tm1-client.js +126 -0
- package/dist/tools/analysis/analyze-callgraph.d.ts +28 -0
- package/dist/tools/analysis/analyze-callgraph.js +350 -0
- package/dist/tools/analysis/analyze-chore-graph.d.ts +2 -0
- package/dist/tools/analysis/analyze-chore-graph.js +148 -0
- package/dist/tools/analysis/analyze-object-usage.d.ts +2 -0
- package/dist/tools/analysis/analyze-object-usage.js +143 -0
- package/dist/tools/analysis/audit-complexity.d.ts +2 -0
- package/dist/tools/analysis/audit-complexity.js +255 -0
- package/dist/tools/analysis/audit-feeders.d.ts +2 -0
- package/dist/tools/analysis/audit-feeders.js +417 -0
- package/dist/tools/analysis/audit-naming.d.ts +2 -0
- package/dist/tools/analysis/audit-naming.js +379 -0
- package/dist/tools/analysis/check-v12-readiness.d.ts +2 -0
- package/dist/tools/analysis/check-v12-readiness.js +136 -0
- package/dist/tools/analysis/find-orphan-dimensions.d.ts +2 -0
- package/dist/tools/analysis/find-orphan-dimensions.js +55 -0
- package/dist/tools/analysis/invalidate-callgraph-cache.d.ts +2 -0
- package/dist/tools/analysis/invalidate-callgraph-cache.js +40 -0
- package/dist/tools/analysis/trace-data-flow.d.ts +2 -0
- package/dist/tools/analysis/trace-data-flow.js +138 -0
- package/dist/tools/annotations.d.ts +12 -0
- package/dist/tools/annotations.js +61 -0
- package/dist/tools/celldata/check-feeders.d.ts +2 -0
- package/dist/tools/celldata/check-feeders.js +48 -0
- package/dist/tools/celldata/check-writable-coords.d.ts +2 -0
- package/dist/tools/celldata/check-writable-coords.js +126 -0
- package/dist/tools/celldata/execute-mdx.d.ts +17 -0
- package/dist/tools/celldata/execute-mdx.js +126 -0
- package/dist/tools/celldata/get-cell-value.d.ts +2 -0
- package/dist/tools/celldata/get-cell-value.js +30 -0
- package/dist/tools/celldata/get-view-definition.d.ts +2 -0
- package/dist/tools/celldata/get-view-definition.js +29 -0
- package/dist/tools/celldata/get-view.d.ts +2 -0
- package/dist/tools/celldata/get-view.js +55 -0
- package/dist/tools/celldata/sample-cells.d.ts +2 -0
- package/dist/tools/celldata/sample-cells.js +101 -0
- package/dist/tools/celldata/trace-cell-calculation.d.ts +2 -0
- package/dist/tools/celldata/trace-cell-calculation.js +53 -0
- package/dist/tools/celldata/trace-feeders.d.ts +2 -0
- package/dist/tools/celldata/trace-feeders.js +44 -0
- package/dist/tools/celldata/write-cells.d.ts +2 -0
- package/dist/tools/celldata/write-cells.js +65 -0
- package/dist/tools/confirm.d.ts +10 -0
- package/dist/tools/confirm.js +64 -0
- package/dist/tools/define-tool.d.ts +51 -0
- package/dist/tools/define-tool.js +49 -0
- package/dist/tools/dimension-management/bulk-upsert-elements.d.ts +2 -0
- package/dist/tools/dimension-management/bulk-upsert-elements.js +103 -0
- package/dist/tools/dimension-management/create-dimension.d.ts +2 -0
- package/dist/tools/dimension-management/create-dimension.js +22 -0
- package/dist/tools/dimension-management/create-element-attribute.d.ts +2 -0
- package/dist/tools/dimension-management/create-element-attribute.js +26 -0
- package/dist/tools/dimension-management/create-element.d.ts +2 -0
- package/dist/tools/dimension-management/create-element.js +31 -0
- package/dist/tools/dimension-management/create-hierarchy.d.ts +2 -0
- package/dist/tools/dimension-management/create-hierarchy.js +22 -0
- package/dist/tools/dimension-management/delete-dimension.d.ts +2 -0
- package/dist/tools/dimension-management/delete-dimension.js +25 -0
- package/dist/tools/dimension-management/delete-element.d.ts +2 -0
- package/dist/tools/dimension-management/delete-element.js +26 -0
- package/dist/tools/dimension-management/delete-elements.d.ts +2 -0
- package/dist/tools/dimension-management/delete-elements.js +44 -0
- package/dist/tools/dimension-management/delete-hierarchy.d.ts +2 -0
- package/dist/tools/dimension-management/delete-hierarchy.js +35 -0
- package/dist/tools/dimension-management/get-element-attribute-values.d.ts +2 -0
- package/dist/tools/dimension-management/get-element-attribute-values.js +77 -0
- package/dist/tools/dimension-management/list-element-attributes.d.ts +2 -0
- package/dist/tools/dimension-management/list-element-attributes.js +31 -0
- package/dist/tools/dimension-management/move-element.d.ts +2 -0
- package/dist/tools/dimension-management/move-element.js +28 -0
- package/dist/tools/dimension-management/update-element-attribute-value.d.ts +2 -0
- package/dist/tools/dimension-management/update-element-attribute-value.js +80 -0
- package/dist/tools/dimension-management/update-element.d.ts +2 -0
- package/dist/tools/dimension-management/update-element.js +35 -0
- package/dist/tools/error-format.d.ts +22 -0
- package/dist/tools/error-format.js +130 -0
- package/dist/tools/fileops/delete-file.d.ts +2 -0
- package/dist/tools/fileops/delete-file.js +32 -0
- package/dist/tools/fileops/get-file-content.d.ts +2 -0
- package/dist/tools/fileops/get-file-content.js +76 -0
- package/dist/tools/fileops/list-files.d.ts +2 -0
- package/dist/tools/fileops/list-files.js +43 -0
- package/dist/tools/fileops/search-files.d.ts +2 -0
- package/dist/tools/fileops/search-files.js +76 -0
- package/dist/tools/fileops/upload-file.d.ts +2 -0
- package/dist/tools/fileops/upload-file.js +69 -0
- package/dist/tools/format.d.ts +57 -0
- package/dist/tools/format.js +157 -0
- package/dist/tools/hierarchy.d.ts +6 -0
- package/dist/tools/hierarchy.js +27 -0
- package/dist/tools/index.d.ts +4 -0
- package/dist/tools/index.js +263 -0
- package/dist/tools/local-file.d.ts +16 -0
- package/dist/tools/local-file.js +88 -0
- package/dist/tools/metadata/get-ancestors.d.ts +2 -0
- package/dist/tools/metadata/get-ancestors.js +36 -0
- package/dist/tools/metadata/get-descendants.d.ts +2 -0
- package/dist/tools/metadata/get-descendants.js +64 -0
- package/dist/tools/metadata/get-hierarchy.d.ts +2 -0
- package/dist/tools/metadata/get-hierarchy.js +130 -0
- package/dist/tools/metadata/list-chores.d.ts +2 -0
- package/dist/tools/metadata/list-chores.js +62 -0
- package/dist/tools/metadata/list-cubes.d.ts +2 -0
- package/dist/tools/metadata/list-cubes.js +128 -0
- package/dist/tools/metadata/list-dimensions.d.ts +2 -0
- package/dist/tools/metadata/list-dimensions.js +131 -0
- package/dist/tools/metadata/list-processes-grouped.d.ts +2 -0
- package/dist/tools/metadata/list-processes-grouped.js +96 -0
- package/dist/tools/metadata/list-processes.d.ts +2 -0
- package/dist/tools/metadata/list-processes.js +108 -0
- package/dist/tools/metadata/resolve-default-members.d.ts +2 -0
- package/dist/tools/metadata/resolve-default-members.js +46 -0
- package/dist/tools/model-building/check-cube-rule.d.ts +2 -0
- package/dist/tools/model-building/check-cube-rule.js +51 -0
- package/dist/tools/model-building/clear-cube.d.ts +2 -0
- package/dist/tools/model-building/clear-cube.js +46 -0
- package/dist/tools/model-building/create-cube.d.ts +2 -0
- package/dist/tools/model-building/create-cube.js +34 -0
- package/dist/tools/model-building/delete-cube.d.ts +2 -0
- package/dist/tools/model-building/delete-cube.js +27 -0
- package/dist/tools/model-building/get-all-cube-rules.d.ts +2 -0
- package/dist/tools/model-building/get-all-cube-rules.js +149 -0
- package/dist/tools/model-building/get-cube-rules.d.ts +2 -0
- package/dist/tools/model-building/get-cube-rules.js +69 -0
- package/dist/tools/model-building/rules-source.d.ts +21 -0
- package/dist/tools/model-building/rules-source.js +49 -0
- package/dist/tools/model-building/search-rules.d.ts +2 -0
- package/dist/tools/model-building/search-rules.js +132 -0
- package/dist/tools/model-building/set-cube-rules.d.ts +2 -0
- package/dist/tools/model-building/set-cube-rules.js +81 -0
- package/dist/tools/model-building/unload-cube.d.ts +2 -0
- package/dist/tools/model-building/unload-cube.js +23 -0
- package/dist/tools/operations/diagnose-process-error.d.ts +2 -0
- package/dist/tools/operations/diagnose-process-error.js +178 -0
- package/dist/tools/operations/error-log-helpers.d.ts +25 -0
- package/dist/tools/operations/error-log-helpers.js +57 -0
- package/dist/tools/operations/get-audit-log.d.ts +2 -0
- package/dist/tools/operations/get-audit-log.js +70 -0
- package/dist/tools/operations/get-cube-stats.d.ts +2 -0
- package/dist/tools/operations/get-cube-stats.js +107 -0
- package/dist/tools/operations/get-error-log-content.d.ts +2 -0
- package/dist/tools/operations/get-error-log-content.js +164 -0
- package/dist/tools/operations/get-jobs.d.ts +3 -0
- package/dist/tools/operations/get-jobs.js +51 -0
- package/dist/tools/operations/get-message-log.d.ts +2 -0
- package/dist/tools/operations/get-message-log.js +63 -0
- package/dist/tools/operations/get-server-info.d.ts +2 -0
- package/dist/tools/operations/get-server-info.js +180 -0
- package/dist/tools/operations/get-server-state.d.ts +2 -0
- package/dist/tools/operations/get-server-state.js +129 -0
- package/dist/tools/operations/get-sessions.d.ts +2 -0
- package/dist/tools/operations/get-sessions.js +76 -0
- package/dist/tools/operations/get-threads.d.ts +3 -0
- package/dist/tools/operations/get-threads.js +50 -0
- package/dist/tools/operations/get-transaction-log.d.ts +2 -0
- package/dist/tools/operations/get-transaction-log.js +63 -0
- package/dist/tools/operations/list-error-logs.d.ts +8 -0
- package/dist/tools/operations/list-error-logs.js +157 -0
- package/dist/tools/operations/save-data.d.ts +2 -0
- package/dist/tools/operations/save-data.js +50 -0
- package/dist/tools/pagination.d.ts +32 -0
- package/dist/tools/pagination.js +116 -0
- package/dist/tools/scheduling/create-chore.d.ts +2 -0
- package/dist/tools/scheduling/create-chore.js +93 -0
- package/dist/tools/scheduling/delete-chore.d.ts +2 -0
- package/dist/tools/scheduling/delete-chore.js +22 -0
- package/dist/tools/scheduling/execute-chore.d.ts +2 -0
- package/dist/tools/scheduling/execute-chore.js +52 -0
- package/dist/tools/scheduling/toggle-chore.d.ts +2 -0
- package/dist/tools/scheduling/toggle-chore.js +22 -0
- package/dist/tools/scheduling/update-chore.d.ts +2 -0
- package/dist/tools/scheduling/update-chore.js +71 -0
- package/dist/tools/schemas/common.d.ts +10 -0
- package/dist/tools/schemas/common.js +23 -0
- package/dist/tools/schemas/items-analysis.d.ts +394 -0
- package/dist/tools/schemas/items-analysis.js +419 -0
- package/dist/tools/schemas/items-cells.d.ts +70 -0
- package/dist/tools/schemas/items-cells.js +65 -0
- package/dist/tools/schemas/items-common.d.ts +18 -0
- package/dist/tools/schemas/items-common.js +39 -0
- package/dist/tools/schemas/items-fileops.d.ts +11 -0
- package/dist/tools/schemas/items-fileops.js +13 -0
- package/dist/tools/schemas/items-metadata.d.ts +262 -0
- package/dist/tools/schemas/items-metadata.js +184 -0
- package/dist/tools/schemas/items-monitoring.d.ts +79 -0
- package/dist/tools/schemas/items-monitoring.js +78 -0
- package/dist/tools/schemas/items-processes.d.ts +279 -0
- package/dist/tools/schemas/items-processes.js +235 -0
- package/dist/tools/schemas/items-scheduling.d.ts +25 -0
- package/dist/tools/schemas/items-scheduling.js +26 -0
- package/dist/tools/schemas/items-security.d.ts +19 -0
- package/dist/tools/schemas/items-security.js +12 -0
- package/dist/tools/schemas/items-subsets.d.ts +2 -0
- package/dist/tools/schemas/items-subsets.js +4 -0
- package/dist/tools/schemas/items-views.d.ts +38 -0
- package/dist/tools/schemas/items-views.js +26 -0
- package/dist/tools/schemas/items.d.ts +12 -0
- package/dist/tools/schemas/items.js +23 -0
- package/dist/tools/schemas/markdown-capable.d.ts +21 -0
- package/dist/tools/schemas/markdown-capable.js +58 -0
- package/dist/tools/schemas/output-schema.d.ts +24 -0
- package/dist/tools/schemas/output-schema.js +25 -0
- package/dist/tools/security/assign-client-group.d.ts +2 -0
- package/dist/tools/security/assign-client-group.js +20 -0
- package/dist/tools/security/create-client.d.ts +2 -0
- package/dist/tools/security/create-client.js +28 -0
- package/dist/tools/security/delete-client.d.ts +2 -0
- package/dist/tools/security/delete-client.js +22 -0
- package/dist/tools/security/get-client.d.ts +2 -0
- package/dist/tools/security/get-client.js +20 -0
- package/dist/tools/security/list-clients.d.ts +2 -0
- package/dist/tools/security/list-clients.js +86 -0
- package/dist/tools/security/list-groups.d.ts +2 -0
- package/dist/tools/security/list-groups.js +43 -0
- package/dist/tools/security/remove-client-group.d.ts +2 -0
- package/dist/tools/security/remove-client-group.js +27 -0
- package/dist/tools/security/update-client.d.ts +2 -0
- package/dist/tools/security/update-client.js +22 -0
- package/dist/tools/subsets/create-subset.d.ts +2 -0
- package/dist/tools/subsets/create-subset.js +44 -0
- package/dist/tools/subsets/delete-subset.d.ts +2 -0
- package/dist/tools/subsets/delete-subset.js +26 -0
- package/dist/tools/subsets/get-subset.d.ts +2 -0
- package/dist/tools/subsets/get-subset.js +29 -0
- package/dist/tools/subsets/list-subsets.d.ts +2 -0
- package/dist/tools/subsets/list-subsets.js +36 -0
- package/dist/tools/subsets/update-subset.d.ts +2 -0
- package/dist/tools/subsets/update-subset.js +33 -0
- package/dist/tools/ti-development/check-process-code.d.ts +2 -0
- package/dist/tools/ti-development/check-process-code.js +96 -0
- package/dist/tools/ti-development/compile-process.d.ts +2 -0
- package/dist/tools/ti-development/compile-process.js +32 -0
- package/dist/tools/ti-development/copy-process.d.ts +2 -0
- package/dist/tools/ti-development/copy-process.js +32 -0
- package/dist/tools/ti-development/delete-process.d.ts +2 -0
- package/dist/tools/ti-development/delete-process.js +26 -0
- package/dist/tools/ti-development/diff-process-with-file.d.ts +2 -0
- package/dist/tools/ti-development/diff-process-with-file.js +208 -0
- package/dist/tools/ti-development/diff-processes.d.ts +2 -0
- package/dist/tools/ti-development/diff-processes.js +312 -0
- package/dist/tools/ti-development/execute-process.d.ts +8 -0
- package/dist/tools/ti-development/execute-process.js +109 -0
- package/dist/tools/ti-development/export-process-to-git.d.ts +2 -0
- package/dist/tools/ti-development/export-process-to-git.js +113 -0
- package/dist/tools/ti-development/export-process-to-pro.d.ts +2 -0
- package/dist/tools/ti-development/export-process-to-pro.js +117 -0
- package/dist/tools/ti-development/get-all-processes-code.d.ts +2 -0
- package/dist/tools/ti-development/get-all-processes-code.js +131 -0
- package/dist/tools/ti-development/get-process-code.d.ts +2 -0
- package/dist/tools/ti-development/get-process-code.js +100 -0
- package/dist/tools/ti-development/get-process-datasource.d.ts +2 -0
- package/dist/tools/ti-development/get-process-datasource.js +20 -0
- package/dist/tools/ti-development/get-process-parameters.d.ts +2 -0
- package/dist/tools/ti-development/get-process-parameters.js +25 -0
- package/dist/tools/ti-development/get-process-variables.d.ts +2 -0
- package/dist/tools/ti-development/get-process-variables.js +38 -0
- package/dist/tools/ti-development/get-process.d.ts +2 -0
- package/dist/tools/ti-development/get-process.js +163 -0
- package/dist/tools/ti-development/import-pro-file.d.ts +2 -0
- package/dist/tools/ti-development/import-pro-file.js +153 -0
- package/dist/tools/ti-development/import-process-from-git.d.ts +2 -0
- package/dist/tools/ti-development/import-process-from-git.js +198 -0
- package/dist/tools/ti-development/install-pro-bundle.d.ts +2 -0
- package/dist/tools/ti-development/install-pro-bundle.js +288 -0
- package/dist/tools/ti-development/preflight.d.ts +39 -0
- package/dist/tools/ti-development/preflight.js +56 -0
- package/dist/tools/ti-development/process-backup.d.ts +29 -0
- package/dist/tools/ti-development/process-backup.js +118 -0
- package/dist/tools/ti-development/search-code.d.ts +2 -0
- package/dist/tools/ti-development/search-code.js +208 -0
- package/dist/tools/ti-development/upsert-process.d.ts +2 -0
- package/dist/tools/ti-development/upsert-process.js +167 -0
- package/dist/tools/ti-development/validate-process-refs.d.ts +2 -0
- package/dist/tools/ti-development/validate-process-refs.js +73 -0
- package/dist/tools/views/create-mdx-view.d.ts +2 -0
- package/dist/tools/views/create-mdx-view.js +21 -0
- package/dist/tools/views/create-native-view.d.ts +2 -0
- package/dist/tools/views/create-native-view.js +81 -0
- package/dist/tools/views/delete-view.d.ts +2 -0
- package/dist/tools/views/delete-view.js +23 -0
- package/dist/tools/views/list-views.d.ts +2 -0
- package/dist/tools/views/list-views.js +32 -0
- package/dist/tools/with-annotations.d.ts +6 -0
- package/dist/tools/with-annotations.js +339 -0
- package/dist/types.d.ts +409 -0
- package/dist/types.js +91 -0
- package/dist/version.d.ts +4 -0
- package/dist/version.js +18 -0
- package/package.json +107 -0
|
@@ -0,0 +1,255 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { computeProcessMetrics, } from "../../lib/complexity/process-metrics.js";
|
|
3
|
+
import { computeRulesMetrics, } from "../../lib/complexity/rules-metrics.js";
|
|
4
|
+
import { clusterVariableNames, findTypeInconsistencies, reportPrefixConvention, groupByCohort, } from "../../lib/complexity/cross-process.js";
|
|
5
|
+
import { lintProcess, } from "../../lib/complexity/antipatterns.js";
|
|
6
|
+
import { AuditComplexityResultSchema } from "../schemas/items.js";
|
|
7
|
+
import { READ_ONLY } from "../annotations.js";
|
|
8
|
+
import { defineTool } from "../define-tool.js";
|
|
9
|
+
const SCOPE_VALUES = [
|
|
10
|
+
"processes",
|
|
11
|
+
"rules",
|
|
12
|
+
"consistency",
|
|
13
|
+
"antipatterns",
|
|
14
|
+
];
|
|
15
|
+
// antipatterns is opt-in (different output shape: a findings list, not a
|
|
16
|
+
// ranked score) and excluded from the default scope.
|
|
17
|
+
const SCOPE_DEFAULT = [
|
|
18
|
+
"processes",
|
|
19
|
+
"rules",
|
|
20
|
+
"consistency",
|
|
21
|
+
];
|
|
22
|
+
export const registerAuditComplexity = defineTool({
|
|
23
|
+
name: "tm1_audit_complexity",
|
|
24
|
+
description: "Bulk-scan TI processes and cube rules for complexity metrics (LOC, branches, max nesting, score) " +
|
|
25
|
+
"and cross-process naming consistency (variant clusters, type conflicts, prefix adherence p/v/n/s, cohorts). " +
|
|
26
|
+
"Cube rules: LOC, rule/feeder counts, DB() coupling, skipcheck/feedstrings flags.",
|
|
27
|
+
annotations: READ_ONLY,
|
|
28
|
+
output: AuditComplexityResultSchema,
|
|
29
|
+
input: {
|
|
30
|
+
scope: z
|
|
31
|
+
.array(z.enum(SCOPE_VALUES))
|
|
32
|
+
.optional()
|
|
33
|
+
.describe("Sections to scan: 'processes' (TI metrics), 'rules' (cube rules), " +
|
|
34
|
+
"'consistency' (cross-process naming/type/cohort checks), " +
|
|
35
|
+
"'antipatterns' (TI lint findings: destructive-unguarded, " +
|
|
36
|
+
"exec-in-loop, cellget-perf, hardcoded-path). " +
|
|
37
|
+
"Default: processes+rules+consistency. 'antipatterns' is opt-in."),
|
|
38
|
+
includeControl: z
|
|
39
|
+
.boolean()
|
|
40
|
+
.optional()
|
|
41
|
+
.default(false)
|
|
42
|
+
.describe("Include control objects ('}'-prefix). Default false."),
|
|
43
|
+
topN: z
|
|
44
|
+
.number()
|
|
45
|
+
.int()
|
|
46
|
+
.min(1)
|
|
47
|
+
.max(500)
|
|
48
|
+
.optional()
|
|
49
|
+
.default(20)
|
|
50
|
+
.describe("Per section, return only the N highest-scoring entries. Summary " +
|
|
51
|
+
"counters reflect the full scan. Default 20."),
|
|
52
|
+
scoreThreshold: z
|
|
53
|
+
.number()
|
|
54
|
+
.int()
|
|
55
|
+
.min(0)
|
|
56
|
+
.optional()
|
|
57
|
+
.default(0)
|
|
58
|
+
.describe("Filter: only include entries whose score is >= this value (applied " +
|
|
59
|
+
"alongside topN, against the rankBy score). Default 0 (no filter). " +
|
|
60
|
+
"When > 0, surviving " +
|
|
61
|
+
"process/rules entries also drive status='fail'; at 0, status is " +
|
|
62
|
+
"informational and only consistency issues (variable clusters, " +
|
|
63
|
+
"type conflicts) trigger 'fail'."),
|
|
64
|
+
rankBy: z
|
|
65
|
+
.enum(["scoreV1", "scoreV2"])
|
|
66
|
+
.optional()
|
|
67
|
+
.default("scoreV1")
|
|
68
|
+
.describe("Which process score drives sort, scoreThreshold, and status. " +
|
|
69
|
+
"'scoreV1' (default) = loc + 2*branches + 3*maxNesting (size/nesting). " +
|
|
70
|
+
"'scoreV2' = loc + ifCost + loopCost + hotInLoop: loop nesting " +
|
|
71
|
+
"multiplies geometrically (nestMult^depth), if cost scales with " +
|
|
72
|
+
"condition complexity and depth, and hot ops (CellPutN/ASCIIOutput/" +
|
|
73
|
+
"ExecuteProcess/…) inside loops are penalised. Rules always sort by " +
|
|
74
|
+
"their own score regardless."),
|
|
75
|
+
weights: z
|
|
76
|
+
.object({
|
|
77
|
+
loopBase: z.number().optional(),
|
|
78
|
+
nestMult: z.number().optional(),
|
|
79
|
+
ifBase: z.number().optional(),
|
|
80
|
+
hotPenalty: z.number().optional(),
|
|
81
|
+
commentDiscountMax: z.number().min(0).max(1).optional(),
|
|
82
|
+
})
|
|
83
|
+
.optional()
|
|
84
|
+
.describe("Override v2 score weights (only affects scoreV2). Defaults: " +
|
|
85
|
+
"loopBase=2, nestMult=3, ifBase=1, hotPenalty=2, commentDiscountMax=0. " +
|
|
86
|
+
"Set commentDiscountMax (0..1) to discount scoreV2 by comment ratio " +
|
|
87
|
+
"(capped); 0 = off. Use to recalibrate without code changes."),
|
|
88
|
+
cellGetDimThreshold: z
|
|
89
|
+
.number()
|
|
90
|
+
.int()
|
|
91
|
+
.min(1)
|
|
92
|
+
.optional()
|
|
93
|
+
.default(12)
|
|
94
|
+
.describe("Only affects scope='antipatterns'. Element-arg count at/above which " +
|
|
95
|
+
"a CellGetN/CellGetS is flagged as a perf risk (cellget-perf). " +
|
|
96
|
+
"Default 12. Lower it to surface mid-dimensional cubes too."),
|
|
97
|
+
},
|
|
98
|
+
handler: async ({ scope, includeControl, topN, scoreThreshold, rankBy, weights, cellGetDimThreshold, }, tm1Client) => {
|
|
99
|
+
const activeScope = scope && scope.length > 0 ? scope : SCOPE_DEFAULT;
|
|
100
|
+
const want = (s) => activeScope.includes(s);
|
|
101
|
+
const scoreWeights = weights;
|
|
102
|
+
const procScore = (m) => rankBy === "scoreV2" ? m.totals.scoreV2 : m.totals.score;
|
|
103
|
+
const serverInfo = await tm1Client.server.getInfo();
|
|
104
|
+
const processMetrics = [];
|
|
105
|
+
const processVarInputs = [];
|
|
106
|
+
const findings = [];
|
|
107
|
+
// ── Processes ──────────────────────────────────────────────────────
|
|
108
|
+
// getAllCode / getAllRules apply the control-prefix filter server-side
|
|
109
|
+
// via OData ($filter=not startswith(Name,'}')), so we trust the service
|
|
110
|
+
// and don't double-filter here.
|
|
111
|
+
if (want("processes") || want("consistency") || want("antipatterns")) {
|
|
112
|
+
const all = await tm1Client.processes.getAllCode(includeControl);
|
|
113
|
+
for (const p of all) {
|
|
114
|
+
const code = {
|
|
115
|
+
prolog: p.prolog,
|
|
116
|
+
metadata: p.metadata,
|
|
117
|
+
data: p.data,
|
|
118
|
+
epilog: p.epilog,
|
|
119
|
+
};
|
|
120
|
+
processMetrics.push(computeProcessMetrics(p.name, code, scoreWeights));
|
|
121
|
+
if (want("antipatterns")) {
|
|
122
|
+
findings.push(...lintProcess(p.name, code, { cellGetDimThreshold }));
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
if (want("consistency")) {
|
|
126
|
+
// Variables ride along with the process list in a single request.
|
|
127
|
+
// Asking per process cost one round trip each — 221 of them on a
|
|
128
|
+
// real model — for data the server will hand over in one go.
|
|
129
|
+
// Nothing partial can arrive, so there is no per-process failure to
|
|
130
|
+
// reconcile: the request either answers or throws, and a partial
|
|
131
|
+
// scan would skew every cross-process aggregate below it.
|
|
132
|
+
const variablesByProcess = await tm1Client.processes.getAllVariables(includeControl);
|
|
133
|
+
for (const p of all) {
|
|
134
|
+
processVarInputs.push({
|
|
135
|
+
process: p.name,
|
|
136
|
+
variables: (variablesByProcess.get(p.name) ?? []).map((v) => ({
|
|
137
|
+
name: v.name,
|
|
138
|
+
type: v.type,
|
|
139
|
+
})),
|
|
140
|
+
});
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
// ── Rules ──────────────────────────────────────────────────────────
|
|
145
|
+
const rulesMetrics = [];
|
|
146
|
+
if (want("rules")) {
|
|
147
|
+
const all = await tm1Client.cubes.getAllRules(includeControl);
|
|
148
|
+
for (const r of all) {
|
|
149
|
+
rulesMetrics.push(computeRulesMetrics(r.cubeName, r.rulesText));
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
// ── Cross-process consistency ──────────────────────────────────────
|
|
153
|
+
const consistency = want("consistency")
|
|
154
|
+
? {
|
|
155
|
+
variableClusters: clusterVariableNames(processVarInputs),
|
|
156
|
+
typeConflicts: findTypeInconsistencies(processVarInputs),
|
|
157
|
+
prefixConvention: reportPrefixConvention(processVarInputs),
|
|
158
|
+
cohorts: groupByCohort(processVarInputs),
|
|
159
|
+
}
|
|
160
|
+
: null;
|
|
161
|
+
// ── Sort + filter + cap ────────────────────────────────────────────
|
|
162
|
+
const processesScanned = processMetrics.length;
|
|
163
|
+
const rulesScanned = rulesMetrics.length;
|
|
164
|
+
processMetrics.sort((a, b) => procScore(b) - procScore(a));
|
|
165
|
+
rulesMetrics.sort((a, b) => b.score - a.score);
|
|
166
|
+
const topProcesses = processMetrics
|
|
167
|
+
.filter((m) => procScore(m) >= scoreThreshold)
|
|
168
|
+
.slice(0, topN);
|
|
169
|
+
const topRules = rulesMetrics
|
|
170
|
+
.filter((m) => m.score >= scoreThreshold)
|
|
171
|
+
.slice(0, topN);
|
|
172
|
+
// At default scoreThreshold=0 the score formula (loc + 2*branches +
|
|
173
|
+
// 3*nesting) is >= 1 for any non-empty process, so gating status on
|
|
174
|
+
// topProcesses/topRules would mark every run "fail". Gate process/rules
|
|
175
|
+
// contributions to status only when the caller opted into a threshold.
|
|
176
|
+
const thresholdActive = scoreThreshold > 0;
|
|
177
|
+
const consistencyIssues = consistency !== null &&
|
|
178
|
+
(consistency.variableClusters.length > 0 ||
|
|
179
|
+
consistency.typeConflicts.length > 0);
|
|
180
|
+
// ── Anti-patterns ──────────────────────────────────────────────────
|
|
181
|
+
const SEV_ORDER = { error: 0, warn: 1, info: 2 };
|
|
182
|
+
const antipatterns = want("antipatterns")
|
|
183
|
+
? (() => {
|
|
184
|
+
const summary = { error: 0, warn: 0, info: 0 };
|
|
185
|
+
for (const f of findings)
|
|
186
|
+
summary[f.severity]++;
|
|
187
|
+
const sorted = [...findings].sort((a, b) => SEV_ORDER[a.severity] - SEV_ORDER[b.severity] ||
|
|
188
|
+
a.process.localeCompare(b.process) ||
|
|
189
|
+
a.line - b.line);
|
|
190
|
+
const top = sorted.slice(0, topN);
|
|
191
|
+
return {
|
|
192
|
+
summary: { ...summary, total: findings.length },
|
|
193
|
+
findings: top,
|
|
194
|
+
truncated: findings.length > top.length,
|
|
195
|
+
};
|
|
196
|
+
})()
|
|
197
|
+
: null;
|
|
198
|
+
const antipatternErrors = antipatterns !== null && antipatterns.summary.error > 0;
|
|
199
|
+
const status = consistencyIssues ||
|
|
200
|
+
antipatternErrors ||
|
|
201
|
+
(thresholdActive && (topProcesses.length > 0 || topRules.length > 0))
|
|
202
|
+
? "fail"
|
|
203
|
+
: "pass";
|
|
204
|
+
return {
|
|
205
|
+
content: [
|
|
206
|
+
{
|
|
207
|
+
type: "text",
|
|
208
|
+
text: JSON.stringify({
|
|
209
|
+
status,
|
|
210
|
+
productVersion: serverInfo.productVersion,
|
|
211
|
+
scope: activeScope,
|
|
212
|
+
includeControl,
|
|
213
|
+
rankBy,
|
|
214
|
+
scanned: {
|
|
215
|
+
processes: processesScanned,
|
|
216
|
+
rules: rulesScanned,
|
|
217
|
+
},
|
|
218
|
+
summary: {
|
|
219
|
+
processes: {
|
|
220
|
+
totalLoc: processMetrics.reduce((a, m) => a + m.totals.loc, 0),
|
|
221
|
+
totalBranches: processMetrics.reduce((a, m) => a + m.totals.branches, 0),
|
|
222
|
+
maxNesting: processMetrics.reduce((a, m) => Math.max(a, m.totals.maxNesting), 0),
|
|
223
|
+
avgCommentRatio: processesScanned === 0
|
|
224
|
+
? 0
|
|
225
|
+
: processMetrics.reduce((a, m) => a + m.totals.commentRatio, 0) / processesScanned,
|
|
226
|
+
totalDeadCodeLines: processMetrics.reduce((a, m) => a + m.totals.deadCodeLines, 0),
|
|
227
|
+
avgDeadCodeRatio: processesScanned === 0
|
|
228
|
+
? 0
|
|
229
|
+
: processMetrics.reduce((a, m) => a + m.totals.deadCodeRatio, 0) / processesScanned,
|
|
230
|
+
},
|
|
231
|
+
rules: {
|
|
232
|
+
totalRulesLoc: rulesMetrics.reduce((a, m) => a + m.rulesLoc, 0),
|
|
233
|
+
totalRuleCount: rulesMetrics.reduce((a, m) => a + m.ruleCount, 0),
|
|
234
|
+
totalDbCalls: rulesMetrics.reduce((a, m) => a + m.dbCallCount, 0),
|
|
235
|
+
totalDeadCodeLines: rulesMetrics.reduce((a, m) => a + m.deadCodeLines, 0),
|
|
236
|
+
cubesWithoutSkipcheck: rulesMetrics
|
|
237
|
+
.filter((m) => !m.hasSkipcheck && m.rulesLoc > 0)
|
|
238
|
+
.map((m) => m.cube),
|
|
239
|
+
},
|
|
240
|
+
},
|
|
241
|
+
topProcesses,
|
|
242
|
+
topRules,
|
|
243
|
+
consistency,
|
|
244
|
+
antipatterns,
|
|
245
|
+
truncated: {
|
|
246
|
+
processes: processMetrics.length > topProcesses.length,
|
|
247
|
+
rules: rulesMetrics.length > topRules.length,
|
|
248
|
+
},
|
|
249
|
+
}),
|
|
250
|
+
},
|
|
251
|
+
],
|
|
252
|
+
};
|
|
253
|
+
},
|
|
254
|
+
});
|
|
255
|
+
//# sourceMappingURL=audit-complexity.js.map
|
|
@@ -0,0 +1,417 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { parseRules } from "../../lib/callgraph/rulesParser.js";
|
|
3
|
+
import { extractBracketLists } from "../../lib/feeders/brackets.js";
|
|
4
|
+
import { detectBroaderThanMatchedRule, detectBroaderThanRule, detectDbFeederWithoutSkipcheck, detectFeederToConsolidated, detectOrphanFeeder, detectWildcardBracket, findMatchingRule, } from "../../lib/feeders/static-heuristics.js";
|
|
5
|
+
import { ElementTypeCache } from "../../lib/feeders/element-type-cache.js";
|
|
6
|
+
import { mapSettledWithConcurrency } from "../../lib/concurrency.js";
|
|
7
|
+
import { computeFedToPopulatedRatio, computeFeederMemoryRatio, fetchCubeStats, CubeStatsUnavailableError, } from "../../lib/cube-stats/fetcher.js";
|
|
8
|
+
import { isControlName } from "../../lib/control-name.js";
|
|
9
|
+
import { AuditFeedersResultSchema } from "../schemas/items.js";
|
|
10
|
+
import { READ_ONLY } from "../annotations.js";
|
|
11
|
+
import { defineTool } from "../define-tool.js";
|
|
12
|
+
export const registerAuditFeeders = defineTool({
|
|
13
|
+
name: "tm1_audit_feeders",
|
|
14
|
+
description: "Static heuristics (S1–S5) scan cube rules for overfeeding: wildcard brackets, feeders into consolidated " +
|
|
15
|
+
"elements, over-broad feeders, DB() without skipcheck, orphan feeders. " +
|
|
16
|
+
"mode='runtime' returns StatsByCube fed/populated ratio + memory stats; mode='both' runs both and escalates static findings with runtime evidence. " +
|
|
17
|
+
"Where }StatsByCube is absent (TM1 v12) or unreadable, runtime evidence is reported as `runtimeUnavailable` and the static half still runs.",
|
|
18
|
+
annotations: READ_ONLY,
|
|
19
|
+
output: AuditFeedersResultSchema,
|
|
20
|
+
input: {
|
|
21
|
+
cubes: z
|
|
22
|
+
.array(z.string())
|
|
23
|
+
.optional()
|
|
24
|
+
.describe("Restrict the scan to these cube names. Default: every non-control cube with rules."),
|
|
25
|
+
topN: z
|
|
26
|
+
.number()
|
|
27
|
+
.int()
|
|
28
|
+
.min(1)
|
|
29
|
+
.max(10000)
|
|
30
|
+
.optional()
|
|
31
|
+
.default(50)
|
|
32
|
+
.describe("Cap on returned findings (summary counters reflect the full scan). Default 50."),
|
|
33
|
+
includeControl: z
|
|
34
|
+
.boolean()
|
|
35
|
+
.optional()
|
|
36
|
+
.default(false)
|
|
37
|
+
.describe("Include control objects ('}'-prefix). Default false."),
|
|
38
|
+
s1MinPinnedRatio: z
|
|
39
|
+
.number()
|
|
40
|
+
.min(0)
|
|
41
|
+
.max(1)
|
|
42
|
+
.optional()
|
|
43
|
+
.default(0.5)
|
|
44
|
+
.describe("S1 ratio-fallback gate (only used when no rule shares any element with the feeder.RHS): flag when (feederConstraintCount / cubeTotalDims) < this value. Default 0.5. Rule-paired comparison (feeder.pinned < matchedRule.pinned) is preferred when a match is found."),
|
|
45
|
+
mode: z
|
|
46
|
+
.enum(["static", "runtime", "both"])
|
|
47
|
+
.optional()
|
|
48
|
+
.default("static")
|
|
49
|
+
.describe("static: rule-text heuristics only (default). runtime: }StatsByCube cube-level findings only (no static scan). both: static scan + runtime evidence + severity escalation on overlap."),
|
|
50
|
+
fedRatioThreshold: z
|
|
51
|
+
.number()
|
|
52
|
+
.min(1)
|
|
53
|
+
.optional()
|
|
54
|
+
.default(50)
|
|
55
|
+
.describe("Runtime: flag cube (severity hint) when fedCells / populatedNumeric ≥ this value. Default 50 — community rule of thumb for 'suspicious' (tm1forum/Cubewise; some use 20). Raise to 100 to only flag definite overfeeding."),
|
|
56
|
+
fedRatioEvidenceThreshold: z
|
|
57
|
+
.number()
|
|
58
|
+
.min(1)
|
|
59
|
+
.optional()
|
|
60
|
+
.default(100)
|
|
61
|
+
.describe("Runtime: escalate cube_high_fed_ratio to severity 'evidence' when fedCells / populatedNumeric ≥ this value. Default 100 — community consensus for definite overfeeding. Must be ≥ fedRatioThreshold to take effect."),
|
|
62
|
+
memoryThresholdMb: z
|
|
63
|
+
.number()
|
|
64
|
+
.min(0)
|
|
65
|
+
.optional()
|
|
66
|
+
.default(1024)
|
|
67
|
+
.describe("Runtime: flag cube when memoryTotal (MB) ≥ this value. Default 1024 (1 GiB)."),
|
|
68
|
+
severityThreshold: z
|
|
69
|
+
.enum(["none", "hint", "evidence"])
|
|
70
|
+
.optional()
|
|
71
|
+
.default("hint")
|
|
72
|
+
.describe("pass/fail boundary on `status`. none: always pass. hint (default): fail on any finding. evidence: fail only when runtime evidence is present — useful for CI gates that should not block on static-only hints."),
|
|
73
|
+
},
|
|
74
|
+
handler: async ({ cubes, topN, includeControl, s1MinPinnedRatio, mode, fedRatioThreshold, fedRatioEvidenceThreshold, memoryThresholdMb, severityThreshold, }, tm1Client) => {
|
|
75
|
+
const serverInfo = await tm1Client.server.getInfo();
|
|
76
|
+
// withDimensions: the static scan needs each rule-bearing cube's
|
|
77
|
+
// dimension order. Expanded here it costs nothing extra; fetched per
|
|
78
|
+
// cube it was one GET per cube with rules.
|
|
79
|
+
const all = await tm1Client.cubes.getAllRules({
|
|
80
|
+
includeControl,
|
|
81
|
+
withDimensions: true,
|
|
82
|
+
});
|
|
83
|
+
const targetSet = cubes && cubes.length > 0 ? new Set(cubes) : null;
|
|
84
|
+
const skipcheckMap = new Map();
|
|
85
|
+
for (const c of all) {
|
|
86
|
+
if (!c.rulesText)
|
|
87
|
+
continue;
|
|
88
|
+
skipcheckMap.set(c.cubeName.toLowerCase(), parseRules(c.rulesText).hasSkipcheck);
|
|
89
|
+
}
|
|
90
|
+
const lookupSkipcheck = (cubeName) => {
|
|
91
|
+
const v = skipcheckMap.get(cubeName.toLowerCase());
|
|
92
|
+
return v === undefined ? null : v;
|
|
93
|
+
};
|
|
94
|
+
const elementTypeCache = new ElementTypeCache(tm1Client.hierarchies);
|
|
95
|
+
const findings = [];
|
|
96
|
+
const scannedCubeNames = [];
|
|
97
|
+
let cubesScanned = 0;
|
|
98
|
+
let feederLinesScanned = 0;
|
|
99
|
+
let dimResolveFailures = 0;
|
|
100
|
+
const wantsStatic = mode === "static" || mode === "both";
|
|
101
|
+
for (const c of all) {
|
|
102
|
+
if (targetSet && !targetSet.has(c.cubeName))
|
|
103
|
+
continue;
|
|
104
|
+
if (!includeControl && isControlName(c.cubeName))
|
|
105
|
+
continue;
|
|
106
|
+
cubesScanned++;
|
|
107
|
+
scannedCubeNames.push(c.cubeName);
|
|
108
|
+
if (!c.rulesText || c.rulesText.trim() === "")
|
|
109
|
+
continue;
|
|
110
|
+
if (!wantsStatic)
|
|
111
|
+
continue;
|
|
112
|
+
const ast = parseRules(c.rulesText);
|
|
113
|
+
// Normal path: the names rode along on the bulk rules request. The
|
|
114
|
+
// per-cube fetch stays as a fallback for a server that answered
|
|
115
|
+
// without the expansion — a missing dimension list would silently
|
|
116
|
+
// change every ratio below, so it is worth one request to avoid.
|
|
117
|
+
let cubeDimNames = c.dimensions ?? [];
|
|
118
|
+
if (cubeDimNames.length === 0) {
|
|
119
|
+
try {
|
|
120
|
+
cubeDimNames = await tm1Client.cubes.getDimensionNames(c.cubeName);
|
|
121
|
+
}
|
|
122
|
+
catch {
|
|
123
|
+
dimResolveFailures++;
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
const cubeDimCount = cubeDimNames.length;
|
|
127
|
+
const ruleLhs = [];
|
|
128
|
+
for (const line of ast.lines) {
|
|
129
|
+
if (line.section !== "rules")
|
|
130
|
+
continue;
|
|
131
|
+
if (line.isBlank || line.isComment)
|
|
132
|
+
continue;
|
|
133
|
+
const lists = extractBracketLists(line.trimmed);
|
|
134
|
+
if (lists.length === 0)
|
|
135
|
+
continue;
|
|
136
|
+
ruleLhs.push(lists[0]);
|
|
137
|
+
}
|
|
138
|
+
for (const line of ast.lines) {
|
|
139
|
+
if (line.section !== "feeders")
|
|
140
|
+
continue;
|
|
141
|
+
if (line.isBlank || line.isComment)
|
|
142
|
+
continue;
|
|
143
|
+
if (/^feeders\s*;?\s*$/i.test(line.trimmed))
|
|
144
|
+
continue;
|
|
145
|
+
// Multi-line feeders place `=>` and the RHS on a continuation line.
|
|
146
|
+
// The preceding feeder's LHS already covered it — skip so we don't
|
|
147
|
+
// re-score the RHS bracket as if it were the LHS.
|
|
148
|
+
if (/^=>/.test(line.trimmed))
|
|
149
|
+
continue;
|
|
150
|
+
const lists = extractBracketLists(line.trimmed);
|
|
151
|
+
if (lists.length === 0)
|
|
152
|
+
continue;
|
|
153
|
+
feederLinesScanned++;
|
|
154
|
+
const feederLhs = lists[0];
|
|
155
|
+
let lhsRuleHit = null;
|
|
156
|
+
let lhsDetail;
|
|
157
|
+
if (detectWildcardBracket(feederLhs)) {
|
|
158
|
+
lhsRuleHit = "wildcard_bracket";
|
|
159
|
+
}
|
|
160
|
+
else {
|
|
161
|
+
const cons = await detectFeederToConsolidated(feederLhs, cubeDimNames, elementTypeCache);
|
|
162
|
+
if (cons) {
|
|
163
|
+
lhsRuleHit = "feeder_to_consolidated";
|
|
164
|
+
lhsDetail = `${cons.dim}:${cons.elem}`;
|
|
165
|
+
}
|
|
166
|
+
else if (!isCrossCubeDbFeeder(line.trimmed)) {
|
|
167
|
+
// Cross-cube DB-feeders: rule lives in target cube; S4 covers
|
|
168
|
+
// their DB-feeder risk so skip S1 here.
|
|
169
|
+
// Pair by feeder.RHS ⇄ rule.LHS — the feeder marks cells the
|
|
170
|
+
// rule writes, so the target bracket is the right signal.
|
|
171
|
+
// Falls back to feeder.LHS when RHS isn't a plain bracket.
|
|
172
|
+
const feederRhs = lists.length > 1 ? lists[1] : null;
|
|
173
|
+
const matchBracket = feederRhs ?? feederLhs;
|
|
174
|
+
const matchedRule = findMatchingRule(matchBracket, ruleLhs);
|
|
175
|
+
if (matchedRule) {
|
|
176
|
+
if (detectBroaderThanMatchedRule(feederLhs, matchedRule)) {
|
|
177
|
+
lhsRuleHit = "feeder_broader_than_rule";
|
|
178
|
+
lhsDetail = `pins ${feederLhs.entries.length} vs rule ${matchedRule.entries.length}`;
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
else if (detectBroaderThanRule(feederLhs, cubeDimCount, s1MinPinnedRatio)) {
|
|
182
|
+
lhsRuleHit = "feeder_broader_than_rule";
|
|
183
|
+
lhsDetail = `pins ${feederLhs.entries.length}/${cubeDimCount} dims (no matching rule — ratio fallback)`;
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
if (!lhsRuleHit) {
|
|
187
|
+
if (!isCrossCubeDbFeeder(line.trimmed)) {
|
|
188
|
+
// Cross-cube DB-feeders: target rules live in another cube,
|
|
189
|
+
// so a local orphan check can't see them. S4 covers the
|
|
190
|
+
// DB-skipcheck risk; skip S5 here to avoid false orphans.
|
|
191
|
+
// Orphan check uses feeder.RHS (target cells) so it pairs
|
|
192
|
+
// with rule.LHS (cells the rule writes) — feeder.LHS uses
|
|
193
|
+
// different elements in the idiomatic 1:1 pattern.
|
|
194
|
+
const feederRhs = lists.length > 1 ? lists[1] : null;
|
|
195
|
+
const orphanBracket = feederRhs ?? feederLhs;
|
|
196
|
+
if (detectOrphanFeeder(orphanBracket, ruleLhs)) {
|
|
197
|
+
lhsRuleHit = "orphan_feeder";
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
if (lhsRuleHit) {
|
|
203
|
+
findings.push({
|
|
204
|
+
cube: c.cubeName,
|
|
205
|
+
line: line.lineIndex + 1,
|
|
206
|
+
severity: "hint",
|
|
207
|
+
rule: lhsRuleHit,
|
|
208
|
+
feeder: line.trimmed,
|
|
209
|
+
...(lhsDetail !== undefined ? { detail: lhsDetail } : {}),
|
|
210
|
+
});
|
|
211
|
+
}
|
|
212
|
+
const dbTarget = detectDbFeederWithoutSkipcheck(line.trimmed, lookupSkipcheck);
|
|
213
|
+
if (dbTarget) {
|
|
214
|
+
findings.push({
|
|
215
|
+
cube: c.cubeName,
|
|
216
|
+
line: line.lineIndex + 1,
|
|
217
|
+
severity: "hint",
|
|
218
|
+
rule: "db_feeder_without_skipcheck",
|
|
219
|
+
feeder: line.trimmed,
|
|
220
|
+
detail: dbTarget,
|
|
221
|
+
});
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
// ─── Runtime evidence (mode: runtime | both) ────────────────────────
|
|
226
|
+
const wantsRuntime = mode === "runtime" || mode === "both";
|
|
227
|
+
const runtimeStats = {};
|
|
228
|
+
let runtimeAvailableCount = 0;
|
|
229
|
+
let runtimeFailureCount = 0;
|
|
230
|
+
let runtimeUnavailable;
|
|
231
|
+
if (wantsRuntime && scannedCubeNames.length > 0) {
|
|
232
|
+
// Cap in-flight }StatsByCube MDX calls so a large model can't flood TM1's
|
|
233
|
+
// worker pool with hundreds of simultaneous requests.
|
|
234
|
+
const settled = await mapSettledWithConcurrency(scannedCubeNames, 10, (name) => fetchCubeStats(tm1Client, name));
|
|
235
|
+
// Tracks a failure that is about the server/account rather than the
|
|
236
|
+
// cube, so it can be reported once (see runtimeUnavailable below).
|
|
237
|
+
const unavailableReasons = new Set();
|
|
238
|
+
let unavailableSample;
|
|
239
|
+
let unavailableCount = 0;
|
|
240
|
+
for (let i = 0; i < settled.length; i++) {
|
|
241
|
+
const cubeName = scannedCubeNames[i];
|
|
242
|
+
const r = settled[i];
|
|
243
|
+
if (r.status !== "fulfilled") {
|
|
244
|
+
runtimeFailureCount++;
|
|
245
|
+
const err = r.reason;
|
|
246
|
+
const unavailable = err instanceof CubeStatsUnavailableError ? err : null;
|
|
247
|
+
if (unavailable) {
|
|
248
|
+
unavailableReasons.add(unavailable.reason);
|
|
249
|
+
unavailableSample ??= unavailable;
|
|
250
|
+
unavailableCount++;
|
|
251
|
+
}
|
|
252
|
+
runtimeStats[cubeName] = {
|
|
253
|
+
available: false,
|
|
254
|
+
memoryTotal: null,
|
|
255
|
+
memoryMb: null,
|
|
256
|
+
fedCells: null,
|
|
257
|
+
populatedNumeric: null,
|
|
258
|
+
fedToPopulatedRatio: null,
|
|
259
|
+
feederMemoryRatio: null,
|
|
260
|
+
error: unavailable ? unavailable.message : String(r.reason),
|
|
261
|
+
};
|
|
262
|
+
continue;
|
|
263
|
+
}
|
|
264
|
+
const stats = r.value;
|
|
265
|
+
const memoryTotal = typeof stats.memoryTotal === "number" ? stats.memoryTotal : null;
|
|
266
|
+
const memoryMb = memoryTotal !== null
|
|
267
|
+
? Number((memoryTotal / 1_048_576).toFixed(2))
|
|
268
|
+
: null;
|
|
269
|
+
const fedCells = typeof stats.fedCells === "number" ? stats.fedCells : null;
|
|
270
|
+
const populatedNumeric = typeof stats.populatedNumeric === "number"
|
|
271
|
+
? stats.populatedNumeric
|
|
272
|
+
: null;
|
|
273
|
+
const fedToPopulatedRatio = computeFedToPopulatedRatio(stats);
|
|
274
|
+
const feederMemoryRatio = computeFeederMemoryRatio(stats);
|
|
275
|
+
const stat = {
|
|
276
|
+
available: true,
|
|
277
|
+
memoryTotal,
|
|
278
|
+
memoryMb,
|
|
279
|
+
fedCells,
|
|
280
|
+
populatedNumeric,
|
|
281
|
+
fedToPopulatedRatio,
|
|
282
|
+
feederMemoryRatio,
|
|
283
|
+
};
|
|
284
|
+
runtimeStats[cubeName] = stat;
|
|
285
|
+
runtimeAvailableCount++;
|
|
286
|
+
// Cube-level findings. Fed-ratio severity follows community
|
|
287
|
+
// calibration: ≥ threshold (50) = suspicious hint, ≥ evidence
|
|
288
|
+
// threshold (100) = definite overfeeding.
|
|
289
|
+
if (fedToPopulatedRatio !== null &&
|
|
290
|
+
fedToPopulatedRatio >= fedRatioThreshold) {
|
|
291
|
+
const definite = fedRatioEvidenceThreshold >= fedRatioThreshold &&
|
|
292
|
+
fedToPopulatedRatio >= fedRatioEvidenceThreshold;
|
|
293
|
+
findings.push({
|
|
294
|
+
cube: cubeName,
|
|
295
|
+
line: 0,
|
|
296
|
+
severity: definite ? "evidence" : "hint",
|
|
297
|
+
rule: "cube_high_fed_ratio",
|
|
298
|
+
feeder: "",
|
|
299
|
+
detail: `fed/populated=${fedToPopulatedRatio.toFixed(1)}x (fed ${fedCells ?? "?"} / populated ${populatedNumeric ?? "?"})`,
|
|
300
|
+
});
|
|
301
|
+
}
|
|
302
|
+
if (memoryMb !== null && memoryMb >= memoryThresholdMb) {
|
|
303
|
+
findings.push({
|
|
304
|
+
cube: cubeName,
|
|
305
|
+
line: 0,
|
|
306
|
+
severity: "evidence",
|
|
307
|
+
rule: "cube_high_memory",
|
|
308
|
+
feeder: "",
|
|
309
|
+
detail: `${memoryMb} MB`,
|
|
310
|
+
});
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
// Every cube failed the same server- or account-wide way: say it once
|
|
314
|
+
// and drop the N identical per-cube copies. The static half (mode
|
|
315
|
+
// 'both') is untouched — it needs no stats cube.
|
|
316
|
+
if (unavailableSample &&
|
|
317
|
+
unavailableCount === scannedCubeNames.length &&
|
|
318
|
+
unavailableReasons.size === 1) {
|
|
319
|
+
runtimeUnavailable = {
|
|
320
|
+
reason: unavailableSample.reason,
|
|
321
|
+
message: unavailableSample.message,
|
|
322
|
+
cubes: unavailableCount,
|
|
323
|
+
};
|
|
324
|
+
for (const name of scannedCubeNames)
|
|
325
|
+
delete runtimeStats[name];
|
|
326
|
+
}
|
|
327
|
+
// Escalate static findings on cubes with runtime evidence.
|
|
328
|
+
const evidenceCubes = new Set();
|
|
329
|
+
for (const f of findings) {
|
|
330
|
+
if (f.severity === "evidence" &&
|
|
331
|
+
(f.rule === "cube_high_fed_ratio" || f.rule === "cube_high_memory")) {
|
|
332
|
+
evidenceCubes.add(f.cube);
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
for (const f of findings) {
|
|
336
|
+
if (f.severity === "hint" && evidenceCubes.has(f.cube)) {
|
|
337
|
+
f.severity = "evidence";
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
const byRule = {
|
|
342
|
+
wildcard_bracket: 0,
|
|
343
|
+
feeder_to_consolidated: 0,
|
|
344
|
+
feeder_broader_than_rule: 0,
|
|
345
|
+
db_feeder_without_skipcheck: 0,
|
|
346
|
+
orphan_feeder: 0,
|
|
347
|
+
cube_high_fed_ratio: 0,
|
|
348
|
+
cube_high_memory: 0,
|
|
349
|
+
};
|
|
350
|
+
const bySeverity = { hint: 0, evidence: 0 };
|
|
351
|
+
const byCube = {};
|
|
352
|
+
for (const f of findings) {
|
|
353
|
+
byRule[f.rule]++;
|
|
354
|
+
bySeverity[f.severity]++;
|
|
355
|
+
byCube[f.cube] = (byCube[f.cube] ?? 0) + 1;
|
|
356
|
+
}
|
|
357
|
+
findings.sort((a, b) => a.cube.localeCompare(b.cube) ||
|
|
358
|
+
a.line - b.line ||
|
|
359
|
+
a.rule.localeCompare(b.rule));
|
|
360
|
+
const truncated = findings.length > topN;
|
|
361
|
+
const trimmed = findings.slice(0, topN);
|
|
362
|
+
let status;
|
|
363
|
+
if (severityThreshold === "none") {
|
|
364
|
+
status = "pass";
|
|
365
|
+
}
|
|
366
|
+
else if (severityThreshold === "evidence") {
|
|
367
|
+
status = bySeverity.evidence > 0 ? "fail" : "pass";
|
|
368
|
+
}
|
|
369
|
+
else {
|
|
370
|
+
status = findings.length > 0 ? "fail" : "pass";
|
|
371
|
+
}
|
|
372
|
+
return {
|
|
373
|
+
content: [
|
|
374
|
+
{
|
|
375
|
+
type: "text",
|
|
376
|
+
text: JSON.stringify({
|
|
377
|
+
status,
|
|
378
|
+
productVersion: serverInfo.productVersion,
|
|
379
|
+
mode,
|
|
380
|
+
includeControl,
|
|
381
|
+
s1MinPinnedRatio,
|
|
382
|
+
fedRatioThreshold,
|
|
383
|
+
fedRatioEvidenceThreshold,
|
|
384
|
+
memoryThresholdMb,
|
|
385
|
+
severityThreshold,
|
|
386
|
+
scanned: {
|
|
387
|
+
cubes: cubesScanned,
|
|
388
|
+
feederLines: feederLinesScanned,
|
|
389
|
+
dimResolveFailures,
|
|
390
|
+
runtimeAvailable: runtimeAvailableCount,
|
|
391
|
+
runtimeFailures: runtimeFailureCount,
|
|
392
|
+
},
|
|
393
|
+
invalidCount: findings.length,
|
|
394
|
+
summary: { byRule, bySeverity, byCube },
|
|
395
|
+
truncated: { findings: truncated },
|
|
396
|
+
findings: trimmed,
|
|
397
|
+
runtimeUnavailable,
|
|
398
|
+
runtimeStats: wantsRuntime ? runtimeStats : undefined,
|
|
399
|
+
rulesetSource: "Static heuristics S1 (feeder_broader_than_rule), S2 (feeder_to_consolidated), " +
|
|
400
|
+
"S3 (wildcard_bracket), S4 (db_feeder_without_skipcheck), S5 (orphan_feeder). " +
|
|
401
|
+
"Runtime evidence: cube_high_fed_ratio + cube_high_memory via }StatsByCube.",
|
|
402
|
+
}, null, 2),
|
|
403
|
+
},
|
|
404
|
+
],
|
|
405
|
+
};
|
|
406
|
+
},
|
|
407
|
+
});
|
|
408
|
+
/**
|
|
409
|
+
* Cross-cube DB-feeder: the feeder line writes into another cube via DB(...).
|
|
410
|
+
* Static-scan can't pair these with a local rule because the rule lives in
|
|
411
|
+
* the *target* cube, not the source. S5 (db_feeder_without_skipcheck) already
|
|
412
|
+
* covers their DB-feeder risk profile, so S1 skips them.
|
|
413
|
+
*/
|
|
414
|
+
function isCrossCubeDbFeeder(lineText) {
|
|
415
|
+
return /=>\s*DB\s*\(/i.test(lineText);
|
|
416
|
+
}
|
|
417
|
+
//# sourceMappingURL=audit-feeders.js.map
|