@untangle-code/cli 0.0.0-stage → 0.1.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/LICENSE +661 -0
- package/NOTICE +90 -0
- package/README.md +451 -2
- package/THIRD_PARTY_LICENSES.md +152 -0
- package/dist/cli/args.d.ts +48 -0
- package/dist/cli/args.d.ts.map +1 -0
- package/dist/cli/args.js +167 -0
- package/dist/cli/args.js.map +1 -0
- package/dist/cli/command.d.ts +69 -0
- package/dist/cli/command.d.ts.map +1 -0
- package/dist/cli/command.js +82 -0
- package/dist/cli/command.js.map +1 -0
- package/dist/cli/deadline.d.ts +33 -0
- package/dist/cli/deadline.d.ts.map +1 -0
- package/dist/cli/deadline.js +49 -0
- package/dist/cli/deadline.js.map +1 -0
- package/dist/cli/embedder-deadline.d.ts +72 -0
- package/dist/cli/embedder-deadline.d.ts.map +1 -0
- package/dist/cli/embedder-deadline.js +117 -0
- package/dist/cli/embedder-deadline.js.map +1 -0
- package/dist/cli/exit.d.ts +71 -0
- package/dist/cli/exit.d.ts.map +1 -0
- package/dist/cli/exit.js +81 -0
- package/dist/cli/exit.js.map +1 -0
- package/dist/cli/graphs.d.ts +65 -0
- package/dist/cli/graphs.d.ts.map +1 -0
- package/dist/cli/graphs.js +108 -0
- package/dist/cli/graphs.js.map +1 -0
- package/dist/cli/index-freshness.d.ts +13 -0
- package/dist/cli/index-freshness.d.ts.map +1 -0
- package/dist/cli/index-freshness.js +226 -0
- package/dist/cli/index-freshness.js.map +1 -0
- package/dist/cli/index-refresh.d.ts +10 -0
- package/dist/cli/index-refresh.d.ts.map +1 -0
- package/dist/cli/index-refresh.js +76 -0
- package/dist/cli/index-refresh.js.map +1 -0
- package/dist/cli/index-state.d.ts +184 -0
- package/dist/cli/index-state.d.ts.map +1 -0
- package/dist/cli/index-state.js +852 -0
- package/dist/cli/index-state.js.map +1 -0
- package/dist/cli/io.d.ts +29 -0
- package/dist/cli/io.d.ts.map +1 -0
- package/dist/cli/io.js +42 -0
- package/dist/cli/io.js.map +1 -0
- package/dist/cli/language-support.d.ts +77 -0
- package/dist/cli/language-support.d.ts.map +1 -0
- package/dist/cli/language-support.js +152 -0
- package/dist/cli/language-support.js.map +1 -0
- package/dist/cli/renewing-lease.d.ts +26 -0
- package/dist/cli/renewing-lease.d.ts.map +1 -0
- package/dist/cli/renewing-lease.js +102 -0
- package/dist/cli/renewing-lease.js.map +1 -0
- package/dist/cli/search-graph-enrichment.d.ts +16 -0
- package/dist/cli/search-graph-enrichment.d.ts.map +1 -0
- package/dist/cli/search-graph-enrichment.js +428 -0
- package/dist/cli/search-graph-enrichment.js.map +1 -0
- package/dist/cli/system.d.ts +34 -0
- package/dist/cli/system.d.ts.map +1 -0
- package/dist/cli/system.js +89 -0
- package/dist/cli/system.js.map +1 -0
- package/dist/cli/vector-store-policy.d.ts +116 -0
- package/dist/cli/vector-store-policy.d.ts.map +1 -0
- package/dist/cli/vector-store-policy.js +160 -0
- package/dist/cli/vector-store-policy.js.map +1 -0
- package/dist/cli/version.d.ts +3 -0
- package/dist/cli/version.d.ts.map +1 -0
- package/dist/cli/version.js +3 -0
- package/dist/cli/version.js.map +1 -0
- package/dist/cli/workspace.d.ts +105 -0
- package/dist/cli/workspace.d.ts.map +1 -0
- package/dist/cli/workspace.js +215 -0
- package/dist/cli/workspace.js.map +1 -0
- package/dist/commands/complexity.d.ts +72 -0
- package/dist/commands/complexity.d.ts.map +1 -0
- package/dist/commands/complexity.js +580 -0
- package/dist/commands/complexity.js.map +1 -0
- package/dist/commands/doctor.d.ts +66 -0
- package/dist/commands/doctor.d.ts.map +1 -0
- package/dist/commands/doctor.js +764 -0
- package/dist/commands/doctor.js.map +1 -0
- package/dist/commands/doctor.languages.d.ts +37 -0
- package/dist/commands/doctor.languages.d.ts.map +1 -0
- package/dist/commands/doctor.languages.js +143 -0
- package/dist/commands/doctor.languages.js.map +1 -0
- package/dist/commands/doctor.storage.d.ts +17 -0
- package/dist/commands/doctor.storage.d.ts.map +1 -0
- package/dist/commands/doctor.storage.js +91 -0
- package/dist/commands/doctor.storage.js.map +1 -0
- package/dist/commands/extensions/add.d.ts +10 -0
- package/dist/commands/extensions/add.d.ts.map +1 -0
- package/dist/commands/extensions/add.js +213 -0
- package/dist/commands/extensions/add.js.map +1 -0
- package/dist/commands/extensions/configure.d.ts +5 -0
- package/dist/commands/extensions/configure.d.ts.map +1 -0
- package/dist/commands/extensions/configure.js +58 -0
- package/dist/commands/extensions/configure.js.map +1 -0
- package/dist/commands/extensions/container.d.ts +15 -0
- package/dist/commands/extensions/container.d.ts.map +1 -0
- package/dist/commands/extensions/container.js +135 -0
- package/dist/commands/extensions/container.js.map +1 -0
- package/dist/commands/extensions/context.d.ts +37 -0
- package/dist/commands/extensions/context.d.ts.map +1 -0
- package/dist/commands/extensions/context.js +72 -0
- package/dist/commands/extensions/context.js.map +1 -0
- package/dist/commands/extensions/enable.d.ts +6 -0
- package/dist/commands/extensions/enable.d.ts.map +1 -0
- package/dist/commands/extensions/enable.js +180 -0
- package/dist/commands/extensions/enable.js.map +1 -0
- package/dist/commands/extensions/environment.d.ts +74 -0
- package/dist/commands/extensions/environment.d.ts.map +1 -0
- package/dist/commands/extensions/environment.js +168 -0
- package/dist/commands/extensions/environment.js.map +1 -0
- package/dist/commands/extensions/feature-scan.d.ts +48 -0
- package/dist/commands/extensions/feature-scan.d.ts.map +1 -0
- package/dist/commands/extensions/feature-scan.js +156 -0
- package/dist/commands/extensions/feature-scan.js.map +1 -0
- package/dist/commands/extensions/invoke.d.ts +60 -0
- package/dist/commands/extensions/invoke.d.ts.map +1 -0
- package/dist/commands/extensions/invoke.js +275 -0
- package/dist/commands/extensions/invoke.js.map +1 -0
- package/dist/commands/extensions/list.d.ts +5 -0
- package/dist/commands/extensions/list.d.ts.map +1 -0
- package/dist/commands/extensions/list.js +125 -0
- package/dist/commands/extensions/list.js.map +1 -0
- package/dist/commands/extensions/logs.d.ts +5 -0
- package/dist/commands/extensions/logs.d.ts.map +1 -0
- package/dist/commands/extensions/logs.js +74 -0
- package/dist/commands/extensions/logs.js.map +1 -0
- package/dist/commands/extensions/provision.d.ts +36 -0
- package/dist/commands/extensions/provision.d.ts.map +1 -0
- package/dist/commands/extensions/provision.js +137 -0
- package/dist/commands/extensions/provision.js.map +1 -0
- package/dist/commands/extensions/remove.d.ts +5 -0
- package/dist/commands/extensions/remove.d.ts.map +1 -0
- package/dist/commands/extensions/remove.js +77 -0
- package/dist/commands/extensions/remove.js.map +1 -0
- package/dist/commands/extensions/render.d.ts +16 -0
- package/dist/commands/extensions/render.d.ts.map +1 -0
- package/dist/commands/extensions/render.js +25 -0
- package/dist/commands/extensions/render.js.map +1 -0
- package/dist/commands/extensions/run.d.ts +30 -0
- package/dist/commands/extensions/run.d.ts.map +1 -0
- package/dist/commands/extensions/run.js +292 -0
- package/dist/commands/extensions/run.js.map +1 -0
- package/dist/commands/extensions/secret-store.d.ts +15 -0
- package/dist/commands/extensions/secret-store.d.ts.map +1 -0
- package/dist/commands/extensions/secret-store.js +164 -0
- package/dist/commands/extensions/secret-store.js.map +1 -0
- package/dist/commands/extensions/setup.d.ts +17 -0
- package/dist/commands/extensions/setup.d.ts.map +1 -0
- package/dist/commands/extensions/setup.js +94 -0
- package/dist/commands/extensions/setup.js.map +1 -0
- package/dist/commands/extensions/source.d.ts +47 -0
- package/dist/commands/extensions/source.d.ts.map +1 -0
- package/dist/commands/extensions/source.js +142 -0
- package/dist/commands/extensions/source.js.map +1 -0
- package/dist/commands/extensions/state.d.ts +62 -0
- package/dist/commands/extensions/state.d.ts.map +1 -0
- package/dist/commands/extensions/state.js +177 -0
- package/dist/commands/extensions/state.js.map +1 -0
- package/dist/commands/extensions/status.d.ts +9 -0
- package/dist/commands/extensions/status.d.ts.map +1 -0
- package/dist/commands/extensions/status.js +239 -0
- package/dist/commands/extensions/status.js.map +1 -0
- package/dist/commands/extensions.d.ts +3 -0
- package/dist/commands/extensions.d.ts.map +1 -0
- package/dist/commands/extensions.js +223 -0
- package/dist/commands/extensions.js.map +1 -0
- package/dist/commands/flow/index.d.ts +3 -0
- package/dist/commands/flow/index.d.ts.map +1 -0
- package/dist/commands/flow/index.js +295 -0
- package/dist/commands/flow/index.js.map +1 -0
- package/dist/commands/flow/limits.d.ts +12 -0
- package/dist/commands/flow/limits.d.ts.map +1 -0
- package/dist/commands/flow/limits.js +13 -0
- package/dist/commands/flow/limits.js.map +1 -0
- package/dist/commands/flow/output.d.ts +8 -0
- package/dist/commands/flow/output.d.ts.map +1 -0
- package/dist/commands/flow/output.js +11 -0
- package/dist/commands/flow/output.js.map +1 -0
- package/dist/commands/flow/render.d.ts +51 -0
- package/dist/commands/flow/render.d.ts.map +1 -0
- package/dist/commands/flow/render.js +220 -0
- package/dist/commands/flow/render.js.map +1 -0
- package/dist/commands/flow/select.d.ts +31 -0
- package/dist/commands/flow/select.d.ts.map +1 -0
- package/dist/commands/flow/select.js +62 -0
- package/dist/commands/flow/select.js.map +1 -0
- package/dist/commands/graph/boundaries-input.d.ts +26 -0
- package/dist/commands/graph/boundaries-input.d.ts.map +1 -0
- package/dist/commands/graph/boundaries-input.js +54 -0
- package/dist/commands/graph/boundaries-input.js.map +1 -0
- package/dist/commands/graph/boundaries.d.ts +4 -0
- package/dist/commands/graph/boundaries.d.ts.map +1 -0
- package/dist/commands/graph/boundaries.js +141 -0
- package/dist/commands/graph/boundaries.js.map +1 -0
- package/dist/commands/graph/bounds.d.ts +16 -0
- package/dist/commands/graph/bounds.d.ts.map +1 -0
- package/dist/commands/graph/bounds.js +22 -0
- package/dist/commands/graph/bounds.js.map +1 -0
- package/dist/commands/graph/category-clusters.d.ts +20 -0
- package/dist/commands/graph/category-clusters.d.ts.map +1 -0
- package/dist/commands/graph/category-clusters.js +158 -0
- package/dist/commands/graph/category-clusters.js.map +1 -0
- package/dist/commands/graph/feature-3d.d.ts +22 -0
- package/dist/commands/graph/feature-3d.d.ts.map +1 -0
- package/dist/commands/graph/feature-3d.js +114 -0
- package/dist/commands/graph/feature-3d.js.map +1 -0
- package/dist/commands/graph/feature-clusters.d.ts +17 -0
- package/dist/commands/graph/feature-clusters.d.ts.map +1 -0
- package/dist/commands/graph/feature-clusters.js +94 -0
- package/dist/commands/graph/feature-clusters.js.map +1 -0
- package/dist/commands/graph/feature-html.d.ts +26 -0
- package/dist/commands/graph/feature-html.d.ts.map +1 -0
- package/dist/commands/graph/feature-html.js +314 -0
- package/dist/commands/graph/feature-html.js.map +1 -0
- package/dist/commands/graph/feature-map.d.ts +31 -0
- package/dist/commands/graph/feature-map.d.ts.map +1 -0
- package/dist/commands/graph/feature-map.js +217 -0
- package/dist/commands/graph/feature-map.js.map +1 -0
- package/dist/commands/graph/feature-model.d.ts +55 -0
- package/dist/commands/graph/feature-model.d.ts.map +1 -0
- package/dist/commands/graph/feature-model.js +167 -0
- package/dist/commands/graph/feature-model.js.map +1 -0
- package/dist/commands/graph/feature-untangle-motion.d.ts +33 -0
- package/dist/commands/graph/feature-untangle-motion.d.ts.map +1 -0
- package/dist/commands/graph/feature-untangle-motion.js +155 -0
- package/dist/commands/graph/feature-untangle-motion.js.map +1 -0
- package/dist/commands/graph/index.d.ts +3 -0
- package/dist/commands/graph/index.d.ts.map +1 -0
- package/dist/commands/graph/index.js +414 -0
- package/dist/commands/graph/index.js.map +1 -0
- package/dist/commands/graph/render.d.ts +63 -0
- package/dist/commands/graph/render.d.ts.map +1 -0
- package/dist/commands/graph/render.js +352 -0
- package/dist/commands/graph/render.js.map +1 -0
- package/dist/commands/graph/select.d.ts +34 -0
- package/dist/commands/graph/select.d.ts.map +1 -0
- package/dist/commands/graph/select.js +55 -0
- package/dist/commands/graph/select.js.map +1 -0
- package/dist/commands/index/index.d.ts +6 -0
- package/dist/commands/index/index.d.ts.map +1 -0
- package/dist/commands/index/index.js +461 -0
- package/dist/commands/index/index.js.map +1 -0
- package/dist/commands/index/render.d.ts +53 -0
- package/dist/commands/index/render.d.ts.map +1 -0
- package/dist/commands/index/render.js +205 -0
- package/dist/commands/index/render.js.map +1 -0
- package/dist/commands/index/target.d.ts +34 -0
- package/dist/commands/index/target.d.ts.map +1 -0
- package/dist/commands/index/target.js +97 -0
- package/dist/commands/index/target.js.map +1 -0
- package/dist/commands/index-watch.d.ts +30 -0
- package/dist/commands/index-watch.d.ts.map +1 -0
- package/dist/commands/index-watch.js +138 -0
- package/dist/commands/index-watch.js.map +1 -0
- package/dist/commands/init/command.d.ts +25 -0
- package/dist/commands/init/command.d.ts.map +1 -0
- package/dist/commands/init/command.js +198 -0
- package/dist/commands/init/command.js.map +1 -0
- package/dist/commands/init/config-draft.d.ts +48 -0
- package/dist/commands/init/config-draft.d.ts.map +1 -0
- package/dist/commands/init/config-draft.js +201 -0
- package/dist/commands/init/config-draft.js.map +1 -0
- package/dist/commands/init/diff.d.ts +33 -0
- package/dist/commands/init/diff.d.ts.map +1 -0
- package/dist/commands/init/diff.js +109 -0
- package/dist/commands/init/diff.js.map +1 -0
- package/dist/commands/init/http-probe.d.ts +26 -0
- package/dist/commands/init/http-probe.d.ts.map +1 -0
- package/dist/commands/init/http-probe.js +144 -0
- package/dist/commands/init/http-probe.js.map +1 -0
- package/dist/commands/init/ignore-rules.d.ts +70 -0
- package/dist/commands/init/ignore-rules.d.ts.map +1 -0
- package/dist/commands/init/ignore-rules.js +146 -0
- package/dist/commands/init/ignore-rules.js.map +1 -0
- package/dist/commands/init/index.d.ts +33 -0
- package/dist/commands/init/index.d.ts.map +1 -0
- package/dist/commands/init/index.js +32 -0
- package/dist/commands/init/index.js.map +1 -0
- package/dist/commands/init/integrations-apply.d.ts +50 -0
- package/dist/commands/init/integrations-apply.d.ts.map +1 -0
- package/dist/commands/init/integrations-apply.js +452 -0
- package/dist/commands/init/integrations-apply.js.map +1 -0
- package/dist/commands/init/integrations-plan.d.ts +68 -0
- package/dist/commands/init/integrations-plan.d.ts.map +1 -0
- package/dist/commands/init/integrations-plan.js +515 -0
- package/dist/commands/init/integrations-plan.js.map +1 -0
- package/dist/commands/init/integrations.d.ts +5 -0
- package/dist/commands/init/integrations.d.ts.map +1 -0
- package/dist/commands/init/integrations.js +4 -0
- package/dist/commands/init/integrations.js.map +1 -0
- package/dist/commands/init/languages.d.ts +55 -0
- package/dist/commands/init/languages.d.ts.map +1 -0
- package/dist/commands/init/languages.js +245 -0
- package/dist/commands/init/languages.js.map +1 -0
- package/dist/commands/init/product-context.d.ts +63 -0
- package/dist/commands/init/product-context.d.ts.map +1 -0
- package/dist/commands/init/product-context.js +390 -0
- package/dist/commands/init/product-context.js.map +1 -0
- package/dist/commands/init/render.d.ts +38 -0
- package/dist/commands/init/render.d.ts.map +1 -0
- package/dist/commands/init/render.js +501 -0
- package/dist/commands/init/render.js.map +1 -0
- package/dist/commands/init/report.d.ts +24 -0
- package/dist/commands/init/report.d.ts.map +1 -0
- package/dist/commands/init/report.js +163 -0
- package/dist/commands/init/report.js.map +1 -0
- package/dist/commands/init/run.d.ts +71 -0
- package/dist/commands/init/run.d.ts.map +1 -0
- package/dist/commands/init/run.js +253 -0
- package/dist/commands/init/run.js.map +1 -0
- package/dist/commands/init/services.d.ts +82 -0
- package/dist/commands/init/services.d.ts.map +1 -0
- package/dist/commands/init/services.js +209 -0
- package/dist/commands/init/services.js.map +1 -0
- package/dist/commands/init/storage.d.ts +8 -0
- package/dist/commands/init/storage.d.ts.map +1 -0
- package/dist/commands/init/storage.js +102 -0
- package/dist/commands/init/storage.js.map +1 -0
- package/dist/commands/init/toml.d.ts +65 -0
- package/dist/commands/init/toml.d.ts.map +1 -0
- package/dist/commands/init/toml.js +159 -0
- package/dist/commands/init/toml.js.map +1 -0
- package/dist/commands/init/topology.d.ts +54 -0
- package/dist/commands/init/topology.d.ts.map +1 -0
- package/dist/commands/init/topology.js +146 -0
- package/dist/commands/init/topology.js.map +1 -0
- package/dist/commands/init/types.d.ts +334 -0
- package/dist/commands/init/types.d.ts.map +1 -0
- package/dist/commands/init/types.js +31 -0
- package/dist/commands/init/types.js.map +1 -0
- package/dist/commands/init/wizard-terminal.d.ts +36 -0
- package/dist/commands/init/wizard-terminal.d.ts.map +1 -0
- package/dist/commands/init/wizard-terminal.js +163 -0
- package/dist/commands/init/wizard-terminal.js.map +1 -0
- package/dist/commands/init/wizard.d.ts +25 -0
- package/dist/commands/init/wizard.d.ts.map +1 -0
- package/dist/commands/init/wizard.js +358 -0
- package/dist/commands/init/wizard.js.map +1 -0
- package/dist/commands/mcp.d.ts +4 -0
- package/dist/commands/mcp.d.ts.map +1 -0
- package/dist/commands/mcp.js +111 -0
- package/dist/commands/mcp.js.map +1 -0
- package/dist/commands/product-test-runner.d.ts +4 -0
- package/dist/commands/product-test-runner.d.ts.map +1 -0
- package/dist/commands/product-test-runner.js +85 -0
- package/dist/commands/product-test-runner.js.map +1 -0
- package/dist/commands/product.d.ts +16 -0
- package/dist/commands/product.d.ts.map +1 -0
- package/dist/commands/product.js +262 -0
- package/dist/commands/product.js.map +1 -0
- package/dist/commands/query.d.ts +114 -0
- package/dist/commands/query.d.ts.map +1 -0
- package/dist/commands/query.js +783 -0
- package/dist/commands/query.js.map +1 -0
- package/dist/commands/scan.d.ts +10 -0
- package/dist/commands/scan.d.ts.map +1 -0
- package/dist/commands/scan.js +302 -0
- package/dist/commands/scan.js.map +1 -0
- package/dist/commands/sdd.d.ts +24 -0
- package/dist/commands/sdd.d.ts.map +1 -0
- package/dist/commands/sdd.js +195 -0
- package/dist/commands/sdd.js.map +1 -0
- package/dist/commands/unavailable.d.ts +40 -0
- package/dist/commands/unavailable.d.ts.map +1 -0
- package/dist/commands/unavailable.js +73 -0
- package/dist/commands/unavailable.js.map +1 -0
- package/dist/commands/watch/analyze.d.ts +69 -0
- package/dist/commands/watch/analyze.d.ts.map +1 -0
- package/dist/commands/watch/analyze.js +402 -0
- package/dist/commands/watch/analyze.js.map +1 -0
- package/dist/commands/watch/cli.d.ts +8 -0
- package/dist/commands/watch/cli.d.ts.map +1 -0
- package/dist/commands/watch/cli.js +97 -0
- package/dist/commands/watch/cli.js.map +1 -0
- package/dist/commands/watch/delta.d.ts +46 -0
- package/dist/commands/watch/delta.d.ts.map +1 -0
- package/dist/commands/watch/delta.js +170 -0
- package/dist/commands/watch/delta.js.map +1 -0
- package/dist/commands/watch/events.d.ts +214 -0
- package/dist/commands/watch/events.d.ts.map +1 -0
- package/dist/commands/watch/events.js +13 -0
- package/dist/commands/watch/events.js.map +1 -0
- package/dist/commands/watch/index.d.ts +19 -0
- package/dist/commands/watch/index.d.ts.map +1 -0
- package/dist/commands/watch/index.js +15 -0
- package/dist/commands/watch/index.js.map +1 -0
- package/dist/commands/watch/options.d.ts +43 -0
- package/dist/commands/watch/options.d.ts.map +1 -0
- package/dist/commands/watch/options.js +193 -0
- package/dist/commands/watch/options.js.map +1 -0
- package/dist/commands/watch/render.d.ts +26 -0
- package/dist/commands/watch/render.d.ts.map +1 -0
- package/dist/commands/watch/render.js +175 -0
- package/dist/commands/watch/render.js.map +1 -0
- package/dist/commands/watch/run.d.ts +14 -0
- package/dist/commands/watch/run.d.ts.map +1 -0
- package/dist/commands/watch/run.js +460 -0
- package/dist/commands/watch/run.js.map +1 -0
- package/dist/commands/watch/runtime.d.ts +67 -0
- package/dist/commands/watch/runtime.d.ts.map +1 -0
- package/dist/commands/watch/runtime.js +149 -0
- package/dist/commands/watch/runtime.js.map +1 -0
- package/dist/commands/watch-command.d.ts +3 -0
- package/dist/commands/watch-command.d.ts.map +1 -0
- package/dist/commands/watch-command.js +273 -0
- package/dist/commands/watch-command.js.map +1 -0
- package/dist/entry-point.d.ts +11 -0
- package/dist/entry-point.d.ts.map +1 -0
- package/dist/entry-point.js +65 -0
- package/dist/entry-point.js.map +1 -0
- package/dist/index.d.ts +38 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +245 -0
- package/dist/index.js.map +1 -0
- package/dist/mcp/boundaries-schema.d.ts +262 -0
- package/dist/mcp/boundaries-schema.d.ts.map +1 -0
- package/dist/mcp/boundaries-schema.js +183 -0
- package/dist/mcp/boundaries-schema.js.map +1 -0
- package/dist/mcp/default-runtime.d.ts +16 -0
- package/dist/mcp/default-runtime.d.ts.map +1 -0
- package/dist/mcp/default-runtime.js +718 -0
- package/dist/mcp/default-runtime.js.map +1 -0
- package/dist/mcp/envelope.d.ts +13 -0
- package/dist/mcp/envelope.d.ts.map +1 -0
- package/dist/mcp/envelope.js +29 -0
- package/dist/mcp/envelope.js.map +1 -0
- package/dist/mcp/index.d.ts +8 -0
- package/dist/mcp/index.d.ts.map +1 -0
- package/dist/mcp/index.js +8 -0
- package/dist/mcp/index.js.map +1 -0
- package/dist/mcp/output-schemas.d.ts +5928 -0
- package/dist/mcp/output-schemas.d.ts.map +1 -0
- package/dist/mcp/output-schemas.js +2814 -0
- package/dist/mcp/output-schemas.js.map +1 -0
- package/dist/mcp/path-sandbox.d.ts +35 -0
- package/dist/mcp/path-sandbox.d.ts.map +1 -0
- package/dist/mcp/path-sandbox.js +128 -0
- package/dist/mcp/path-sandbox.js.map +1 -0
- package/dist/mcp/server.d.ts +155 -0
- package/dist/mcp/server.d.ts.map +1 -0
- package/dist/mcp/server.js +257 -0
- package/dist/mcp/server.js.map +1 -0
- package/dist/mcp/stdio.d.ts +20 -0
- package/dist/mcp/stdio.d.ts.map +1 -0
- package/dist/mcp/stdio.js +71 -0
- package/dist/mcp/stdio.js.map +1 -0
- package/dist/mcp/tools.d.ts +355 -0
- package/dist/mcp/tools.d.ts.map +1 -0
- package/dist/mcp/tools.js +319 -0
- package/dist/mcp/tools.js.map +1 -0
- package/dist/mcp/types.d.ts +15 -0
- package/dist/mcp/types.d.ts.map +1 -0
- package/dist/mcp/types.js +45 -0
- package/dist/mcp/types.js.map +1 -0
- package/package.json +99 -3
- package/src/cli/args.ts +231 -0
- package/src/cli/command.ts +146 -0
- package/src/cli/deadline.ts +56 -0
- package/src/cli/embedder-deadline.ts +187 -0
- package/src/cli/exit.ts +94 -0
- package/src/cli/graphs.ts +191 -0
- package/src/cli/index-freshness.ts +303 -0
- package/src/cli/index-refresh.ts +125 -0
- package/src/cli/index-state.ts +1217 -0
- package/src/cli/io.ts +56 -0
- package/src/cli/language-support.ts +203 -0
- package/src/cli/renewing-lease.ts +121 -0
- package/src/cli/search-graph-enrichment.ts +639 -0
- package/src/cli/system.ts +94 -0
- package/src/cli/vector-store-policy.ts +213 -0
- package/src/cli/version.ts +2 -0
- package/src/cli/workspace.ts +324 -0
- package/src/commands/complexity.ts +776 -0
- package/src/commands/doctor.languages.ts +187 -0
- package/src/commands/doctor.storage.ts +124 -0
- package/src/commands/doctor.ts +946 -0
- package/src/commands/extensions/add.ts +312 -0
- package/src/commands/extensions/configure.ts +82 -0
- package/src/commands/extensions/container.ts +209 -0
- package/src/commands/extensions/context.ts +109 -0
- package/src/commands/extensions/enable.ts +237 -0
- package/src/commands/extensions/environment.ts +218 -0
- package/src/commands/extensions/feature-scan.ts +232 -0
- package/src/commands/extensions/invoke.ts +368 -0
- package/src/commands/extensions/list.ts +158 -0
- package/src/commands/extensions/logs.ts +104 -0
- package/src/commands/extensions/provision.ts +206 -0
- package/src/commands/extensions/remove.ts +110 -0
- package/src/commands/extensions/render.ts +32 -0
- package/src/commands/extensions/run.ts +386 -0
- package/src/commands/extensions/secret-store.ts +223 -0
- package/src/commands/extensions/setup.ts +140 -0
- package/src/commands/extensions/source.ts +189 -0
- package/src/commands/extensions/state.ts +252 -0
- package/src/commands/extensions/status.ts +320 -0
- package/src/commands/extensions.ts +280 -0
- package/src/commands/flow/index.ts +402 -0
- package/src/commands/flow/limits.ts +14 -0
- package/src/commands/flow/output.ts +16 -0
- package/src/commands/flow/render.ts +318 -0
- package/src/commands/flow/select.ts +101 -0
- package/src/commands/graph/boundaries-input.ts +63 -0
- package/src/commands/graph/boundaries.ts +182 -0
- package/src/commands/graph/bounds.ts +25 -0
- package/src/commands/graph/category-clusters.ts +194 -0
- package/src/commands/graph/feature-3d.ts +141 -0
- package/src/commands/graph/feature-clusters.ts +125 -0
- package/src/commands/graph/feature-html.ts +336 -0
- package/src/commands/graph/feature-map.ts +270 -0
- package/src/commands/graph/feature-model.ts +234 -0
- package/src/commands/graph/feature-untangle-motion.ts +192 -0
- package/src/commands/graph/index.ts +562 -0
- package/src/commands/graph/render.ts +503 -0
- package/src/commands/graph/select.ts +77 -0
- package/src/commands/index/index.ts +595 -0
- package/src/commands/index/render.ts +325 -0
- package/src/commands/index/target.ts +136 -0
- package/src/commands/index-watch.ts +206 -0
- package/src/commands/init/command.ts +238 -0
- package/src/commands/init/config-draft.ts +235 -0
- package/src/commands/init/diff.ts +117 -0
- package/src/commands/init/http-probe.ts +150 -0
- package/src/commands/init/ignore-rules.ts +170 -0
- package/src/commands/init/index.ts +63 -0
- package/src/commands/init/integrations-apply.ts +618 -0
- package/src/commands/init/integrations-plan.ts +634 -0
- package/src/commands/init/integrations.ts +8 -0
- package/src/commands/init/languages.ts +320 -0
- package/src/commands/init/product-context.ts +576 -0
- package/src/commands/init/render.ts +598 -0
- package/src/commands/init/report.ts +204 -0
- package/src/commands/init/run.ts +349 -0
- package/src/commands/init/services.ts +271 -0
- package/src/commands/init/storage.ts +136 -0
- package/src/commands/init/toml.ts +174 -0
- package/src/commands/init/topology.ts +192 -0
- package/src/commands/init/types.ts +366 -0
- package/src/commands/init/wizard-terminal.ts +206 -0
- package/src/commands/init/wizard.ts +450 -0
- package/src/commands/mcp.ts +123 -0
- package/src/commands/product-test-runner.ts +80 -0
- package/src/commands/product.ts +331 -0
- package/src/commands/query.ts +1032 -0
- package/src/commands/scan.ts +360 -0
- package/src/commands/sdd.ts +243 -0
- package/src/commands/unavailable.ts +92 -0
- package/src/commands/watch/README.md +160 -0
- package/src/commands/watch/analyze.ts +600 -0
- package/src/commands/watch/cli.ts +108 -0
- package/src/commands/watch/delta.ts +186 -0
- package/src/commands/watch/events.ts +235 -0
- package/src/commands/watch/index.ts +53 -0
- package/src/commands/watch/options.ts +234 -0
- package/src/commands/watch/render.ts +240 -0
- package/src/commands/watch/run.ts +553 -0
- package/src/commands/watch/runtime.ts +167 -0
- package/src/commands/watch-command.ts +294 -0
- package/src/entry-point.ts +67 -0
- package/src/index.ts +291 -0
- package/src/mcp/boundaries-schema.ts +193 -0
- package/src/mcp/default-runtime.ts +1034 -0
- package/src/mcp/envelope.ts +57 -0
- package/src/mcp/index.ts +28 -0
- package/src/mcp/output-schemas.ts +3071 -0
- package/src/mcp/path-sandbox.ts +156 -0
- package/src/mcp/server.ts +358 -0
- package/src/mcp/stdio.ts +92 -0
- package/src/mcp/tools.ts +563 -0
- package/src/mcp/types.ts +66 -0
|
@@ -0,0 +1,318 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Die Darstellung des Symbolgraphen — reine Funktionen, kein I/O.
|
|
3
|
+
*
|
|
4
|
+
* DIE ZUSAGE DIESER DATEI, in einem Satz: KEINE KANTE OHNE IHRE
|
|
5
|
+
* AUFLOESUNGSART UND IHRE CONFIDENCE.
|
|
6
|
+
*
|
|
7
|
+
* Der Symbolgraph unterscheidet vier Auspraegungen (`exact`, `heuristic`,
|
|
8
|
+
* `ambiguous`, `unresolved`) und traegt zu jeder eine Confidence mit Basis und
|
|
9
|
+
* Signalen. Diese Unterschiede sind der eigentliche Wert des Graphen: ein
|
|
10
|
+
* Aufrufpfad, der ueber eine geratene Namensgleichheit fuehrt, ist eine ANDERE
|
|
11
|
+
* Aussage als einer ueber einen aufgeloesten Import. Wer beide gleich
|
|
12
|
+
* darstellt, hat die Information weggeworfen, fuer die der Graph gebaut wurde.
|
|
13
|
+
*
|
|
14
|
+
* Deshalb gilt hier zusaetzlich: EINE MEHRDEUTIGE KANTE ZEIGT ALLE
|
|
15
|
+
* KANDIDATEN, mit ihrem Gewicht. Es wird keiner ausgewaehlt — auch nicht
|
|
16
|
+
* „der wahrscheinlichste".
|
|
17
|
+
*/
|
|
18
|
+
import type { SkipLedgerEntryV1, SymbolEdgeV1, SymbolNodeV1 } from "@untangle-code/domain";
|
|
19
|
+
import { compareCodepoints } from "@untangle-code/domain";
|
|
20
|
+
import type {
|
|
21
|
+
AllCallPathsResultV1,
|
|
22
|
+
CallPathV1,
|
|
23
|
+
EntryPointSetV1,
|
|
24
|
+
ImpactResultV1,
|
|
25
|
+
ShortestCallPathResultV1,
|
|
26
|
+
SymbolGraphIndex,
|
|
27
|
+
} from "@untangle-code/symbol-graph";
|
|
28
|
+
|
|
29
|
+
import { describeSymbol } from "./select.js";
|
|
30
|
+
|
|
31
|
+
/** Kurzform einer Kanten-Confidence: Wert, Basis, Signale. */
|
|
32
|
+
export function describeConfidence(edge: SymbolEdgeV1): string {
|
|
33
|
+
return (
|
|
34
|
+
`Confidence ${edge.confidence.value.toFixed(3)} (${edge.confidence.basis}` +
|
|
35
|
+
`${edge.confidence.signals.length === 0 ? "" : `; ${edge.confidence.signals.join(", ")}`})`
|
|
36
|
+
);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Eine Kante in einer Zeile — und, wenn sie mehrdeutig oder unaufgeloest ist,
|
|
41
|
+
* in mehreren.
|
|
42
|
+
*/
|
|
43
|
+
export function describeEdge(edge: SymbolEdgeV1, indent: string): string[] {
|
|
44
|
+
const lines: string[] = [];
|
|
45
|
+
const qualifier = edge.toQualifier === undefined ? "" : `${edge.toQualifier}.`;
|
|
46
|
+
lines.push(
|
|
47
|
+
`${indent}${edge.kind} "${qualifier}${edge.toName}" [${edge.resolution}] ${describeConfidence(edge)}` +
|
|
48
|
+
(edge.crossRepo ? " >> crosses a repository boundary" : ""),
|
|
49
|
+
);
|
|
50
|
+
if (edge.resolution === "exact" || edge.resolution === "heuristic") {
|
|
51
|
+
const target = edge.target;
|
|
52
|
+
if (target !== undefined) {
|
|
53
|
+
lines.push(`${indent} -> ${target.qualifiedName} ${target.filePath}`);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
if (edge.resolution === "ambiguous") {
|
|
57
|
+
const candidates = [...(edge.candidates ?? [])].sort(
|
|
58
|
+
(left, right) =>
|
|
59
|
+
right.weight - left.weight || compareCodepoints(left.symbolId, right.symbolId),
|
|
60
|
+
);
|
|
61
|
+
lines.push(`${indent} AMBIGUOUS: ${String(candidates.length)} candidates; none selected:`);
|
|
62
|
+
for (const candidate of candidates) {
|
|
63
|
+
lines.push(
|
|
64
|
+
`${indent} ${candidate.weight.toFixed(3)} ${candidate.qualifiedName} ${candidate.filePath}`,
|
|
65
|
+
);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
if (edge.resolution === "unresolved") {
|
|
69
|
+
lines.push(
|
|
70
|
+
`${indent} UNRESOLVED: ${edge.unresolvedReason ?? "no reason given"} — ${edge.unresolvedDetail ?? ""}`.trimEnd(),
|
|
71
|
+
);
|
|
72
|
+
}
|
|
73
|
+
for (const site of edge.sites) {
|
|
74
|
+
lines.push(`${indent} Location: ${site.filePath}:${String(site.range.startLine)}`);
|
|
75
|
+
}
|
|
76
|
+
if (edge.sites.length === 0 && edge.sitesMissingReason !== undefined) {
|
|
77
|
+
lines.push(`${indent} no source location: ${edge.sitesMissingReason}`);
|
|
78
|
+
}
|
|
79
|
+
return lines;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/** Ein Aufrufpfad: Knoten, Kanten, und was den Pfad schwaecht. */
|
|
83
|
+
export function renderPath(index: SymbolGraphIndex, path: CallPathV1, title: string): string[] {
|
|
84
|
+
const lines: string[] = [];
|
|
85
|
+
lines.push(
|
|
86
|
+
`${title} Depth ${String(path.depth)} Confidence ${path.confidence.toFixed(3)} ` +
|
|
87
|
+
`weakest resolution: ${path.weakestResolution}` +
|
|
88
|
+
(path.containsAmbiguous ? " INCLUDES AMBIGUOUS EDGES" : ""),
|
|
89
|
+
);
|
|
90
|
+
for (let i = 0; i < path.symbolIds.length; i++) {
|
|
91
|
+
const node = index.node(path.symbolIds[i] as string);
|
|
92
|
+
lines.push(` ${node === null ? (path.symbolIds[i] as string) : describeSymbol(node)}`);
|
|
93
|
+
const edgeId = path.edgeIds[i];
|
|
94
|
+
if (edgeId === undefined) continue;
|
|
95
|
+
const edge = index.edge(edgeId);
|
|
96
|
+
if (edge === null) {
|
|
97
|
+
lines.push(` (edge ${edgeId} missing from snapshot)`);
|
|
98
|
+
continue;
|
|
99
|
+
}
|
|
100
|
+
lines.push(...describeEdge(edge, " "));
|
|
101
|
+
}
|
|
102
|
+
return lines;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* Der kuerzeste Pfad — oder der benannte Grund, warum es keinen gibt.
|
|
107
|
+
*
|
|
108
|
+
* `wallTimeEnforced` ist kein Zierrat: das Zeitbudget der Suche wird nur
|
|
109
|
+
* geprueft, wenn ihr eine Zeitquelle mitgegeben wurde. Ohne sie steht in
|
|
110
|
+
* `limits.maxWallTimeMs` eine Zahl, an die sich nichts haelt — und eine
|
|
111
|
+
* Budgetzeile, die eine nicht durchgesetzte Grenze wie eine durchgesetzte
|
|
112
|
+
* ausgibt, ist genau die stille Unwahrheit, die E4 verbietet.
|
|
113
|
+
*/
|
|
114
|
+
export function renderShortest(
|
|
115
|
+
index: SymbolGraphIndex,
|
|
116
|
+
result: ShortestCallPathResultV1,
|
|
117
|
+
wallTimeEnforced = true,
|
|
118
|
+
): string[] {
|
|
119
|
+
const lines: string[] = ["SHORTEST CALL PATH"];
|
|
120
|
+
if (result.path === null) {
|
|
121
|
+
lines.push(
|
|
122
|
+
` NO PATH: ${result.missReason ?? "no reason given"}` +
|
|
123
|
+
(result.missDetail === undefined ? "" : ` — ${result.missDetail}`),
|
|
124
|
+
);
|
|
125
|
+
} else {
|
|
126
|
+
lines.push(...renderPath(index, result.path, " Path"));
|
|
127
|
+
}
|
|
128
|
+
if (result.truncated) {
|
|
129
|
+
lines.push(` TRUNCATED: ${result.truncationReason ?? "unknown"}; the search was incomplete.`);
|
|
130
|
+
}
|
|
131
|
+
lines.push(
|
|
132
|
+
` Budgets: maxDepth=${String(result.limits.maxDepth)} maxNodes=${String(result.limits.maxNodes)} ` +
|
|
133
|
+
`maxEdges=${String(result.limits.maxEdges)} maxWallTimeMs=${String(result.limits.maxWallTimeMs)}` +
|
|
134
|
+
(wallTimeEnforced
|
|
135
|
+
? ""
|
|
136
|
+
: " (maxWallTimeMs is not enforced: the search deliberately receives no " +
|
|
137
|
+
"clock, so repeated runs over the same index produce identical output)"),
|
|
138
|
+
);
|
|
139
|
+
return lines;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
/** Alle Pfade bis Tiefe N — samt der verworfenen, die nie stumm verschwinden. */
|
|
143
|
+
export function renderAllPaths(index: SymbolGraphIndex, result: AllCallPathsResultV1): string[] {
|
|
144
|
+
const lines: string[] = [`ALL CALL PATHS UP TO DEPTH ${String(result.maxDepth)}`];
|
|
145
|
+
if (result.paths.length === 0) {
|
|
146
|
+
lines.push(
|
|
147
|
+
` NO PATH: ${result.missReason ?? "no reason given"}` +
|
|
148
|
+
(result.missDetail === undefined ? "" : ` — ${result.missDetail}`),
|
|
149
|
+
);
|
|
150
|
+
}
|
|
151
|
+
for (let i = 0; i < result.paths.length; i++) {
|
|
152
|
+
lines.push(...renderPath(index, result.paths[i] as CallPathV1, ` Path ${String(i + 1)}`));
|
|
153
|
+
}
|
|
154
|
+
if (result.pathLimitReached) {
|
|
155
|
+
const count = result.droppedPathCountExact
|
|
156
|
+
? String(result.droppedPathCount)
|
|
157
|
+
: `at least ${String(result.droppedPathCount)}`;
|
|
158
|
+
lines.push(
|
|
159
|
+
` PATH LIMIT REACHED: ${count} additional paths were discarded ` +
|
|
160
|
+
"(increase the limit with --limit).",
|
|
161
|
+
);
|
|
162
|
+
}
|
|
163
|
+
if (result.truncated) {
|
|
164
|
+
lines.push(` TRUNCATED: ${result.truncationReason ?? "unknown"}.`);
|
|
165
|
+
}
|
|
166
|
+
lines.push(...renderLedgerEntries(result.skipped, " "));
|
|
167
|
+
return lines;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
/** Einstiegspunkte — als das, was sie sind: Heuristik mit Belegen. */
|
|
171
|
+
export function renderEntryPoints(set: EntryPointSetV1, limit: number): string[] {
|
|
172
|
+
const lines: string[] = [
|
|
173
|
+
`ENTRY POINTS (${String(set.entryPoints.length)}) — heuristic, not a measurement`,
|
|
174
|
+
];
|
|
175
|
+
const sorted = [...set.entryPoints].sort(
|
|
176
|
+
(left, right) =>
|
|
177
|
+
right.confidence.value - left.confidence.value ||
|
|
178
|
+
compareCodepoints(left.filePath, right.filePath) ||
|
|
179
|
+
compareCodepoints(left.symbolId, right.symbolId),
|
|
180
|
+
);
|
|
181
|
+
for (const entry of sorted.slice(0, limit)) {
|
|
182
|
+
lines.push(
|
|
183
|
+
` ${entry.confidence.value.toFixed(3)} ${entry.qualifiedName} ${entry.filePath} ` +
|
|
184
|
+
`[${entry.kinds.join(", ")}]`,
|
|
185
|
+
);
|
|
186
|
+
for (const signal of entry.signals) {
|
|
187
|
+
lines.push(` ${signal.kind} (+${signal.weight.toFixed(2)}): ${signal.reason}`);
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
if (sorted.length > limit) {
|
|
191
|
+
lines.push(` … ${String(sorted.length - limit)} more (increase --limit).`);
|
|
192
|
+
}
|
|
193
|
+
const kinds = Object.keys(set.countsByKind).sort(compareCodepoints);
|
|
194
|
+
lines.push(
|
|
195
|
+
` by kind: ${kinds.map((kind) => `${kind} ${String(set.countsByKind[kind as keyof typeof set.countsByKind] ?? 0)}`).join(", ")}`,
|
|
196
|
+
);
|
|
197
|
+
return lines;
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
/** Impact: wer ist betroffen, wie sicher ist das, und was fehlt trotzdem. */
|
|
201
|
+
export function renderImpact(
|
|
202
|
+
index: SymbolGraphIndex,
|
|
203
|
+
result: ImpactResultV1,
|
|
204
|
+
limit: number,
|
|
205
|
+
): string[] {
|
|
206
|
+
const lines: string[] = [
|
|
207
|
+
`AFFECTED SYMBOLS (${String(result.affected.length)}) — confidence threshold ${result.minConfidence.toFixed(3)}`,
|
|
208
|
+
];
|
|
209
|
+
const sorted = [...result.affected].sort(
|
|
210
|
+
(left, right) =>
|
|
211
|
+
right.confidence - left.confidence ||
|
|
212
|
+
left.minDepth - right.minDepth ||
|
|
213
|
+
compareCodepoints(left.symbolId, right.symbolId),
|
|
214
|
+
);
|
|
215
|
+
for (const affected of sorted.slice(0, limit)) {
|
|
216
|
+
lines.push(
|
|
217
|
+
` ${affected.confidence.toFixed(3)} ${affected.qualifiedName} ${affected.filePath} ` +
|
|
218
|
+
`Depth ${String(affected.depth)} (shortest path ${String(affected.minDepth)}) ` +
|
|
219
|
+
`weakest resolution: ${affected.weakestResolution}` +
|
|
220
|
+
(affected.throughAmbiguous ? " VIA AMBIGUOUS EDGE" : ""),
|
|
221
|
+
);
|
|
222
|
+
for (const edgeId of affected.viaEdgeIds) {
|
|
223
|
+
const edge = index.edge(edgeId);
|
|
224
|
+
if (edge === null) {
|
|
225
|
+
lines.push(` (edge ${edgeId} missing from snapshot)`);
|
|
226
|
+
continue;
|
|
227
|
+
}
|
|
228
|
+
lines.push(...describeEdge(edge, " "));
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
if (sorted.length > limit) {
|
|
232
|
+
lines.push(` … ${String(sorted.length - limit)} more (increase --limit).`);
|
|
233
|
+
}
|
|
234
|
+
lines.push(
|
|
235
|
+
` Ambiguous edges involved: ${result.containsAmbiguousEdges ? `yes (${String(result.ambiguousEdgeIds.length)})` : "no"}`,
|
|
236
|
+
);
|
|
237
|
+
if (result.traversal.truncated) {
|
|
238
|
+
lines.push(
|
|
239
|
+
` TRUNCATED: ${result.traversal.truncationReason ?? "unknown"}; the result is incomplete.`,
|
|
240
|
+
);
|
|
241
|
+
}
|
|
242
|
+
lines.push(...renderLedgerEntries(result.skipped, " "));
|
|
243
|
+
return lines;
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
/** Was ein Symbol ruft und wer es ruft — jede Kante mit Art und Confidence. */
|
|
247
|
+
export function renderSymbolOverview(index: SymbolGraphIndex, node: SymbolNodeV1): string[] {
|
|
248
|
+
const lines: string[] = [];
|
|
249
|
+
lines.push(`Symbol ${describeSymbol(node)}`);
|
|
250
|
+
lines.push(
|
|
251
|
+
` Repository ${node.repoId} Lines ${String(node.startLine)}-${String(node.endLine)} ` +
|
|
252
|
+
`incoming ${String(index.inDegree(node.id))}, outgoing ${String(index.outDegree(node.id))}`,
|
|
253
|
+
);
|
|
254
|
+
lines.push("");
|
|
255
|
+
|
|
256
|
+
const outgoing = index.outgoingEdges(node.id);
|
|
257
|
+
lines.push(`CALLEES (${String(outgoing.length)} edges, including unresolved edges)`);
|
|
258
|
+
if (outgoing.length === 0) lines.push(" (none)");
|
|
259
|
+
for (const edge of outgoing) {
|
|
260
|
+
lines.push(...describeEdge(edge, " "));
|
|
261
|
+
}
|
|
262
|
+
lines.push("");
|
|
263
|
+
|
|
264
|
+
const callers = index.callers(node.id);
|
|
265
|
+
lines.push(`CALLERS (${String(callers.length)} bindings)`);
|
|
266
|
+
if (callers.length === 0) {
|
|
267
|
+
lines.push(" (no callers in the index; this may be an entry point, see --entry-points)");
|
|
268
|
+
}
|
|
269
|
+
for (const binding of callers) {
|
|
270
|
+
const caller = index.node(binding.symbolId);
|
|
271
|
+
lines.push(
|
|
272
|
+
` ${binding.weight.toFixed(3)} [${binding.resolution}${binding.ambiguous ? ", ambiguous" : ""}] ` +
|
|
273
|
+
`${caller === null ? binding.symbolId : describeSymbol(caller)}`,
|
|
274
|
+
);
|
|
275
|
+
}
|
|
276
|
+
return lines;
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
/** Ledger-Eintraege: jede Auslassung mit Grund (E4). */
|
|
280
|
+
export function renderLedgerEntries(
|
|
281
|
+
entries: readonly SkipLedgerEntryV1[],
|
|
282
|
+
indent: string,
|
|
283
|
+
): string[] {
|
|
284
|
+
if (entries.length === 0) return [];
|
|
285
|
+
const lines: string[] = [`${indent}SKIPPED (${String(entries.length)}):`];
|
|
286
|
+
for (const entry of entries) {
|
|
287
|
+
lines.push(
|
|
288
|
+
`${indent} ${entry.subjectId ?? entry.path ?? "(no item)"} ${entry.reason}: ${entry.detail}`,
|
|
289
|
+
);
|
|
290
|
+
}
|
|
291
|
+
return lines;
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
/** Kennzahlen des Symbolgraphen, als Kopfzeile jeder Ausgabe. */
|
|
295
|
+
export function renderSymbolGraphHeader(
|
|
296
|
+
index: SymbolGraphIndex,
|
|
297
|
+
generationId: string,
|
|
298
|
+
ledgerInShard: boolean,
|
|
299
|
+
): string[] {
|
|
300
|
+
const metrics = index.graph.metrics;
|
|
301
|
+
const lines: string[] = [];
|
|
302
|
+
lines.push(`Symbol graph Generation ${generationId}`);
|
|
303
|
+
lines.push(
|
|
304
|
+
` ${String(metrics.nodeCount)} symbols, ${String(metrics.edgeCount)} edges from ${String(metrics.fileCount)} files`,
|
|
305
|
+
);
|
|
306
|
+
lines.push(
|
|
307
|
+
` Resolution: exact ${(metrics.exactEdgeRate * 100).toFixed(1)} %, ` +
|
|
308
|
+
`ambiguous ${(metrics.ambiguousEdgeRate * 100).toFixed(1)} %, ` +
|
|
309
|
+
`unresolved ${(metrics.unresolvedEdgeRate * 100).toFixed(1)} %`,
|
|
310
|
+
);
|
|
311
|
+
if (!ledgerInShard) {
|
|
312
|
+
lines.push(
|
|
313
|
+
" Note: the stored shard has no skip ledger; skipped " +
|
|
314
|
+
"graph-build items appear in the `untangle index` report.",
|
|
315
|
+
);
|
|
316
|
+
}
|
|
317
|
+
return lines;
|
|
318
|
+
}
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Von einem getippten Symbolnamen zum Knoten des Symbolgraphen.
|
|
3
|
+
*
|
|
4
|
+
* DIE REGEL DIESES MODULS IST DIESELBE WIE DIE DES SYMBOLGRAPHEN SELBST: bei
|
|
5
|
+
* mehreren Kandidaten wird KEINER heimlich gewaehlt. `untangle flow` zeigt
|
|
6
|
+
* dann alle und verlangt eine Entscheidung. Ein Werkzeug, das hier raet,
|
|
7
|
+
* beantwortet eine andere Frage als die gestellte — und sagt es nicht.
|
|
8
|
+
*
|
|
9
|
+
* Erlaubte Schreibweisen, von der staerksten zur schwaechsten:
|
|
10
|
+
* `sym_ab12…` die Symbol-ID
|
|
11
|
+
* `Klasse.methode` der qualifizierte Name
|
|
12
|
+
* `pfad/datei.ts:name` Name in einer bestimmten Datei
|
|
13
|
+
* `name` der blosse Name
|
|
14
|
+
*/
|
|
15
|
+
import type { SymbolNodeV1 } from "@untangle-code/domain";
|
|
16
|
+
import { compareCodepoints } from "@untangle-code/domain";
|
|
17
|
+
|
|
18
|
+
export type SymbolSelectionV1 =
|
|
19
|
+
| {
|
|
20
|
+
status: "found";
|
|
21
|
+
node: SymbolNodeV1;
|
|
22
|
+
matchedBy: "symbol_id" | "qualified_name" | "file_and_name" | "name";
|
|
23
|
+
}
|
|
24
|
+
| { status: "ambiguous"; candidates: SymbolNodeV1[]; matchedBy: string }
|
|
25
|
+
| { status: "absent"; near: SymbolNodeV1[] };
|
|
26
|
+
|
|
27
|
+
function order(left: SymbolNodeV1, right: SymbolNodeV1): number {
|
|
28
|
+
return (
|
|
29
|
+
compareCodepoints(left.filePath, right.filePath) ||
|
|
30
|
+
left.startLine - right.startLine ||
|
|
31
|
+
compareCodepoints(left.id, right.id)
|
|
32
|
+
);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/** Beschreibt einen Kandidaten so, dass der Nutzer ihn eindeutig nachtippen kann. */
|
|
36
|
+
export function describeSymbol(node: SymbolNodeV1): string {
|
|
37
|
+
return `${node.qualifiedName} ${node.filePath}:${String(node.startLine)} [${node.kind}]`;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export function selectSymbolNode(nodes: readonly SymbolNodeV1[], query: string): SymbolSelectionV1 {
|
|
41
|
+
const trimmed = query.trim();
|
|
42
|
+
|
|
43
|
+
const byId = nodes.filter((node) => node.id === trimmed);
|
|
44
|
+
if (byId.length === 1) {
|
|
45
|
+
return { status: "found", node: byId[0] as SymbolNodeV1, matchedBy: "symbol_id" };
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
const byQualified = nodes.filter((node) => node.qualifiedName === trimmed);
|
|
49
|
+
if (byQualified.length === 1) {
|
|
50
|
+
return { status: "found", node: byQualified[0] as SymbolNodeV1, matchedBy: "qualified_name" };
|
|
51
|
+
}
|
|
52
|
+
if (byQualified.length > 1) {
|
|
53
|
+
return {
|
|
54
|
+
status: "ambiguous",
|
|
55
|
+
candidates: [...byQualified].sort(order),
|
|
56
|
+
matchedBy: "qualified_name",
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
// `pfad/datei.ts:name` — der Doppelpunkt trennt nur, wenn rechts davon kein
|
|
61
|
+
// Pfadtrenner mehr steht.
|
|
62
|
+
const separator = trimmed.lastIndexOf(":");
|
|
63
|
+
if (separator > 0 && !trimmed.slice(separator + 1).includes("/")) {
|
|
64
|
+
const filePart = trimmed.slice(0, separator).replaceAll("\\", "/");
|
|
65
|
+
const namePart = trimmed.slice(separator + 1);
|
|
66
|
+
const inFile = nodes.filter(
|
|
67
|
+
(node) =>
|
|
68
|
+
(node.name === namePart || node.qualifiedName === namePart) &&
|
|
69
|
+
(node.filePath === filePart || node.filePath.endsWith(`/${filePart}`)),
|
|
70
|
+
);
|
|
71
|
+
if (inFile.length === 1) {
|
|
72
|
+
return { status: "found", node: inFile[0] as SymbolNodeV1, matchedBy: "file_and_name" };
|
|
73
|
+
}
|
|
74
|
+
if (inFile.length > 1) {
|
|
75
|
+
return {
|
|
76
|
+
status: "ambiguous",
|
|
77
|
+
candidates: [...inFile].sort(order),
|
|
78
|
+
matchedBy: "file_and_name",
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
const byName = nodes.filter((node) => node.name === trimmed);
|
|
84
|
+
if (byName.length === 1) {
|
|
85
|
+
return { status: "found", node: byName[0] as SymbolNodeV1, matchedBy: "name" };
|
|
86
|
+
}
|
|
87
|
+
if (byName.length > 1) {
|
|
88
|
+
return { status: "ambiguous", candidates: [...byName].sort(order), matchedBy: "name" };
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
const lowered = trimmed.toLowerCase();
|
|
92
|
+
const near = nodes
|
|
93
|
+
.filter(
|
|
94
|
+
(node) =>
|
|
95
|
+
node.name.toLowerCase().includes(lowered) ||
|
|
96
|
+
node.qualifiedName.toLowerCase().includes(lowered),
|
|
97
|
+
)
|
|
98
|
+
.sort(order)
|
|
99
|
+
.slice(0, 10);
|
|
100
|
+
return { status: "absent", near };
|
|
101
|
+
}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import * as z from "zod/v4";
|
|
2
|
+
|
|
3
|
+
/** Repository-relative roots are selectors, never filesystem escape paths. */
|
|
4
|
+
const rootSelector = z
|
|
5
|
+
.string()
|
|
6
|
+
.max(4096)
|
|
7
|
+
.refine(
|
|
8
|
+
(value) =>
|
|
9
|
+
value === "" ||
|
|
10
|
+
(!value.startsWith("/") &&
|
|
11
|
+
!/[:\\*?[\]{}]/u.test(value) &&
|
|
12
|
+
value.split("/").every((part) => part !== "" && part !== "." && part !== "..") &&
|
|
13
|
+
!Array.from(value).some((character) => character.charCodeAt(0) < 32)),
|
|
14
|
+
"Expected a literal repository-relative directory (empty string selects the repository root).",
|
|
15
|
+
);
|
|
16
|
+
|
|
17
|
+
const origin = z
|
|
18
|
+
.string()
|
|
19
|
+
.max(4096)
|
|
20
|
+
.refine((value) => {
|
|
21
|
+
try {
|
|
22
|
+
const url = new URL(value);
|
|
23
|
+
return (
|
|
24
|
+
["http:", "https:"].includes(url.protocol) &&
|
|
25
|
+
!url.username &&
|
|
26
|
+
!url.password &&
|
|
27
|
+
url.pathname === "/" &&
|
|
28
|
+
!url.search &&
|
|
29
|
+
!url.hash
|
|
30
|
+
);
|
|
31
|
+
} catch {
|
|
32
|
+
return false;
|
|
33
|
+
}
|
|
34
|
+
}, "Expected an HTTP(S) origin without credentials, path, query or fragment.");
|
|
35
|
+
|
|
36
|
+
export const httpServiceBindingSchema = z
|
|
37
|
+
.object({
|
|
38
|
+
id: z.string().trim().min(1).max(256),
|
|
39
|
+
frontendRoots: z.array(rootSelector).min(1).max(32),
|
|
40
|
+
backendRoots: z.array(rootSelector).min(1).max(32),
|
|
41
|
+
sameOrigin: z.boolean().optional(),
|
|
42
|
+
origins: z.array(origin).max(32).optional(),
|
|
43
|
+
})
|
|
44
|
+
.strict();
|
|
45
|
+
|
|
46
|
+
export const httpServiceBindingsSchema = z
|
|
47
|
+
.array(httpServiceBindingSchema)
|
|
48
|
+
.max(100)
|
|
49
|
+
.superRefine((services, ctx) => {
|
|
50
|
+
const ids = new Set<string>();
|
|
51
|
+
services.forEach((service, i) => {
|
|
52
|
+
if (ids.has(service.id))
|
|
53
|
+
ctx.addIssue({ code: "custom", path: [i, "id"], message: "Service ids must be unique." });
|
|
54
|
+
ids.add(service.id);
|
|
55
|
+
});
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
export const httpServicesFileSchema = z
|
|
59
|
+
.object({
|
|
60
|
+
schemaVersion: z.literal(1),
|
|
61
|
+
services: httpServiceBindingsSchema,
|
|
62
|
+
})
|
|
63
|
+
.strict();
|
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
import { createHash } from "node:crypto";
|
|
2
|
+
import { readFileSync, realpathSync, statSync } from "node:fs";
|
|
3
|
+
import path from "node:path";
|
|
4
|
+
|
|
5
|
+
import { analyzeFrontendBoundaries } from "@untangle-code/core";
|
|
6
|
+
import type { HttpServiceBindingV1 } from "@untangle-code/domain";
|
|
7
|
+
|
|
8
|
+
import { enumFlag, integerFlag, stringFlag, type ParsedArgs } from "../../cli/args.js";
|
|
9
|
+
import type { CommandContext } from "../../cli/command.js";
|
|
10
|
+
import { EXIT, OperationalError, UsageError } from "../../cli/exit.js";
|
|
11
|
+
import { line } from "../../cli/io.js";
|
|
12
|
+
import { loadWorkspace } from "../../cli/workspace.js";
|
|
13
|
+
|
|
14
|
+
import { httpServicesFileSchema } from "./boundaries-input.js";
|
|
15
|
+
|
|
16
|
+
interface ServiceControl {
|
|
17
|
+
path: string;
|
|
18
|
+
status: "loaded" | "missing";
|
|
19
|
+
contentHash?: string;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
function inside(root: string, candidate: string): boolean {
|
|
23
|
+
const relative = path.relative(root, candidate);
|
|
24
|
+
return relative !== ".." && !relative.startsWith(".." + path.sep) && !path.isAbsolute(relative);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
function readServices(
|
|
28
|
+
root: string,
|
|
29
|
+
requested: string | undefined,
|
|
30
|
+
): {
|
|
31
|
+
services: HttpServiceBindingV1[];
|
|
32
|
+
control: ServiceControl;
|
|
33
|
+
verify: () => void;
|
|
34
|
+
} {
|
|
35
|
+
const selected = requested ?? ".untangle/services.json";
|
|
36
|
+
const candidate = path.resolve(root, selected);
|
|
37
|
+
if (!inside(root, candidate))
|
|
38
|
+
throw new UsageError("Service configuration must be inside the project root.");
|
|
39
|
+
const controlPath = path.relative(root, candidate).split(path.sep).join("/");
|
|
40
|
+
let physical: string;
|
|
41
|
+
try {
|
|
42
|
+
physical = realpathSync(candidate);
|
|
43
|
+
} catch (error) {
|
|
44
|
+
if (requested === undefined && (error as NodeJS.ErrnoException).code === "ENOENT") {
|
|
45
|
+
return {
|
|
46
|
+
services: [],
|
|
47
|
+
control: { path: controlPath, status: "missing" },
|
|
48
|
+
verify: () => {
|
|
49
|
+
try {
|
|
50
|
+
realpathSync(candidate);
|
|
51
|
+
} catch (failure) {
|
|
52
|
+
if ((failure as NodeJS.ErrnoException).code === "ENOENT") return;
|
|
53
|
+
throw failure;
|
|
54
|
+
}
|
|
55
|
+
throw new OperationalError(
|
|
56
|
+
"Service configuration appeared during the analysis; repeat it.",
|
|
57
|
+
);
|
|
58
|
+
},
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
throw new OperationalError("Service configuration could not be read.");
|
|
62
|
+
}
|
|
63
|
+
if (!inside(root, physical))
|
|
64
|
+
throw new UsageError("Service configuration resolves outside the project root.");
|
|
65
|
+
const stat = statSync(physical);
|
|
66
|
+
if (!stat.isFile() || stat.size > 1024 * 1024)
|
|
67
|
+
throw new UsageError("Service configuration must be a regular JSON file no larger than 1 MiB.");
|
|
68
|
+
const bytes = readFileSync(physical);
|
|
69
|
+
let raw: unknown;
|
|
70
|
+
try {
|
|
71
|
+
raw = JSON.parse(new TextDecoder("utf-8", { fatal: true }).decode(bytes));
|
|
72
|
+
} catch {
|
|
73
|
+
throw new UsageError("Service configuration is not valid UTF-8 JSON.");
|
|
74
|
+
}
|
|
75
|
+
const parsed = httpServicesFileSchema.safeParse(raw);
|
|
76
|
+
if (!parsed.success)
|
|
77
|
+
throw new UsageError(
|
|
78
|
+
"Invalid service configuration: " +
|
|
79
|
+
parsed.error.issues.map((issue) => issue.path.join(".") + ": " + issue.message).join("; "),
|
|
80
|
+
);
|
|
81
|
+
const digest = (value: Uint8Array) => createHash("sha256").update(value).digest("hex");
|
|
82
|
+
const contentHash = digest(bytes);
|
|
83
|
+
return {
|
|
84
|
+
services: parsed.data.services.map((service) => ({
|
|
85
|
+
id: service.id,
|
|
86
|
+
frontendRoots: service.frontendRoots,
|
|
87
|
+
backendRoots: service.backendRoots,
|
|
88
|
+
...(service.sameOrigin === undefined ? {} : { sameOrigin: service.sameOrigin }),
|
|
89
|
+
...(service.origins === undefined ? {} : { origins: service.origins }),
|
|
90
|
+
})),
|
|
91
|
+
control: { path: controlPath, status: "loaded", contentHash },
|
|
92
|
+
verify: () => {
|
|
93
|
+
if (realpathSync(candidate) !== physical || digest(readFileSync(physical)) !== contentHash)
|
|
94
|
+
throw new OperationalError("Service configuration changed during the analysis; repeat it.");
|
|
95
|
+
},
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
export async function runBoundaries(ctx: CommandContext, args: ParsedArgs): Promise<number> {
|
|
100
|
+
const allowed = new Set(["root", "services", "path", "max-relations", "format"]);
|
|
101
|
+
for (const flag of Object.keys(args.flags))
|
|
102
|
+
if (!allowed.has(flag))
|
|
103
|
+
throw new UsageError(`Option --${flag} is not supported by graph boundaries.`);
|
|
104
|
+
const format = enumFlag(args, "format", ["text", "json"] as const, "text");
|
|
105
|
+
const maxRelations = integerFlag(args, "max-relations", 200);
|
|
106
|
+
if (maxRelations < 1 || maxRelations > 1000)
|
|
107
|
+
throw new UsageError("--max-relations must be between 1 and 1000.");
|
|
108
|
+
const rootFlag = stringFlag(args, "root");
|
|
109
|
+
const workspace = loadWorkspace({
|
|
110
|
+
cwd: path.resolve(ctx.cwd, rootFlag ?? "."),
|
|
111
|
+
env: ctx.env,
|
|
112
|
+
strict: true,
|
|
113
|
+
});
|
|
114
|
+
const root = realpathSync(
|
|
115
|
+
rootFlag === undefined ? workspace.root : path.resolve(ctx.cwd, rootFlag),
|
|
116
|
+
);
|
|
117
|
+
const services = readServices(root, stringFlag(args, "services"));
|
|
118
|
+
const selectedPath = stringFlag(args, "path");
|
|
119
|
+
if (
|
|
120
|
+
selectedPath !== undefined &&
|
|
121
|
+
(!selectedPath ||
|
|
122
|
+
selectedPath.length > 4096 ||
|
|
123
|
+
selectedPath.startsWith("/") ||
|
|
124
|
+
/[:\\*?[\]{}]/u.test(selectedPath) ||
|
|
125
|
+
selectedPath.split("/").some((part) => !part || part === "." || part === ".."))
|
|
126
|
+
)
|
|
127
|
+
throw new UsageError("--path must be one literal repository-relative file path.");
|
|
128
|
+
const repository = (workspace.config.repositories ?? []).find(
|
|
129
|
+
(entry) => path.resolve(workspace.load.sources.configBaseDir, entry.path) === root,
|
|
130
|
+
);
|
|
131
|
+
const report = await analyzeFrontendBoundaries({
|
|
132
|
+
root,
|
|
133
|
+
services: services.services,
|
|
134
|
+
maxRelations,
|
|
135
|
+
...(selectedPath === undefined ? {} : { path: selectedPath }),
|
|
136
|
+
...(repository?.exclude === undefined
|
|
137
|
+
? {}
|
|
138
|
+
: { inventoryScope: { additionalDefaultExcludes: repository.exclude } }),
|
|
139
|
+
signal: ctx.signal,
|
|
140
|
+
});
|
|
141
|
+
ctx.signal.throwIfAborted();
|
|
142
|
+
services.verify();
|
|
143
|
+
const data = { ...report, servicesManifest: services.control };
|
|
144
|
+
if (format === "json") line(ctx.io, JSON.stringify(data, null, 2));
|
|
145
|
+
else {
|
|
146
|
+
line(
|
|
147
|
+
ctx.io,
|
|
148
|
+
`Frontend/backend HTTP dependencies: ${report.status}; sources ${report.freshness.status}`,
|
|
149
|
+
);
|
|
150
|
+
line(
|
|
151
|
+
ctx.io,
|
|
152
|
+
`${report.http.summary.endpoints} endpoints; ${report.http.summary.requests} requests: ${report.http.summary.resolved} resolved, ${report.http.summary.ambiguous} ambiguous, ${report.http.summary.unresolved} unresolved.`,
|
|
153
|
+
);
|
|
154
|
+
for (const request of report.http.requests) {
|
|
155
|
+
line(
|
|
156
|
+
ctx.io,
|
|
157
|
+
`${request.source.path}:${request.source.range.startLine} ${request.method ?? "?"} ${request.path ?? "?"} [${request.status}]`,
|
|
158
|
+
);
|
|
159
|
+
for (const target of request.targets) {
|
|
160
|
+
const route = target.provenance.find((item) => item.kind === "route");
|
|
161
|
+
line(
|
|
162
|
+
ctx.io,
|
|
163
|
+
` -> ${target.serviceId ?? "unbound"} ${target.handler}${route ? " " + route.path + ":" + route.range.startLine : ""}`,
|
|
164
|
+
);
|
|
165
|
+
}
|
|
166
|
+
if (request.reason) line(ctx.io, " " + request.reason);
|
|
167
|
+
}
|
|
168
|
+
for (const importer of report.importContext.requestImporters)
|
|
169
|
+
line(
|
|
170
|
+
ctx.io,
|
|
171
|
+
`Import context: ${importer.path} -> ${importer.requestPath} (${importer.distance} import edges; no function-call proof)`,
|
|
172
|
+
);
|
|
173
|
+
line(
|
|
174
|
+
ctx.io,
|
|
175
|
+
`Feature associations: ${report.features.associationCount}; declared dependsOn remains unchanged.`,
|
|
176
|
+
);
|
|
177
|
+
if (report.truncation.truncated)
|
|
178
|
+
line(ctx.io, "Output was truncated; inspect the JSON counts and limits.");
|
|
179
|
+
for (const limitation of report.limitations) line(ctx.io, "Limit: " + limitation);
|
|
180
|
+
}
|
|
181
|
+
return report.freshness.status === "stale" ? EXIT.environment : EXIT.ok;
|
|
182
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Memory-bounded projection of one file's direct edges.
|
|
3
|
+
*
|
|
4
|
+
* Persisted snapshots already keep their edges in canonical order. Iterating
|
|
5
|
+
* that snapshot directly avoids materialising the complete high-degree result
|
|
6
|
+
* returned by `RestoredFileGraph.edgesFrom` immediately before JSON encoding.
|
|
7
|
+
* We still count every matching edge so the visible omission count is exact.
|
|
8
|
+
*/
|
|
9
|
+
export function boundDirectEdges<T extends { readonly fromFileId: string }>(
|
|
10
|
+
candidates: Iterable<T>,
|
|
11
|
+
fromFileId: string,
|
|
12
|
+
maxEdges: number,
|
|
13
|
+
): { edges: T[]; truncated: boolean; omittedCount: number } {
|
|
14
|
+
const edges: T[] = [];
|
|
15
|
+
let matchingCount = 0;
|
|
16
|
+
|
|
17
|
+
for (const edge of candidates) {
|
|
18
|
+
if (edge.fromFileId !== fromFileId) continue;
|
|
19
|
+
matchingCount += 1;
|
|
20
|
+
if (edges.length < maxEdges) edges.push(edge);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
const omittedCount = matchingCount - edges.length;
|
|
24
|
+
return { edges, truncated: omittedCount > 0, omittedCount };
|
|
25
|
+
}
|