@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,270 @@
|
|
|
1
|
+
import { constants } from "node:fs";
|
|
2
|
+
import { lstat, mkdir, open, realpath, rm, rmdir, stat } from "node:fs/promises";
|
|
3
|
+
import path from "node:path";
|
|
4
|
+
|
|
5
|
+
import { analyzeProductAlignment } from "@untangle-code/core";
|
|
6
|
+
import { canonicalJson, sha256Hex, type ProductAlignmentReportV1 } from "@untangle-code/domain";
|
|
7
|
+
import { discoverFiles } from "@untangle-code/scanner";
|
|
8
|
+
import { NodeFileSystem } from "@untangle-code/scanner/node-fs";
|
|
9
|
+
|
|
10
|
+
import { enumFlag, integerFlag, stringFlag, type ParsedArgs } from "../../cli/args.js";
|
|
11
|
+
import type { CommandContext } from "../../cli/command.js";
|
|
12
|
+
import { UsageError } from "../../cli/exit.js";
|
|
13
|
+
import { line, note } from "../../cli/io.js";
|
|
14
|
+
|
|
15
|
+
import { createFeatureMapHtml } from "./feature-html.js";
|
|
16
|
+
import {
|
|
17
|
+
buildFeatureMapGraph,
|
|
18
|
+
featureMapLimits,
|
|
19
|
+
type FeatureMapGraphV1,
|
|
20
|
+
type FeatureMapLimitsV1,
|
|
21
|
+
} from "./feature-model.js";
|
|
22
|
+
|
|
23
|
+
export interface FeatureMapOptionsV1 extends FeatureMapLimitsV1 {
|
|
24
|
+
root: string;
|
|
25
|
+
manifestPath?: string;
|
|
26
|
+
testEvidencePath?: string;
|
|
27
|
+
signal?: AbortSignal;
|
|
28
|
+
}
|
|
29
|
+
export interface FeatureMapWriteResultV1 {
|
|
30
|
+
schemaVersion: 1;
|
|
31
|
+
kind: "feature_map_artifact";
|
|
32
|
+
htmlPath: string;
|
|
33
|
+
jsonPath: string;
|
|
34
|
+
sha256: { html: string; json: string };
|
|
35
|
+
summary: FeatureMapGraphV1["summary"];
|
|
36
|
+
graph: FeatureMapGraphV1;
|
|
37
|
+
report: ProductAlignmentReportV1;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/** Reuse the safe scanner for a declared-feature-free census; never invent ownership or metrics. */
|
|
41
|
+
async function unassignedCensus(root: string, signal?: AbortSignal): Promise<string[]> {
|
|
42
|
+
const paths: string[] = [];
|
|
43
|
+
for await (const file of discoverFiles({
|
|
44
|
+
fs: new NodeFileSystem(),
|
|
45
|
+
roots: [root],
|
|
46
|
+
repoRoot: root,
|
|
47
|
+
ignore: {
|
|
48
|
+
additionalDefaultExcludes: [
|
|
49
|
+
"/.untangle",
|
|
50
|
+
"/untangle.toml",
|
|
51
|
+
"/untangle.toml.untangle-init-tmp",
|
|
52
|
+
],
|
|
53
|
+
},
|
|
54
|
+
...(signal === undefined ? {} : { signal }),
|
|
55
|
+
})) {
|
|
56
|
+
signal?.throwIfAborted();
|
|
57
|
+
if (
|
|
58
|
+
file.languageId === "unknown" ||
|
|
59
|
+
file.languageId === "markdown" ||
|
|
60
|
+
/\.(?:json|toml|ya?ml|lock)$/iu.test(file.relativePath)
|
|
61
|
+
)
|
|
62
|
+
continue;
|
|
63
|
+
paths.push(file.relativePath);
|
|
64
|
+
if (paths.length >= 50_000) break;
|
|
65
|
+
}
|
|
66
|
+
return paths;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
interface CreatedDirectory {
|
|
70
|
+
path: string;
|
|
71
|
+
ino: number;
|
|
72
|
+
dev: number;
|
|
73
|
+
}
|
|
74
|
+
async function metadataDirectory(
|
|
75
|
+
root: string,
|
|
76
|
+
created: CreatedDirectory[],
|
|
77
|
+
signal?: AbortSignal,
|
|
78
|
+
): Promise<string> {
|
|
79
|
+
let directory = root;
|
|
80
|
+
for (const component of [".untangle", "feature-map"]) {
|
|
81
|
+
signal?.throwIfAborted();
|
|
82
|
+
directory = path.join(directory, component);
|
|
83
|
+
let made = true;
|
|
84
|
+
await mkdir(directory, { mode: 0o700 }).catch((error: unknown) => {
|
|
85
|
+
if ((error as NodeJS.ErrnoException).code !== "EEXIST") throw error;
|
|
86
|
+
made = false;
|
|
87
|
+
});
|
|
88
|
+
const info = await lstat(directory);
|
|
89
|
+
if (!info.isDirectory() || info.isSymbolicLink() || (await realpath(directory)) !== directory)
|
|
90
|
+
throw new Error(
|
|
91
|
+
"Feature-map metadata directories must be physical in-project directories, not symlinks.",
|
|
92
|
+
);
|
|
93
|
+
if (made) created.push({ path: directory, ino: info.ino, dev: info.dev });
|
|
94
|
+
}
|
|
95
|
+
return directory;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
async function removeEmptyOwnDirectories(created: CreatedDirectory[]): Promise<void> {
|
|
99
|
+
for (const directory of [...created].reverse()) {
|
|
100
|
+
const current = await lstat(directory.path).catch(() => null);
|
|
101
|
+
if (current?.ino === directory.ino && current.dev === directory.dev && current.isDirectory())
|
|
102
|
+
await rmdir(directory.path).catch((error: unknown) => {
|
|
103
|
+
if (
|
|
104
|
+
!["ENOENT", "ENOTEMPTY", "EEXIST"].includes((error as NodeJS.ErrnoException).code ?? "")
|
|
105
|
+
)
|
|
106
|
+
throw error;
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
async function readRegular(filePath: string): Promise<string> {
|
|
112
|
+
const handle = await open(filePath, constants.O_RDONLY | constants.O_NOFOLLOW);
|
|
113
|
+
try {
|
|
114
|
+
if (!(await handle.stat()).isFile())
|
|
115
|
+
throw new Error("Feature-map artifact must be a regular file.");
|
|
116
|
+
return await handle.readFile("utf8");
|
|
117
|
+
} finally {
|
|
118
|
+
await handle.close();
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
/** Exclusive creation preserves foreign bytes; interrupted own partial files are removed. */
|
|
123
|
+
async function preserve(filePath: string, content: string, signal?: AbortSignal): Promise<boolean> {
|
|
124
|
+
signal?.throwIfAborted();
|
|
125
|
+
const handle = await open(
|
|
126
|
+
filePath,
|
|
127
|
+
constants.O_WRONLY | constants.O_CREAT | constants.O_EXCL | constants.O_NOFOLLOW,
|
|
128
|
+
0o600,
|
|
129
|
+
).catch(async (error: unknown) => {
|
|
130
|
+
if ((error as NodeJS.ErrnoException).code !== "EEXIST") throw error;
|
|
131
|
+
if ((await readRegular(filePath)) !== content)
|
|
132
|
+
throw new Error("Existing feature-map artifact differs; refusing to overwrite it.");
|
|
133
|
+
return null;
|
|
134
|
+
});
|
|
135
|
+
if (handle === null) return false;
|
|
136
|
+
try {
|
|
137
|
+
signal?.throwIfAborted();
|
|
138
|
+
await handle.writeFile(content, "utf8");
|
|
139
|
+
await handle.sync();
|
|
140
|
+
signal?.throwIfAborted();
|
|
141
|
+
} catch (error) {
|
|
142
|
+
const identity = await handle.stat();
|
|
143
|
+
const observed = await lstat(filePath).catch(() => null);
|
|
144
|
+
if (observed?.ino === identity.ino && observed.dev === identity.dev) await rm(filePath);
|
|
145
|
+
throw error;
|
|
146
|
+
} finally {
|
|
147
|
+
await handle.close();
|
|
148
|
+
}
|
|
149
|
+
return true;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
/** Builds an index-free, source-bound artifact without executing tests or opening a browser. */
|
|
153
|
+
export async function writeFeatureMap(
|
|
154
|
+
options: FeatureMapOptionsV1,
|
|
155
|
+
deps: { analyze?: typeof analyzeProductAlignment } = {},
|
|
156
|
+
): Promise<FeatureMapWriteResultV1> {
|
|
157
|
+
options.signal?.throwIfAborted();
|
|
158
|
+
const limits = featureMapLimits(options);
|
|
159
|
+
const root = await realpath(path.resolve(options.root));
|
|
160
|
+
if (!(await stat(root)).isDirectory())
|
|
161
|
+
throw new TypeError("Feature-map root must be a directory.");
|
|
162
|
+
// Own metadata exists before the census, so its excluded-directory event is
|
|
163
|
+
// stable on the second run; every measurement and source digest remains raw.
|
|
164
|
+
const createdDirectories: CreatedDirectory[] = [];
|
|
165
|
+
try {
|
|
166
|
+
const directory = await metadataDirectory(root, createdDirectories, options.signal);
|
|
167
|
+
const report = await (deps.analyze ?? analyzeProductAlignment)({
|
|
168
|
+
root,
|
|
169
|
+
...(options.manifestPath === undefined
|
|
170
|
+
? {}
|
|
171
|
+
: { manifestPath: path.resolve(root, options.manifestPath) }),
|
|
172
|
+
...(options.testEvidencePath === undefined
|
|
173
|
+
? {}
|
|
174
|
+
: { testEvidencePath: path.resolve(root, options.testEvidencePath) }),
|
|
175
|
+
...(options.signal === undefined ? {} : { signal: options.signal }),
|
|
176
|
+
});
|
|
177
|
+
options.signal?.throwIfAborted();
|
|
178
|
+
const unassigned =
|
|
179
|
+
report.status === "needs_manifest" ? await unassignedCensus(root, options.signal) : [];
|
|
180
|
+
if (unassigned.length > 0) {
|
|
181
|
+
const current = await (deps.analyze ?? analyzeProductAlignment)({
|
|
182
|
+
root,
|
|
183
|
+
...(options.manifestPath === undefined
|
|
184
|
+
? {}
|
|
185
|
+
: { manifestPath: path.resolve(root, options.manifestPath) }),
|
|
186
|
+
...(options.signal === undefined ? {} : { signal: options.signal }),
|
|
187
|
+
});
|
|
188
|
+
if (current.sourceTreeDigest !== report.sourceTreeDigest)
|
|
189
|
+
throw new Error(
|
|
190
|
+
"Project sources changed while collecting unassigned file paths; regenerate the feature map.",
|
|
191
|
+
);
|
|
192
|
+
}
|
|
193
|
+
const graph = buildFeatureMapGraph(report, limits, unassigned);
|
|
194
|
+
const json =
|
|
195
|
+
JSON.stringify({ schemaVersion: 1, kind: "feature_map_snapshot", graph, report }, null, 2) +
|
|
196
|
+
"\n";
|
|
197
|
+
const html = createFeatureMapHtml(graph);
|
|
198
|
+
const digest = sha256Hex(canonicalJson({ json, html }));
|
|
199
|
+
const prefix = path.join(directory, `feature-map-${digest.slice(0, 16)}`);
|
|
200
|
+
const jsonPath = `${prefix}.json`,
|
|
201
|
+
htmlPath = `${prefix}.html`;
|
|
202
|
+
let createdJson = false;
|
|
203
|
+
let createdHtml = false;
|
|
204
|
+
try {
|
|
205
|
+
createdJson = await preserve(jsonPath, json, options.signal);
|
|
206
|
+
createdHtml = await preserve(htmlPath, html, options.signal);
|
|
207
|
+
options.signal?.throwIfAborted();
|
|
208
|
+
} catch (error) {
|
|
209
|
+
if (createdHtml && (await readRegular(htmlPath).catch(() => null)) === html)
|
|
210
|
+
await rm(htmlPath);
|
|
211
|
+
if (createdJson && (await readRegular(jsonPath).catch(() => null)) === json)
|
|
212
|
+
await rm(jsonPath);
|
|
213
|
+
throw error;
|
|
214
|
+
}
|
|
215
|
+
return {
|
|
216
|
+
schemaVersion: 1,
|
|
217
|
+
kind: "feature_map_artifact",
|
|
218
|
+
htmlPath,
|
|
219
|
+
jsonPath,
|
|
220
|
+
sha256: { html: sha256Hex(html), json: sha256Hex(json) },
|
|
221
|
+
summary: graph.summary,
|
|
222
|
+
graph,
|
|
223
|
+
report,
|
|
224
|
+
};
|
|
225
|
+
} catch (error) {
|
|
226
|
+
await removeEmptyOwnDirectories(createdDirectories);
|
|
227
|
+
throw error;
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
/** `graph features`: deliberately bypasses stored-graph loading and all service probes. */
|
|
232
|
+
export async function runFeatureMap(ctx: CommandContext, args: ParsedArgs): Promise<number> {
|
|
233
|
+
if (args.positionals.length !== 0)
|
|
234
|
+
throw new UsageError("graph features accepts no additional positional arguments.");
|
|
235
|
+
const format = enumFlag(args, "format", ["text", "json"] as const, "text");
|
|
236
|
+
const root = path.resolve(ctx.cwd, stringFlag(args, "root") ?? ".");
|
|
237
|
+
const manifestPath = stringFlag(args, "feature-map");
|
|
238
|
+
const testEvidencePath = stringFlag(args, "test-evidence");
|
|
239
|
+
const maxNodes = integerFlag(args, "max-nodes", 500),
|
|
240
|
+
maxEdges = integerFlag(args, "max-edges", 2_000);
|
|
241
|
+
try {
|
|
242
|
+
featureMapLimits({ maxNodes, maxEdges });
|
|
243
|
+
} catch (error) {
|
|
244
|
+
throw new UsageError((error as Error).message);
|
|
245
|
+
}
|
|
246
|
+
const result = await writeFeatureMap({
|
|
247
|
+
root,
|
|
248
|
+
maxNodes,
|
|
249
|
+
maxEdges,
|
|
250
|
+
signal: ctx.signal,
|
|
251
|
+
...(manifestPath === undefined ? {} : { manifestPath }),
|
|
252
|
+
...(testEvidencePath === undefined ? {} : { testEvidencePath }),
|
|
253
|
+
});
|
|
254
|
+
if (format === "json") line(ctx.io, JSON.stringify(result, null, 2));
|
|
255
|
+
else {
|
|
256
|
+
line(ctx.io, result.htmlPath);
|
|
257
|
+
note(
|
|
258
|
+
ctx.io,
|
|
259
|
+
`Feature map: ${result.summary.features} declared features, ${result.summary.shownNodes}/${result.summary.totalNodes} nodes, ${result.summary.shownEdges}/${result.summary.totalEdges} edges; ${result.summary.status}.`,
|
|
260
|
+
);
|
|
261
|
+
note(ctx.io, `Complete report: ${result.jsonPath}`);
|
|
262
|
+
note(
|
|
263
|
+
ctx.io,
|
|
264
|
+
"Open the local HTML file in a browser. No index, service, network request or test execution is required.",
|
|
265
|
+
);
|
|
266
|
+
if (result.summary.truncated)
|
|
267
|
+
note(ctx.io, "Bounded diagram; complete feature metrics remain in the JSON report.");
|
|
268
|
+
}
|
|
269
|
+
return 0;
|
|
270
|
+
}
|
|
@@ -0,0 +1,234 @@
|
|
|
1
|
+
import {
|
|
2
|
+
canonicalJson,
|
|
3
|
+
compareCodepoints,
|
|
4
|
+
uuidv5,
|
|
5
|
+
type ProductAlignmentReportV1,
|
|
6
|
+
} from "@untangle-code/domain";
|
|
7
|
+
|
|
8
|
+
export type FeatureMapNodeKind = "feature" | "code" | "test" | "owner" | "intent" | "unmapped";
|
|
9
|
+
export type FeatureMapEdgeKind = "code" | "test" | "ownership" | "intent" | "dependency";
|
|
10
|
+
export interface FeatureMapNodeV1 {
|
|
11
|
+
id: string;
|
|
12
|
+
kind: FeatureMapNodeKind;
|
|
13
|
+
label: string;
|
|
14
|
+
path?: string;
|
|
15
|
+
status: string;
|
|
16
|
+
cognitive?: number;
|
|
17
|
+
details: Record<string, unknown>;
|
|
18
|
+
}
|
|
19
|
+
export interface FeatureMapEdgeV1 {
|
|
20
|
+
id: string;
|
|
21
|
+
from: string;
|
|
22
|
+
to: string;
|
|
23
|
+
kind: FeatureMapEdgeKind;
|
|
24
|
+
}
|
|
25
|
+
export interface FeatureMapSummaryV1 {
|
|
26
|
+
status: ProductAlignmentReportV1["status"];
|
|
27
|
+
features: number;
|
|
28
|
+
shownNodes: number;
|
|
29
|
+
totalNodes: number;
|
|
30
|
+
shownEdges: number;
|
|
31
|
+
totalEdges: number;
|
|
32
|
+
truncated: boolean;
|
|
33
|
+
mappedCodeFiles: number;
|
|
34
|
+
unmappedCodeFiles: number;
|
|
35
|
+
inventoryFiles: number;
|
|
36
|
+
}
|
|
37
|
+
export interface FeatureMapGraphV1 {
|
|
38
|
+
schemaVersion: 1;
|
|
39
|
+
sourceTreeDigest: string;
|
|
40
|
+
nodes: FeatureMapNodeV1[];
|
|
41
|
+
edges: FeatureMapEdgeV1[];
|
|
42
|
+
summary: FeatureMapSummaryV1;
|
|
43
|
+
limits: { maxNodes: number; maxEdges: number };
|
|
44
|
+
limitations: string[];
|
|
45
|
+
issues: string[];
|
|
46
|
+
dependencyCycles: string[][];
|
|
47
|
+
}
|
|
48
|
+
export interface FeatureMapLimitsV1 {
|
|
49
|
+
maxNodes?: number;
|
|
50
|
+
maxEdges?: number;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export function featureMapLimits(input: FeatureMapLimitsV1): {
|
|
54
|
+
maxNodes: number;
|
|
55
|
+
maxEdges: number;
|
|
56
|
+
} {
|
|
57
|
+
const maxNodes = input.maxNodes ?? 500;
|
|
58
|
+
const maxEdges = input.maxEdges ?? 2_000;
|
|
59
|
+
if (!Number.isInteger(maxNodes) || maxNodes < 1 || maxNodes > 2_000)
|
|
60
|
+
throw new RangeError("maxNodes must be an integer between 1 and 2000.");
|
|
61
|
+
if (!Number.isInteger(maxEdges) || maxEdges < 1 || maxEdges > 10_000)
|
|
62
|
+
throw new RangeError("maxEdges must be an integer between 1 and 10000.");
|
|
63
|
+
return { maxNodes, maxEdges };
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
function identity(kind: string, key: string): string {
|
|
67
|
+
return uuidv5(canonicalJson({ surface: "feature-map-v1", kind, key }));
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/** Relations are declarations/evidence, never inferred semantic or runtime calls. */
|
|
71
|
+
export function buildFeatureMapGraph(
|
|
72
|
+
report: ProductAlignmentReportV1,
|
|
73
|
+
input: FeatureMapLimitsV1 = {},
|
|
74
|
+
unassignedPaths: readonly string[] = [],
|
|
75
|
+
): FeatureMapGraphV1 {
|
|
76
|
+
const limits = featureMapLimits(input);
|
|
77
|
+
const nodes = new Map<string, FeatureMapNodeV1>();
|
|
78
|
+
const edges = new Map<string, FeatureMapEdgeV1>();
|
|
79
|
+
const addNode = (
|
|
80
|
+
kind: FeatureMapNodeKind,
|
|
81
|
+
key: string,
|
|
82
|
+
data: Omit<FeatureMapNodeV1, "kind" | "id">,
|
|
83
|
+
): string => {
|
|
84
|
+
const id = identity(kind === "test" ? "code" : kind, key);
|
|
85
|
+
const existing = nodes.get(id);
|
|
86
|
+
// A file selected as both code and test keeps one identity and both role facts.
|
|
87
|
+
if (existing !== undefined && (kind === "code" || kind === "test")) {
|
|
88
|
+
const roles = new Set([...(existing.details["roles"] as string[]), kind]);
|
|
89
|
+
existing.details["roles"] = [...roles].sort(compareCodepoints);
|
|
90
|
+
} else if (existing === undefined) nodes.set(id, { id, kind, ...data });
|
|
91
|
+
return id;
|
|
92
|
+
};
|
|
93
|
+
const addEdge = (from: string, to: string, kind: FeatureMapEdgeKind): void => {
|
|
94
|
+
const id = identity("edge", canonicalJson({ from, to, kind }));
|
|
95
|
+
edges.set(id, { id, from, to, kind });
|
|
96
|
+
};
|
|
97
|
+
const features = [...report.features].sort((a, b) => compareCodepoints(a.id, b.id));
|
|
98
|
+
for (const feature of features) {
|
|
99
|
+
addNode("feature", feature.id, {
|
|
100
|
+
label: feature.title,
|
|
101
|
+
status: feature.status,
|
|
102
|
+
...(feature.code.metrics === null
|
|
103
|
+
? {}
|
|
104
|
+
: { cognitive: feature.code.metrics.cognitive.execution_unit }),
|
|
105
|
+
details: {
|
|
106
|
+
featureId: feature.id,
|
|
107
|
+
stage: feature.stage,
|
|
108
|
+
review: feature.review,
|
|
109
|
+
codeComplete: feature.code.complete,
|
|
110
|
+
testComplete: feature.tests.complete,
|
|
111
|
+
metrics: feature.code.metrics,
|
|
112
|
+
testMetrics: feature.tests.metrics,
|
|
113
|
+
testEvidence: feature.testEvidence,
|
|
114
|
+
dimensions: feature.dimensions,
|
|
115
|
+
criteria: feature.criteria,
|
|
116
|
+
hotspots: feature.code.hotspots,
|
|
117
|
+
agentHints: feature.agentHints,
|
|
118
|
+
issues: feature.issues,
|
|
119
|
+
},
|
|
120
|
+
});
|
|
121
|
+
}
|
|
122
|
+
for (const feature of features) {
|
|
123
|
+
const featureId = identity("feature", feature.id);
|
|
124
|
+
for (const owner of feature.ownership) {
|
|
125
|
+
const ownerId = addNode("owner", owner.id, {
|
|
126
|
+
label: owner.label ?? owner.id,
|
|
127
|
+
status: owner.status,
|
|
128
|
+
details: {
|
|
129
|
+
ownerId: owner.id,
|
|
130
|
+
authority: report.ownershipAuthority,
|
|
131
|
+
sources: owner.sources,
|
|
132
|
+
},
|
|
133
|
+
});
|
|
134
|
+
addEdge(featureId, ownerId, "ownership");
|
|
135
|
+
}
|
|
136
|
+
for (const intent of feature.intent) {
|
|
137
|
+
const intentId = addNode(
|
|
138
|
+
"intent",
|
|
139
|
+
canonicalJson({ path: intent.path, heading: intent.heading }),
|
|
140
|
+
{
|
|
141
|
+
label: intent.heading || intent.path,
|
|
142
|
+
path: intent.path,
|
|
143
|
+
status: intent.status,
|
|
144
|
+
details: {
|
|
145
|
+
role: intent.role,
|
|
146
|
+
heading: intent.heading,
|
|
147
|
+
contentHash: intent.contentHash,
|
|
148
|
+
startLine: intent.startLine,
|
|
149
|
+
endLine: intent.endLine,
|
|
150
|
+
},
|
|
151
|
+
},
|
|
152
|
+
);
|
|
153
|
+
addEdge(featureId, intentId, "intent");
|
|
154
|
+
}
|
|
155
|
+
for (const role of ["code", "test"] as const) {
|
|
156
|
+
const selection = role === "code" ? feature.code : feature.tests;
|
|
157
|
+
for (const file of selection.files) {
|
|
158
|
+
const fileId = addNode(role, file.path, {
|
|
159
|
+
label: file.path,
|
|
160
|
+
path: file.path,
|
|
161
|
+
status: file.status,
|
|
162
|
+
details: {
|
|
163
|
+
roles: [role],
|
|
164
|
+
contentHash: file.contentHash,
|
|
165
|
+
sharedFeatures:
|
|
166
|
+
report.coverage.sharedFiles.find((shared) => shared.path === file.path)?.featureIds ??
|
|
167
|
+
[],
|
|
168
|
+
},
|
|
169
|
+
});
|
|
170
|
+
addEdge(featureId, fileId, role);
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
for (const dependency of feature.dependsOn) {
|
|
174
|
+
const target = identity("feature", dependency);
|
|
175
|
+
if (nodes.has(target)) addEdge(featureId, target, "dependency");
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
const unmapped = [...new Set([...report.coverage.unmappedCodeFiles, ...unassignedPaths])].sort(
|
|
179
|
+
compareCodepoints,
|
|
180
|
+
);
|
|
181
|
+
for (const filePath of unmapped) {
|
|
182
|
+
// The fallback census is not an AST measurement and does not imply a feature.
|
|
183
|
+
if (nodes.has(identity("code", filePath))) continue;
|
|
184
|
+
addNode("unmapped", filePath, {
|
|
185
|
+
label: filePath,
|
|
186
|
+
path: filePath,
|
|
187
|
+
status: "unmapped",
|
|
188
|
+
details: { featureAssignment: "none", measurement: "not_provided_by_feature_report" },
|
|
189
|
+
});
|
|
190
|
+
}
|
|
191
|
+
const allNodes = [...nodes.values()];
|
|
192
|
+
const shownNodes = allNodes.slice(0, limits.maxNodes);
|
|
193
|
+
const visible = new Set(shownNodes.map((node) => node.id));
|
|
194
|
+
const allEdges = [...edges.values()].sort((a, b) => compareCodepoints(a.id, b.id));
|
|
195
|
+
const shownEdges = allEdges
|
|
196
|
+
.filter((edge) => visible.has(edge.from) && visible.has(edge.to))
|
|
197
|
+
.slice(0, limits.maxEdges);
|
|
198
|
+
return {
|
|
199
|
+
schemaVersion: 1,
|
|
200
|
+
sourceTreeDigest: report.sourceTreeDigest,
|
|
201
|
+
nodes: shownNodes,
|
|
202
|
+
edges: shownEdges,
|
|
203
|
+
summary: {
|
|
204
|
+
status: report.status,
|
|
205
|
+
features: report.features.length,
|
|
206
|
+
shownNodes: shownNodes.length,
|
|
207
|
+
totalNodes: allNodes.length,
|
|
208
|
+
shownEdges: shownEdges.length,
|
|
209
|
+
totalEdges: allEdges.length,
|
|
210
|
+
truncated:
|
|
211
|
+
shownNodes.length < allNodes.length ||
|
|
212
|
+
shownEdges.length < allEdges.length ||
|
|
213
|
+
report.inventory.truncated,
|
|
214
|
+
mappedCodeFiles: report.coverage.mappedCodeFiles,
|
|
215
|
+
unmappedCodeFiles: Math.max(report.coverage.unmappedCodeFileCount, unmapped.length),
|
|
216
|
+
inventoryFiles: report.inventory.files,
|
|
217
|
+
},
|
|
218
|
+
limits,
|
|
219
|
+
issues: report.issues,
|
|
220
|
+
dependencyCycles: report.dependencyCycles,
|
|
221
|
+
limitations: [
|
|
222
|
+
...report.limitations,
|
|
223
|
+
"Only declared feature, code/test, intent and ownership relations are drawn. Feature dependency edges are not code imports or runtime calls.",
|
|
224
|
+
"Node size represents complete feature cognitive execution_unit complexity only when measured. File sizes do not claim file complexity.",
|
|
225
|
+
"The diagram is a bounded source snapshot. Filtered or omitted nodes never reduce the complete feature metrics in the report.",
|
|
226
|
+
"Spatial positions, depth and thread curvature are visualization choices, not semantic similarity, coupling scores or additional relationships.",
|
|
227
|
+
...(unassignedPaths.length === 0
|
|
228
|
+
? []
|
|
229
|
+
: [
|
|
230
|
+
"Unassigned paths come from an accepted scanner census; they carry no inferred feature, owner or AST metric.",
|
|
231
|
+
]),
|
|
232
|
+
],
|
|
233
|
+
};
|
|
234
|
+
}
|
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
import type { FeaturePoint3D } from "./feature-3d.js";
|
|
2
|
+
|
|
3
|
+
export interface FeatureUntangleState {
|
|
4
|
+
phase: "idle" | "running" | "paused" | "complete";
|
|
5
|
+
target: "wool" | "clusters";
|
|
6
|
+
progress: number;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export interface FeatureUntangleTransition {
|
|
10
|
+
from: Readonly<Record<string, FeaturePoint3D>>;
|
|
11
|
+
to: Readonly<Record<string, FeaturePoint3D>>;
|
|
12
|
+
fromAmount: number;
|
|
13
|
+
toAmount: number;
|
|
14
|
+
target: "wool" | "clusters";
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export interface FeatureUntangleMotionOptions {
|
|
18
|
+
requestFrame?: (callback: (timestamp: number) => void) => number;
|
|
19
|
+
cancelFrame?: (id: number) => void;
|
|
20
|
+
reducedMotion: () => boolean;
|
|
21
|
+
visible: () => boolean;
|
|
22
|
+
onFrame: (positions: Record<string, FeaturePoint3D>, clusterAmount: number) => void;
|
|
23
|
+
onState: (state: FeatureUntangleState) => void;
|
|
24
|
+
durationMs?: number;
|
|
25
|
+
frameIntervalMs?: number;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/** Self-contained for the offline viewer's CSP-hashed serialized runtime. */
|
|
29
|
+
export function createFeatureUntangleMotion(options: FeatureUntangleMotionOptions) {
|
|
30
|
+
const duration = Math.max(1, options.durationMs ?? 2600);
|
|
31
|
+
const interval = Math.max(33, Math.min(160, options.frameIntervalMs ?? 33));
|
|
32
|
+
if (!Number.isFinite(duration) || !Number.isFinite(interval))
|
|
33
|
+
throw new RangeError("Untangling requires bounded timing.");
|
|
34
|
+
let phase: FeatureUntangleState["phase"] = "idle";
|
|
35
|
+
let target: FeatureUntangleState["target"] = "clusters";
|
|
36
|
+
let transition: FeatureUntangleTransition | null = null;
|
|
37
|
+
let elapsed = 0;
|
|
38
|
+
let lastTimestamp: number | null = null;
|
|
39
|
+
let lastPaint = -Infinity;
|
|
40
|
+
let frame: number | null = null;
|
|
41
|
+
let generation = 0;
|
|
42
|
+
|
|
43
|
+
function getState(): FeatureUntangleState {
|
|
44
|
+
return { phase, target, progress: Math.min(1, elapsed / duration) };
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
function announce() {
|
|
48
|
+
options.onState(getState());
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
function clearFrame() {
|
|
52
|
+
generation += 1;
|
|
53
|
+
if (frame !== null) options.cancelFrame?.(frame);
|
|
54
|
+
frame = null;
|
|
55
|
+
lastTimestamp = null;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
function render(progress: number) {
|
|
59
|
+
if (!transition) return;
|
|
60
|
+
const eased = 1 - (1 - progress) ** 3;
|
|
61
|
+
const positions: Record<string, FeaturePoint3D> = Object.create(null) as Record<
|
|
62
|
+
string,
|
|
63
|
+
FeaturePoint3D
|
|
64
|
+
>;
|
|
65
|
+
for (const id of Object.keys(transition.from)) {
|
|
66
|
+
const from = transition.from[id]!;
|
|
67
|
+
const to = transition.to[id]!;
|
|
68
|
+
positions[id] =
|
|
69
|
+
progress === 1
|
|
70
|
+
? { ...to }
|
|
71
|
+
: progress === 0
|
|
72
|
+
? { ...from }
|
|
73
|
+
: {
|
|
74
|
+
x: from.x + (to.x - from.x) * eased,
|
|
75
|
+
y: from.y + (to.y - from.y) * eased,
|
|
76
|
+
z: from.z + (to.z - from.z) * eased,
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
try {
|
|
80
|
+
options.onFrame(
|
|
81
|
+
positions,
|
|
82
|
+
transition.fromAmount + (transition.toAmount - transition.fromAmount) * eased,
|
|
83
|
+
);
|
|
84
|
+
} catch (error) {
|
|
85
|
+
clearFrame();
|
|
86
|
+
phase = "paused";
|
|
87
|
+
announce();
|
|
88
|
+
throw error;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
function schedule() {
|
|
93
|
+
if (phase !== "running" || frame !== null || !options.requestFrame) return;
|
|
94
|
+
const token = generation;
|
|
95
|
+
frame = options.requestFrame((timestamp) => {
|
|
96
|
+
if (token !== generation || phase !== "running") return;
|
|
97
|
+
frame = null;
|
|
98
|
+
if (options.reducedMotion()) {
|
|
99
|
+
finish();
|
|
100
|
+
return;
|
|
101
|
+
}
|
|
102
|
+
if (!options.visible()) {
|
|
103
|
+
pause();
|
|
104
|
+
return;
|
|
105
|
+
}
|
|
106
|
+
if (lastTimestamp !== null) elapsed += Math.max(0, timestamp - lastTimestamp);
|
|
107
|
+
lastTimestamp = timestamp;
|
|
108
|
+
if (elapsed >= duration) {
|
|
109
|
+
finish();
|
|
110
|
+
return;
|
|
111
|
+
}
|
|
112
|
+
if (timestamp - lastPaint >= interval) {
|
|
113
|
+
render(elapsed / duration);
|
|
114
|
+
lastPaint = timestamp;
|
|
115
|
+
}
|
|
116
|
+
schedule();
|
|
117
|
+
});
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
function finish() {
|
|
121
|
+
if (!transition || phase === "complete") return;
|
|
122
|
+
clearFrame();
|
|
123
|
+
elapsed = duration;
|
|
124
|
+
phase = "complete";
|
|
125
|
+
render(1);
|
|
126
|
+
announce();
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
function pause() {
|
|
130
|
+
if (phase !== "running") return;
|
|
131
|
+
clearFrame();
|
|
132
|
+
phase = "paused";
|
|
133
|
+
announce();
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
function resume() {
|
|
137
|
+
if (phase !== "paused") return;
|
|
138
|
+
if (options.reducedMotion() || !options.requestFrame) {
|
|
139
|
+
finish();
|
|
140
|
+
return;
|
|
141
|
+
}
|
|
142
|
+
if (!options.visible()) return;
|
|
143
|
+
phase = "running";
|
|
144
|
+
announce();
|
|
145
|
+
schedule();
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
function cancel() {
|
|
149
|
+
clearFrame();
|
|
150
|
+
transition = null;
|
|
151
|
+
elapsed = 0;
|
|
152
|
+
phase = "idle";
|
|
153
|
+
announce();
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
function start(input: FeatureUntangleTransition) {
|
|
157
|
+
const ids = Object.keys(input.from).sort();
|
|
158
|
+
const targets = Object.keys(input.to).sort();
|
|
159
|
+
if (ids.length !== targets.length || ids.some((id, index) => id !== targets[index]))
|
|
160
|
+
throw new Error("Untangling must preserve every node identity.");
|
|
161
|
+
for (const collection of [input.from, input.to]) {
|
|
162
|
+
for (const point of Object.values(collection)) {
|
|
163
|
+
if (![point.x, point.y, point.z].every(Number.isFinite))
|
|
164
|
+
throw new Error("Untangling requires finite coordinates.");
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
if (
|
|
168
|
+
![input.fromAmount, input.toAmount].every(
|
|
169
|
+
(value) => Number.isFinite(value) && value >= 0 && value <= 1,
|
|
170
|
+
)
|
|
171
|
+
)
|
|
172
|
+
throw new Error("Invalid clustering amount.");
|
|
173
|
+
clearFrame();
|
|
174
|
+
const copy = (points: Readonly<Record<string, FeaturePoint3D>>) =>
|
|
175
|
+
Object.fromEntries(Object.entries(points).map(([id, point]) => [id, { ...point }]));
|
|
176
|
+
transition = { ...input, from: copy(input.from), to: copy(input.to) };
|
|
177
|
+
elapsed = 0;
|
|
178
|
+
lastPaint = -Infinity;
|
|
179
|
+
target = input.target;
|
|
180
|
+
phase = "running";
|
|
181
|
+
if (ids.length === 0 || options.reducedMotion() || !options.requestFrame) {
|
|
182
|
+
finish();
|
|
183
|
+
return;
|
|
184
|
+
}
|
|
185
|
+
render(0);
|
|
186
|
+
if (!options.visible()) phase = "paused";
|
|
187
|
+
announce();
|
|
188
|
+
schedule();
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
return { start, pause, resume, finish, cancel, getState };
|
|
192
|
+
}
|