@zbigniewsobiecki/squint 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +1065 -0
- package/bin/dev.js +5 -0
- package/bin/run.js +5 -0
- package/dist/commands/_shared/db-helper.d.ts +18 -0
- package/dist/commands/_shared/db-helper.d.ts.map +1 -0
- package/dist/commands/_shared/db-helper.js +72 -0
- package/dist/commands/_shared/db-helper.js.map +1 -0
- package/dist/commands/_shared/flags.d.ts +20 -0
- package/dist/commands/_shared/flags.d.ts.map +1 -0
- package/dist/commands/_shared/flags.js +38 -0
- package/dist/commands/_shared/flags.js.map +1 -0
- package/dist/commands/_shared/index.d.ts +6 -0
- package/dist/commands/_shared/index.d.ts.map +1 -0
- package/dist/commands/_shared/index.js +6 -0
- package/dist/commands/_shared/index.js.map +1 -0
- package/dist/commands/_shared/output.d.ts +22 -0
- package/dist/commands/_shared/output.d.ts.map +1 -0
- package/dist/commands/_shared/output.js +36 -0
- package/dist/commands/_shared/output.js.map +1 -0
- package/dist/commands/_shared/source-reader.d.ts +23 -0
- package/dist/commands/_shared/source-reader.d.ts.map +1 -0
- package/dist/commands/_shared/source-reader.js +45 -0
- package/dist/commands/_shared/source-reader.js.map +1 -0
- package/dist/commands/_shared/symbol-resolver.d.ts +35 -0
- package/dist/commands/_shared/symbol-resolver.d.ts.map +1 -0
- package/dist/commands/_shared/symbol-resolver.js +102 -0
- package/dist/commands/_shared/symbol-resolver.js.map +1 -0
- package/dist/commands/browse.d.ts +13 -0
- package/dist/commands/browse.d.ts.map +1 -0
- package/dist/commands/browse.js +106 -0
- package/dist/commands/browse.js.map +1 -0
- package/dist/commands/domains/create.d.ts +15 -0
- package/dist/commands/domains/create.d.ts.map +1 -0
- package/dist/commands/domains/create.js +34 -0
- package/dist/commands/domains/create.js.map +1 -0
- package/dist/commands/domains/delete.d.ts +14 -0
- package/dist/commands/domains/delete.d.ts.map +1 -0
- package/dist/commands/domains/delete.js +41 -0
- package/dist/commands/domains/delete.js.map +1 -0
- package/dist/commands/domains/index.d.ts +2 -0
- package/dist/commands/domains/index.d.ts.map +1 -0
- package/dist/commands/domains/index.js +2 -0
- package/dist/commands/domains/index.js.map +1 -0
- package/dist/commands/domains/list.d.ts +12 -0
- package/dist/commands/domains/list.d.ts.map +1 -0
- package/dist/commands/domains/list.js +67 -0
- package/dist/commands/domains/list.js.map +1 -0
- package/dist/commands/domains/merge.d.ts +14 -0
- package/dist/commands/domains/merge.d.ts.map +1 -0
- package/dist/commands/domains/merge.js +40 -0
- package/dist/commands/domains/merge.js.map +1 -0
- package/dist/commands/domains/rename.d.ts +14 -0
- package/dist/commands/domains/rename.d.ts.map +1 -0
- package/dist/commands/domains/rename.js +33 -0
- package/dist/commands/domains/rename.js.map +1 -0
- package/dist/commands/domains/show.d.ts +14 -0
- package/dist/commands/domains/show.d.ts.map +1 -0
- package/dist/commands/domains/show.js +47 -0
- package/dist/commands/domains/show.js.map +1 -0
- package/dist/commands/domains/sync.d.ts +11 -0
- package/dist/commands/domains/sync.d.ts.map +1 -0
- package/dist/commands/domains/sync.js +33 -0
- package/dist/commands/domains/sync.js.map +1 -0
- package/dist/commands/domains/update.d.ts +14 -0
- package/dist/commands/domains/update.d.ts.map +1 -0
- package/dist/commands/domains/update.js +28 -0
- package/dist/commands/domains/update.js.map +1 -0
- package/dist/commands/features/assign.d.ts +16 -0
- package/dist/commands/features/assign.d.ts.map +1 -0
- package/dist/commands/features/assign.js +51 -0
- package/dist/commands/features/assign.js.map +1 -0
- package/dist/commands/features/create.d.ts +15 -0
- package/dist/commands/features/create.d.ts.map +1 -0
- package/dist/commands/features/create.js +30 -0
- package/dist/commands/features/create.js.map +1 -0
- package/dist/commands/features/delete.d.ts +14 -0
- package/dist/commands/features/delete.d.ts.map +1 -0
- package/dist/commands/features/delete.js +37 -0
- package/dist/commands/features/delete.js.map +1 -0
- package/dist/commands/features/generate.d.ts +34 -0
- package/dist/commands/features/generate.d.ts.map +1 -0
- package/dist/commands/features/generate.js +178 -0
- package/dist/commands/features/generate.js.map +1 -0
- package/dist/commands/features/index.d.ts +2 -0
- package/dist/commands/features/index.d.ts.map +1 -0
- package/dist/commands/features/index.js +2 -0
- package/dist/commands/features/index.js.map +1 -0
- package/dist/commands/features/list.d.ts +11 -0
- package/dist/commands/features/list.d.ts.map +1 -0
- package/dist/commands/features/list.js +45 -0
- package/dist/commands/features/list.js.map +1 -0
- package/dist/commands/features/show.d.ts +15 -0
- package/dist/commands/features/show.d.ts.map +1 -0
- package/dist/commands/features/show.js +61 -0
- package/dist/commands/features/show.js.map +1 -0
- package/dist/commands/features/unassign.d.ts +16 -0
- package/dist/commands/features/unassign.d.ts.map +1 -0
- package/dist/commands/features/unassign.js +55 -0
- package/dist/commands/features/unassign.js.map +1 -0
- package/dist/commands/features/update.d.ts +16 -0
- package/dist/commands/features/update.d.ts.map +1 -0
- package/dist/commands/features/update.js +54 -0
- package/dist/commands/features/update.js.map +1 -0
- package/dist/commands/files/imported-by.d.ts +13 -0
- package/dist/commands/files/imported-by.d.ts.map +1 -0
- package/dist/commands/files/imported-by.js +40 -0
- package/dist/commands/files/imported-by.js.map +1 -0
- package/dist/commands/files/imports.d.ts +14 -0
- package/dist/commands/files/imports.d.ts.map +1 -0
- package/dist/commands/files/imports.js +48 -0
- package/dist/commands/files/imports.js.map +1 -0
- package/dist/commands/files/index.d.ts +2 -0
- package/dist/commands/files/index.d.ts.map +1 -0
- package/dist/commands/files/index.js +2 -0
- package/dist/commands/files/index.js.map +1 -0
- package/dist/commands/files/list.d.ts +11 -0
- package/dist/commands/files/list.d.ts.map +1 -0
- package/dist/commands/files/list.js +35 -0
- package/dist/commands/files/list.js.map +1 -0
- package/dist/commands/files/orphans.d.ts +12 -0
- package/dist/commands/files/orphans.d.ts.map +1 -0
- package/dist/commands/files/orphans.js +43 -0
- package/dist/commands/files/orphans.js.map +1 -0
- package/dist/commands/files/show.d.ts +14 -0
- package/dist/commands/files/show.d.ts.map +1 -0
- package/dist/commands/files/show.js +95 -0
- package/dist/commands/files/show.js.map +1 -0
- package/dist/commands/flows/add-step.d.ts +19 -0
- package/dist/commands/flows/add-step.d.ts.map +1 -0
- package/dist/commands/flows/add-step.js +46 -0
- package/dist/commands/flows/add-step.js.map +1 -0
- package/dist/commands/flows/create.d.ts +17 -0
- package/dist/commands/flows/create.d.ts.map +1 -0
- package/dist/commands/flows/create.js +39 -0
- package/dist/commands/flows/create.js.map +1 -0
- package/dist/commands/flows/delete.d.ts +14 -0
- package/dist/commands/flows/delete.d.ts.map +1 -0
- package/dist/commands/flows/delete.js +37 -0
- package/dist/commands/flows/delete.js.map +1 -0
- package/dist/commands/flows/generate.d.ts +50 -0
- package/dist/commands/flows/generate.d.ts.map +1 -0
- package/dist/commands/flows/generate.js +438 -0
- package/dist/commands/flows/generate.js.map +1 -0
- package/dist/commands/flows/index.d.ts +2 -0
- package/dist/commands/flows/index.d.ts.map +1 -0
- package/dist/commands/flows/index.js +2 -0
- package/dist/commands/flows/index.js.map +1 -0
- package/dist/commands/flows/list.d.ts +12 -0
- package/dist/commands/flows/list.d.ts.map +1 -0
- package/dist/commands/flows/list.js +98 -0
- package/dist/commands/flows/list.js.map +1 -0
- package/dist/commands/flows/remove-step.d.ts +18 -0
- package/dist/commands/flows/remove-step.d.ts.map +1 -0
- package/dist/commands/flows/remove-step.js +41 -0
- package/dist/commands/flows/remove-step.js.map +1 -0
- package/dist/commands/flows/show.d.ts +17 -0
- package/dist/commands/flows/show.d.ts.map +1 -0
- package/dist/commands/flows/show.js +136 -0
- package/dist/commands/flows/show.js.map +1 -0
- package/dist/commands/flows/trace.d.ts +22 -0
- package/dist/commands/flows/trace.d.ts.map +1 -0
- package/dist/commands/flows/trace.js +217 -0
- package/dist/commands/flows/trace.js.map +1 -0
- package/dist/commands/flows/update.d.ts +17 -0
- package/dist/commands/flows/update.d.ts.map +1 -0
- package/dist/commands/flows/update.js +60 -0
- package/dist/commands/flows/update.js.map +1 -0
- package/dist/commands/flows/verify.d.ts +21 -0
- package/dist/commands/flows/verify.d.ts.map +1 -0
- package/dist/commands/flows/verify.js +123 -0
- package/dist/commands/flows/verify.js.map +1 -0
- package/dist/commands/gaps.d.ts +14 -0
- package/dist/commands/gaps.d.ts.map +1 -0
- package/dist/commands/gaps.js +184 -0
- package/dist/commands/gaps.js.map +1 -0
- package/dist/commands/hierarchy/index.d.ts +20 -0
- package/dist/commands/hierarchy/index.d.ts.map +1 -0
- package/dist/commands/hierarchy/index.js +344 -0
- package/dist/commands/hierarchy/index.js.map +1 -0
- package/dist/commands/ingest.d.ts +23 -0
- package/dist/commands/ingest.d.ts.map +1 -0
- package/dist/commands/ingest.js +249 -0
- package/dist/commands/ingest.js.map +1 -0
- package/dist/commands/interactions/create.d.ts +16 -0
- package/dist/commands/interactions/create.d.ts.map +1 -0
- package/dist/commands/interactions/create.js +58 -0
- package/dist/commands/interactions/create.js.map +1 -0
- package/dist/commands/interactions/delete.d.ts +16 -0
- package/dist/commands/interactions/delete.d.ts.map +1 -0
- package/dist/commands/interactions/delete.js +28 -0
- package/dist/commands/interactions/delete.js.map +1 -0
- package/dist/commands/interactions/generate.d.ts +62 -0
- package/dist/commands/interactions/generate.d.ts.map +1 -0
- package/dist/commands/interactions/generate.js +870 -0
- package/dist/commands/interactions/generate.js.map +1 -0
- package/dist/commands/interactions/index.d.ts +2 -0
- package/dist/commands/interactions/index.d.ts.map +1 -0
- package/dist/commands/interactions/index.js +2 -0
- package/dist/commands/interactions/index.js.map +1 -0
- package/dist/commands/interactions/list.d.ts +15 -0
- package/dist/commands/interactions/list.d.ts.map +1 -0
- package/dist/commands/interactions/list.js +127 -0
- package/dist/commands/interactions/list.js.map +1 -0
- package/dist/commands/interactions/show.d.ts +17 -0
- package/dist/commands/interactions/show.d.ts.map +1 -0
- package/dist/commands/interactions/show.js +80 -0
- package/dist/commands/interactions/show.js.map +1 -0
- package/dist/commands/interactions/update.d.ts +20 -0
- package/dist/commands/interactions/update.d.ts.map +1 -0
- package/dist/commands/interactions/update.js +57 -0
- package/dist/commands/interactions/update.js.map +1 -0
- package/dist/commands/interactions/validate.d.ts +12 -0
- package/dist/commands/interactions/validate.d.ts.map +1 -0
- package/dist/commands/interactions/validate.js +94 -0
- package/dist/commands/interactions/validate.js.map +1 -0
- package/dist/commands/interactions/verify.d.ts +18 -0
- package/dist/commands/interactions/verify.d.ts.map +1 -0
- package/dist/commands/interactions/verify.js +127 -0
- package/dist/commands/interactions/verify.js.map +1 -0
- package/dist/commands/llm/_shared/base-llm-command.d.ts +44 -0
- package/dist/commands/llm/_shared/base-llm-command.d.ts.map +1 -0
- package/dist/commands/llm/_shared/base-llm-command.js +73 -0
- package/dist/commands/llm/_shared/base-llm-command.js.map +1 -0
- package/dist/commands/llm/_shared/coverage.d.ts +61 -0
- package/dist/commands/llm/_shared/coverage.d.ts.map +1 -0
- package/dist/commands/llm/_shared/coverage.js +161 -0
- package/dist/commands/llm/_shared/coverage.js.map +1 -0
- package/dist/commands/llm/_shared/csv-utils.d.ts +65 -0
- package/dist/commands/llm/_shared/csv-utils.d.ts.map +1 -0
- package/dist/commands/llm/_shared/csv-utils.js +231 -0
- package/dist/commands/llm/_shared/csv-utils.js.map +1 -0
- package/dist/commands/llm/_shared/csv.d.ts +44 -0
- package/dist/commands/llm/_shared/csv.d.ts.map +1 -0
- package/dist/commands/llm/_shared/csv.js +76 -0
- package/dist/commands/llm/_shared/csv.js.map +1 -0
- package/dist/commands/llm/_shared/entity-utils.d.ts +11 -0
- package/dist/commands/llm/_shared/entity-utils.d.ts.map +1 -0
- package/dist/commands/llm/_shared/entity-utils.js +87 -0
- package/dist/commands/llm/_shared/entity-utils.js.map +1 -0
- package/dist/commands/llm/_shared/flow-csv.d.ts +74 -0
- package/dist/commands/llm/_shared/flow-csv.d.ts.map +1 -0
- package/dist/commands/llm/_shared/flow-csv.js +198 -0
- package/dist/commands/llm/_shared/flow-csv.js.map +1 -0
- package/dist/commands/llm/_shared/flow-prompts.d.ts +61 -0
- package/dist/commands/llm/_shared/flow-prompts.d.ts.map +1 -0
- package/dist/commands/llm/_shared/flow-prompts.js +281 -0
- package/dist/commands/llm/_shared/flow-prompts.js.map +1 -0
- package/dist/commands/llm/_shared/flow-validation.d.ts +69 -0
- package/dist/commands/llm/_shared/flow-validation.d.ts.map +1 -0
- package/dist/commands/llm/_shared/flow-validation.js +176 -0
- package/dist/commands/llm/_shared/flow-validation.js.map +1 -0
- package/dist/commands/llm/_shared/llm-utils.d.ts +88 -0
- package/dist/commands/llm/_shared/llm-utils.d.ts.map +1 -0
- package/dist/commands/llm/_shared/llm-utils.js +256 -0
- package/dist/commands/llm/_shared/llm-utils.js.map +1 -0
- package/dist/commands/llm/_shared/module-csv.d.ts +76 -0
- package/dist/commands/llm/_shared/module-csv.d.ts.map +1 -0
- package/dist/commands/llm/_shared/module-csv.js +196 -0
- package/dist/commands/llm/_shared/module-csv.js.map +1 -0
- package/dist/commands/llm/_shared/module-prompts.d.ts +107 -0
- package/dist/commands/llm/_shared/module-prompts.d.ts.map +1 -0
- package/dist/commands/llm/_shared/module-prompts.js +395 -0
- package/dist/commands/llm/_shared/module-prompts.js.map +1 -0
- package/dist/commands/llm/_shared/process-utils.d.ts +52 -0
- package/dist/commands/llm/_shared/process-utils.d.ts.map +1 -0
- package/dist/commands/llm/_shared/process-utils.js +214 -0
- package/dist/commands/llm/_shared/process-utils.js.map +1 -0
- package/dist/commands/llm/_shared/prompts.d.ts +132 -0
- package/dist/commands/llm/_shared/prompts.d.ts.map +1 -0
- package/dist/commands/llm/_shared/prompts.js +391 -0
- package/dist/commands/llm/_shared/prompts.js.map +1 -0
- package/dist/commands/llm/_shared/pure-check.d.ts +10 -0
- package/dist/commands/llm/_shared/pure-check.d.ts.map +1 -0
- package/dist/commands/llm/_shared/pure-check.js +449 -0
- package/dist/commands/llm/_shared/pure-check.js.map +1 -0
- package/dist/commands/llm/_shared/verify/content-verifier.d.ts +40 -0
- package/dist/commands/llm/_shared/verify/content-verifier.d.ts.map +1 -0
- package/dist/commands/llm/_shared/verify/content-verifier.js +247 -0
- package/dist/commands/llm/_shared/verify/content-verifier.js.map +1 -0
- package/dist/commands/llm/_shared/verify/coverage-checker.d.ts +34 -0
- package/dist/commands/llm/_shared/verify/coverage-checker.d.ts.map +1 -0
- package/dist/commands/llm/_shared/verify/coverage-checker.js +1096 -0
- package/dist/commands/llm/_shared/verify/coverage-checker.js.map +1 -0
- package/dist/commands/llm/_shared/verify/verify-prompts.d.ts +30 -0
- package/dist/commands/llm/_shared/verify/verify-prompts.d.ts.map +1 -0
- package/dist/commands/llm/_shared/verify/verify-prompts.js +118 -0
- package/dist/commands/llm/_shared/verify/verify-prompts.js.map +1 -0
- package/dist/commands/llm/_shared/verify/verify-types.d.ts +47 -0
- package/dist/commands/llm/_shared/verify/verify-types.d.ts.map +1 -0
- package/dist/commands/llm/_shared/verify/verify-types.js +2 -0
- package/dist/commands/llm/_shared/verify/verify-types.js.map +1 -0
- package/dist/commands/llm/annotate.d.ts +7 -0
- package/dist/commands/llm/annotate.d.ts.map +1 -0
- package/dist/commands/llm/annotate.js +11 -0
- package/dist/commands/llm/annotate.js.map +1 -0
- package/dist/commands/llm/features/feature-grouper.d.ts +31 -0
- package/dist/commands/llm/features/feature-grouper.d.ts.map +1 -0
- package/dist/commands/llm/features/feature-grouper.js +223 -0
- package/dist/commands/llm/features/feature-grouper.js.map +1 -0
- package/dist/commands/llm/features/index.d.ts +6 -0
- package/dist/commands/llm/features/index.d.ts.map +1 -0
- package/dist/commands/llm/features/index.js +6 -0
- package/dist/commands/llm/features/index.js.map +1 -0
- package/dist/commands/llm/features/types.d.ts +10 -0
- package/dist/commands/llm/features/types.d.ts.map +1 -0
- package/dist/commands/llm/features/types.js +5 -0
- package/dist/commands/llm/features/types.js.map +1 -0
- package/dist/commands/llm/features.d.ts +7 -0
- package/dist/commands/llm/features.d.ts.map +1 -0
- package/dist/commands/llm/features.js +11 -0
- package/dist/commands/llm/features.js.map +1 -0
- package/dist/commands/llm/flows/atomic-flow-builder.d.ts +51 -0
- package/dist/commands/llm/flows/atomic-flow-builder.d.ts.map +1 -0
- package/dist/commands/llm/flows/atomic-flow-builder.js +247 -0
- package/dist/commands/llm/flows/atomic-flow-builder.js.map +1 -0
- package/dist/commands/llm/flows/dedup.d.ts +18 -0
- package/dist/commands/llm/flows/dedup.d.ts.map +1 -0
- package/dist/commands/llm/flows/dedup.js +76 -0
- package/dist/commands/llm/flows/dedup.js.map +1 -0
- package/dist/commands/llm/flows/entry-point-detector.d.ts +41 -0
- package/dist/commands/llm/flows/entry-point-detector.d.ts.map +1 -0
- package/dist/commands/llm/flows/entry-point-detector.js +388 -0
- package/dist/commands/llm/flows/entry-point-detector.js.map +1 -0
- package/dist/commands/llm/flows/flow-enhancer.d.ts +21 -0
- package/dist/commands/llm/flows/flow-enhancer.d.ts.map +1 -0
- package/dist/commands/llm/flows/flow-enhancer.js +166 -0
- package/dist/commands/llm/flows/flow-enhancer.js.map +1 -0
- package/dist/commands/llm/flows/flow-tracer.d.ts +50 -0
- package/dist/commands/llm/flows/flow-tracer.d.ts.map +1 -0
- package/dist/commands/llm/flows/flow-tracer.js +271 -0
- package/dist/commands/llm/flows/flow-tracer.js.map +1 -0
- package/dist/commands/llm/flows/flow-validator.d.ts +31 -0
- package/dist/commands/llm/flows/flow-validator.d.ts.map +1 -0
- package/dist/commands/llm/flows/flow-validator.js +262 -0
- package/dist/commands/llm/flows/flow-validator.js.map +1 -0
- package/dist/commands/llm/flows/gap-flow-generator.d.ts +13 -0
- package/dist/commands/llm/flows/gap-flow-generator.d.ts.map +1 -0
- package/dist/commands/llm/flows/gap-flow-generator.js +48 -0
- package/dist/commands/llm/flows/gap-flow-generator.js.map +1 -0
- package/dist/commands/llm/flows/index.d.ts +12 -0
- package/dist/commands/llm/flows/index.d.ts.map +1 -0
- package/dist/commands/llm/flows/index.js +12 -0
- package/dist/commands/llm/flows/index.js.map +1 -0
- package/dist/commands/llm/flows/types.d.ts +87 -0
- package/dist/commands/llm/flows/types.d.ts.map +1 -0
- package/dist/commands/llm/flows/types.js +5 -0
- package/dist/commands/llm/flows/types.js.map +1 -0
- package/dist/commands/llm/flows.d.ts +7 -0
- package/dist/commands/llm/flows.d.ts.map +1 -0
- package/dist/commands/llm/flows.js +11 -0
- package/dist/commands/llm/flows.js.map +1 -0
- package/dist/commands/llm/interactions.d.ts +7 -0
- package/dist/commands/llm/interactions.d.ts.map +1 -0
- package/dist/commands/llm/interactions.js +11 -0
- package/dist/commands/llm/interactions.js.map +1 -0
- package/dist/commands/llm/modules.d.ts +7 -0
- package/dist/commands/llm/modules.d.ts.map +1 -0
- package/dist/commands/llm/modules.js +11 -0
- package/dist/commands/llm/modules.js.map +1 -0
- package/dist/commands/llm/relationships.d.ts +7 -0
- package/dist/commands/llm/relationships.d.ts.map +1 -0
- package/dist/commands/llm/relationships.js +11 -0
- package/dist/commands/llm/relationships.js.map +1 -0
- package/dist/commands/modules/assign.d.ts +14 -0
- package/dist/commands/modules/assign.d.ts.map +1 -0
- package/dist/commands/modules/assign.js +54 -0
- package/dist/commands/modules/assign.js.map +1 -0
- package/dist/commands/modules/create.d.ts +16 -0
- package/dist/commands/modules/create.d.ts.map +1 -0
- package/dist/commands/modules/create.js +37 -0
- package/dist/commands/modules/create.js.map +1 -0
- package/dist/commands/modules/delete.d.ts +14 -0
- package/dist/commands/modules/delete.d.ts.map +1 -0
- package/dist/commands/modules/delete.js +54 -0
- package/dist/commands/modules/delete.js.map +1 -0
- package/dist/commands/modules/generate.d.ts +84 -0
- package/dist/commands/modules/generate.d.ts.map +1 -0
- package/dist/commands/modules/generate.js +1234 -0
- package/dist/commands/modules/generate.js.map +1 -0
- package/dist/commands/modules/index.d.ts +2 -0
- package/dist/commands/modules/index.d.ts.map +1 -0
- package/dist/commands/modules/index.js +2 -0
- package/dist/commands/modules/index.js.map +1 -0
- package/dist/commands/modules/list.d.ts +13 -0
- package/dist/commands/modules/list.d.ts.map +1 -0
- package/dist/commands/modules/list.js +92 -0
- package/dist/commands/modules/list.js.map +1 -0
- package/dist/commands/modules/prune.d.ts +10 -0
- package/dist/commands/modules/prune.d.ts.map +1 -0
- package/dist/commands/modules/prune.js +23 -0
- package/dist/commands/modules/prune.js.map +1 -0
- package/dist/commands/modules/show.d.ts +15 -0
- package/dist/commands/modules/show.d.ts.map +1 -0
- package/dist/commands/modules/show.js +95 -0
- package/dist/commands/modules/show.js.map +1 -0
- package/dist/commands/modules/unassign.d.ts +13 -0
- package/dist/commands/modules/unassign.d.ts.map +1 -0
- package/dist/commands/modules/unassign.js +49 -0
- package/dist/commands/modules/unassign.js.map +1 -0
- package/dist/commands/modules/update.d.ts +15 -0
- package/dist/commands/modules/update.d.ts.map +1 -0
- package/dist/commands/modules/update.js +50 -0
- package/dist/commands/modules/update.js.map +1 -0
- package/dist/commands/modules/verify.d.ts +18 -0
- package/dist/commands/modules/verify.d.ts.map +1 -0
- package/dist/commands/modules/verify.js +114 -0
- package/dist/commands/modules/verify.js.map +1 -0
- package/dist/commands/overview.d.ts +12 -0
- package/dist/commands/overview.d.ts.map +1 -0
- package/dist/commands/overview.js +219 -0
- package/dist/commands/overview.js.map +1 -0
- package/dist/commands/parse.d.ts +30 -0
- package/dist/commands/parse.d.ts.map +1 -0
- package/dist/commands/parse.js +211 -0
- package/dist/commands/parse.js.map +1 -0
- package/dist/commands/process-groups/index.d.ts +2 -0
- package/dist/commands/process-groups/index.d.ts.map +1 -0
- package/dist/commands/process-groups/index.js +2 -0
- package/dist/commands/process-groups/index.js.map +1 -0
- package/dist/commands/process-groups/list.d.ts +11 -0
- package/dist/commands/process-groups/list.d.ts.map +1 -0
- package/dist/commands/process-groups/list.js +98 -0
- package/dist/commands/process-groups/list.js.map +1 -0
- package/dist/commands/relationships/annotate.d.ts +27 -0
- package/dist/commands/relationships/annotate.d.ts.map +1 -0
- package/dist/commands/relationships/annotate.js +453 -0
- package/dist/commands/relationships/annotate.js.map +1 -0
- package/dist/commands/relationships/index.d.ts +2 -0
- package/dist/commands/relationships/index.d.ts.map +1 -0
- package/dist/commands/relationships/index.js +2 -0
- package/dist/commands/relationships/index.js.map +1 -0
- package/dist/commands/relationships/list.d.ts +18 -0
- package/dist/commands/relationships/list.d.ts.map +1 -0
- package/dist/commands/relationships/list.js +147 -0
- package/dist/commands/relationships/list.js.map +1 -0
- package/dist/commands/relationships/next.d.ts +17 -0
- package/dist/commands/relationships/next.d.ts.map +1 -0
- package/dist/commands/relationships/next.js +178 -0
- package/dist/commands/relationships/next.js.map +1 -0
- package/dist/commands/relationships/set.d.ts +19 -0
- package/dist/commands/relationships/set.d.ts.map +1 -0
- package/dist/commands/relationships/set.js +65 -0
- package/dist/commands/relationships/set.js.map +1 -0
- package/dist/commands/relationships/show.d.ts +13 -0
- package/dist/commands/relationships/show.d.ts.map +1 -0
- package/dist/commands/relationships/show.js +59 -0
- package/dist/commands/relationships/show.js.map +1 -0
- package/dist/commands/relationships/unset.d.ts +16 -0
- package/dist/commands/relationships/unset.d.ts.map +1 -0
- package/dist/commands/relationships/unset.js +62 -0
- package/dist/commands/relationships/unset.js.map +1 -0
- package/dist/commands/relationships/verify.d.ts +24 -0
- package/dist/commands/relationships/verify.d.ts.map +1 -0
- package/dist/commands/relationships/verify.js +328 -0
- package/dist/commands/relationships/verify.js.map +1 -0
- package/dist/commands/stats.d.ts +11 -0
- package/dist/commands/stats.d.ts.map +1 -0
- package/dist/commands/stats.js +207 -0
- package/dist/commands/stats.js.map +1 -0
- package/dist/commands/symbols/annotate.d.ts +32 -0
- package/dist/commands/symbols/annotate.d.ts.map +1 -0
- package/dist/commands/symbols/annotate.js +862 -0
- package/dist/commands/symbols/annotate.js.map +1 -0
- package/dist/commands/symbols/deps.d.ts +18 -0
- package/dist/commands/symbols/deps.d.ts.map +1 -0
- package/dist/commands/symbols/deps.js +104 -0
- package/dist/commands/symbols/deps.js.map +1 -0
- package/dist/commands/symbols/index.d.ts +2 -0
- package/dist/commands/symbols/index.d.ts.map +1 -0
- package/dist/commands/symbols/index.js +2 -0
- package/dist/commands/symbols/index.js.map +1 -0
- package/dist/commands/symbols/list.d.ts +17 -0
- package/dist/commands/symbols/list.d.ts.map +1 -0
- package/dist/commands/symbols/list.js +136 -0
- package/dist/commands/symbols/list.js.map +1 -0
- package/dist/commands/symbols/next.d.ts +15 -0
- package/dist/commands/symbols/next.d.ts.map +1 -0
- package/dist/commands/symbols/next.js +147 -0
- package/dist/commands/symbols/next.js.map +1 -0
- package/dist/commands/symbols/prereqs.d.ts +18 -0
- package/dist/commands/symbols/prereqs.d.ts.map +1 -0
- package/dist/commands/symbols/prereqs.js +107 -0
- package/dist/commands/symbols/prereqs.js.map +1 -0
- package/dist/commands/symbols/ready.d.ts +17 -0
- package/dist/commands/symbols/ready.d.ts.map +1 -0
- package/dist/commands/symbols/ready.js +126 -0
- package/dist/commands/symbols/ready.js.map +1 -0
- package/dist/commands/symbols/set.d.ts +27 -0
- package/dist/commands/symbols/set.d.ts.map +1 -0
- package/dist/commands/symbols/set.js +241 -0
- package/dist/commands/symbols/set.js.map +1 -0
- package/dist/commands/symbols/show.d.ts +19 -0
- package/dist/commands/symbols/show.d.ts.map +1 -0
- package/dist/commands/symbols/show.js +182 -0
- package/dist/commands/symbols/show.js.map +1 -0
- package/dist/commands/symbols/understood.d.ts +15 -0
- package/dist/commands/symbols/understood.d.ts.map +1 -0
- package/dist/commands/symbols/understood.js +101 -0
- package/dist/commands/symbols/understood.js.map +1 -0
- package/dist/commands/symbols/unset.d.ts +16 -0
- package/dist/commands/symbols/unset.d.ts.map +1 -0
- package/dist/commands/symbols/unset.js +48 -0
- package/dist/commands/symbols/unset.js.map +1 -0
- package/dist/commands/symbols/verify.d.ts +25 -0
- package/dist/commands/symbols/verify.d.ts.map +1 -0
- package/dist/commands/symbols/verify.js +360 -0
- package/dist/commands/symbols/verify.js.map +1 -0
- package/dist/db/connection.d.ts +14 -0
- package/dist/db/connection.d.ts.map +1 -0
- package/dist/db/connection.js +37 -0
- package/dist/db/connection.js.map +1 -0
- package/dist/db/database-facade.d.ts +125 -0
- package/dist/db/database-facade.d.ts.map +1 -0
- package/dist/db/database-facade.js +347 -0
- package/dist/db/database-facade.js.map +1 -0
- package/dist/db/database.d.ts +9 -0
- package/dist/db/database.d.ts.map +1 -0
- package/dist/db/database.js +11 -0
- package/dist/db/database.js.map +1 -0
- package/dist/db/index.d.ts +7 -0
- package/dist/db/index.d.ts.map +1 -0
- package/dist/db/index.js +11 -0
- package/dist/db/index.js.map +1 -0
- package/dist/db/repositories/_shared/call-graph-query.d.ts +10 -0
- package/dist/db/repositories/_shared/call-graph-query.d.ts.map +1 -0
- package/dist/db/repositories/_shared/call-graph-query.js +59 -0
- package/dist/db/repositories/_shared/call-graph-query.js.map +1 -0
- package/dist/db/repositories/call-graph-service.d.ts +28 -0
- package/dist/db/repositories/call-graph-service.d.ts.map +1 -0
- package/dist/db/repositories/call-graph-service.js +223 -0
- package/dist/db/repositories/call-graph-service.js.map +1 -0
- package/dist/db/repositories/definition-repository.d.ts +99 -0
- package/dist/db/repositories/definition-repository.d.ts.map +1 -0
- package/dist/db/repositories/definition-repository.js +317 -0
- package/dist/db/repositories/definition-repository.js.map +1 -0
- package/dist/db/repositories/dependency-repository.d.ts +78 -0
- package/dist/db/repositories/dependency-repository.d.ts.map +1 -0
- package/dist/db/repositories/dependency-repository.js +446 -0
- package/dist/db/repositories/dependency-repository.js.map +1 -0
- package/dist/db/repositories/domain-repository.d.ts +97 -0
- package/dist/db/repositories/domain-repository.d.ts.map +1 -0
- package/dist/db/repositories/domain-repository.js +261 -0
- package/dist/db/repositories/domain-repository.js.map +1 -0
- package/dist/db/repositories/feature-repository.d.ts +64 -0
- package/dist/db/repositories/feature-repository.d.ts.map +1 -0
- package/dist/db/repositories/feature-repository.js +189 -0
- package/dist/db/repositories/feature-repository.js.map +1 -0
- package/dist/db/repositories/file-repository.d.ts +67 -0
- package/dist/db/repositories/file-repository.d.ts.map +1 -0
- package/dist/db/repositories/file-repository.js +179 -0
- package/dist/db/repositories/file-repository.js.map +1 -0
- package/dist/db/repositories/flow-repository.d.ts +172 -0
- package/dist/db/repositories/flow-repository.d.ts.map +1 -0
- package/dist/db/repositories/flow-repository.js +599 -0
- package/dist/db/repositories/flow-repository.js.map +1 -0
- package/dist/db/repositories/graph-repository.d.ts +93 -0
- package/dist/db/repositories/graph-repository.d.ts.map +1 -0
- package/dist/db/repositories/graph-repository.js +413 -0
- package/dist/db/repositories/graph-repository.js.map +1 -0
- package/dist/db/repositories/index.d.ts +20 -0
- package/dist/db/repositories/index.d.ts.map +1 -0
- package/dist/db/repositories/index.js +15 -0
- package/dist/db/repositories/index.js.map +1 -0
- package/dist/db/repositories/interaction-analysis.d.ts +78 -0
- package/dist/db/repositories/interaction-analysis.d.ts.map +1 -0
- package/dist/db/repositories/interaction-analysis.js +340 -0
- package/dist/db/repositories/interaction-analysis.js.map +1 -0
- package/dist/db/repositories/interaction-repository.d.ts +145 -0
- package/dist/db/repositories/interaction-repository.d.ts.map +1 -0
- package/dist/db/repositories/interaction-repository.js +395 -0
- package/dist/db/repositories/interaction-repository.js.map +1 -0
- package/dist/db/repositories/metadata-repository.d.ts +110 -0
- package/dist/db/repositories/metadata-repository.d.ts.map +1 -0
- package/dist/db/repositories/metadata-repository.js +294 -0
- package/dist/db/repositories/metadata-repository.js.map +1 -0
- package/dist/db/repositories/module-repository.d.ts +162 -0
- package/dist/db/repositories/module-repository.d.ts.map +1 -0
- package/dist/db/repositories/module-repository.js +519 -0
- package/dist/db/repositories/module-repository.js.map +1 -0
- package/dist/db/repositories/relationship-repository.d.ts +98 -0
- package/dist/db/repositories/relationship-repository.d.ts.map +1 -0
- package/dist/db/repositories/relationship-repository.js +421 -0
- package/dist/db/repositories/relationship-repository.js.map +1 -0
- package/dist/db/schema-manager.d.ts +31 -0
- package/dist/db/schema-manager.d.ts.map +1 -0
- package/dist/db/schema-manager.js +398 -0
- package/dist/db/schema-manager.js.map +1 -0
- package/dist/db/schema.d.ts +404 -0
- package/dist/db/schema.d.ts.map +1 -0
- package/dist/db/schema.js +234 -0
- package/dist/db/schema.js.map +1 -0
- package/dist/db/utils/tree-builder.d.ts +25 -0
- package/dist/db/utils/tree-builder.d.ts.map +1 -0
- package/dist/db/utils/tree-builder.js +38 -0
- package/dist/db/utils/tree-builder.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -0
- package/dist/parser/ast-parser.d.ts +23 -0
- package/dist/parser/ast-parser.d.ts.map +1 -0
- package/dist/parser/ast-parser.js +65 -0
- package/dist/parser/ast-parser.js.map +1 -0
- package/dist/parser/definition-extractor.d.ts +29 -0
- package/dist/parser/definition-extractor.d.ts.map +1 -0
- package/dist/parser/definition-extractor.js +379 -0
- package/dist/parser/definition-extractor.js.map +1 -0
- package/dist/parser/reference-extractor.d.ts +72 -0
- package/dist/parser/reference-extractor.d.ts.map +1 -0
- package/dist/parser/reference-extractor.js +759 -0
- package/dist/parser/reference-extractor.js.map +1 -0
- package/dist/utils/file-scanner.d.ts +6 -0
- package/dist/utils/file-scanner.d.ts.map +1 -0
- package/dist/utils/file-scanner.js +33 -0
- package/dist/utils/file-scanner.js.map +1 -0
- package/dist/web/api-transforms.d.ts +4 -0
- package/dist/web/api-transforms.d.ts.map +1 -0
- package/dist/web/api-transforms.js +4 -0
- package/dist/web/api-transforms.js.map +1 -0
- package/dist/web/server.d.ts +16 -0
- package/dist/web/server.d.ts.map +1 -0
- package/dist/web/server.js +229 -0
- package/dist/web/server.js.map +1 -0
- package/dist/web/server.test.d.ts +2 -0
- package/dist/web/server.test.d.ts.map +1 -0
- package/dist/web/server.test.js +505 -0
- package/dist/web/server.test.js.map +1 -0
- package/dist/web/transforms/flow-transforms.d.ts +117 -0
- package/dist/web/transforms/flow-transforms.d.ts.map +1 -0
- package/dist/web/transforms/flow-transforms.js +202 -0
- package/dist/web/transforms/flow-transforms.js.map +1 -0
- package/dist/web/transforms/index.d.ts +4 -0
- package/dist/web/transforms/index.d.ts.map +1 -0
- package/dist/web/transforms/index.js +4 -0
- package/dist/web/transforms/index.js.map +1 -0
- package/dist/web/transforms/module-transforms.d.ts +42 -0
- package/dist/web/transforms/module-transforms.d.ts.map +1 -0
- package/dist/web/transforms/module-transforms.js +64 -0
- package/dist/web/transforms/module-transforms.js.map +1 -0
- package/dist/web/transforms/symbol-transforms.d.ts +31 -0
- package/dist/web/transforms/symbol-transforms.d.ts.map +1 -0
- package/dist/web/transforms/symbol-transforms.js +95 -0
- package/dist/web/transforms/symbol-transforms.js.map +1 -0
- package/package.json +96 -0
- package/ui/dist/assets/index-DP3dRMlh.js +268 -0
- package/ui/dist/assets/index-DP3dRMlh.js.map +1 -0
- package/ui/dist/assets/index-Db204Xn1.css +1 -0
- package/ui/dist/index.html +67 -0
|
@@ -0,0 +1,1234 @@
|
|
|
1
|
+
import { Flags } from '@oclif/core';
|
|
2
|
+
import chalk from 'chalk';
|
|
3
|
+
import path from 'node:path';
|
|
4
|
+
import { LlmFlags, SharedFlags } from '../_shared/index.js';
|
|
5
|
+
import { BaseLlmCommand } from '../llm/_shared/base-llm-command.js';
|
|
6
|
+
import { completeWithLogging, getErrorMessage, logLlmRequest, logLlmResponse, } from '../llm/_shared/llm-utils.js';
|
|
7
|
+
import { isValidModulePath, parseAssignmentCsv, parseDeepenCsv, parseTreeCsv } from '../llm/_shared/module-csv.js';
|
|
8
|
+
import { buildAssignmentSystemPrompt, buildAssignmentUserPrompt, buildBranchPushdownSystemPrompt, buildDeepenSystemPrompt, buildDeepenUserPrompt, buildRebalanceSystemPrompt, buildRebalanceUserPrompt, buildTreeSystemPrompt, buildTreeUserPrompt, isTestFile, toSymbolForAssignment, } from '../llm/_shared/module-prompts.js';
|
|
9
|
+
export default class ModulesGenerate extends BaseLlmCommand {
|
|
10
|
+
static description = 'Create module tree structure and assign symbols using LLM';
|
|
11
|
+
static examples = [
|
|
12
|
+
'<%= config.bin %> modules generate',
|
|
13
|
+
'<%= config.bin %> modules generate --phase tree --dry-run',
|
|
14
|
+
'<%= config.bin %> modules generate --phase assign --batch-size 30',
|
|
15
|
+
'<%= config.bin %> modules generate --force',
|
|
16
|
+
];
|
|
17
|
+
static flags = {
|
|
18
|
+
database: SharedFlags.database,
|
|
19
|
+
json: SharedFlags.json,
|
|
20
|
+
...LlmFlags,
|
|
21
|
+
'max-gate-retries': Flags.integer({
|
|
22
|
+
default: 3,
|
|
23
|
+
description: 'Maximum retry attempts when assignment gate fails',
|
|
24
|
+
}),
|
|
25
|
+
phase: Flags.string({
|
|
26
|
+
options: ['all', 'tree', 'assign'],
|
|
27
|
+
default: 'all',
|
|
28
|
+
description: 'Which phase to run: tree (structure), assign (symbols), or all',
|
|
29
|
+
}),
|
|
30
|
+
'batch-size': Flags.integer({
|
|
31
|
+
default: 20,
|
|
32
|
+
description: 'Symbols per LLM call during assignment phase',
|
|
33
|
+
}),
|
|
34
|
+
'max-iterations': Flags.integer({
|
|
35
|
+
default: 100,
|
|
36
|
+
description: 'Maximum LLM iterations for assignment phase',
|
|
37
|
+
}),
|
|
38
|
+
incremental: Flags.boolean({
|
|
39
|
+
default: false,
|
|
40
|
+
description: 'Only assign unassigned symbols (skip tree generation)',
|
|
41
|
+
}),
|
|
42
|
+
'deepen-threshold': Flags.integer({
|
|
43
|
+
default: 10,
|
|
44
|
+
description: 'Min members before splitting a module (0 to disable deepening)',
|
|
45
|
+
}),
|
|
46
|
+
'max-unassigned-pct': Flags.integer({
|
|
47
|
+
default: 5,
|
|
48
|
+
description: 'Maximum % of symbols allowed to remain unassigned',
|
|
49
|
+
}),
|
|
50
|
+
'max-depth': Flags.integer({
|
|
51
|
+
default: 7,
|
|
52
|
+
description: 'Maximum module tree depth (prevents over-nesting during deepening)',
|
|
53
|
+
}),
|
|
54
|
+
'max-modules': Flags.integer({
|
|
55
|
+
default: 0,
|
|
56
|
+
description: 'Maximum total modules allowed (0 = unlimited)',
|
|
57
|
+
}),
|
|
58
|
+
};
|
|
59
|
+
async execute(ctx, flags) {
|
|
60
|
+
const { db, isJson, dryRun, verbose } = ctx;
|
|
61
|
+
const phase = flags.phase;
|
|
62
|
+
const incremental = flags.incremental;
|
|
63
|
+
const llmLogOptions = {
|
|
64
|
+
showRequests: ctx.llmOptions.showLlmRequests,
|
|
65
|
+
showResponses: ctx.llmOptions.showLlmResponses,
|
|
66
|
+
isJson,
|
|
67
|
+
};
|
|
68
|
+
// Check existing modules
|
|
69
|
+
const existingModuleCount = db.modules.getCount();
|
|
70
|
+
if (!incremental) {
|
|
71
|
+
if (!this.checkExistingAndClear(ctx, {
|
|
72
|
+
entityName: 'Modules',
|
|
73
|
+
existingCount: existingModuleCount,
|
|
74
|
+
force: flags.force,
|
|
75
|
+
clearFn: () => db.modules.clear(),
|
|
76
|
+
forceHint: 'Use --force to recreate or --incremental to assign unassigned symbols',
|
|
77
|
+
})) {
|
|
78
|
+
return;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
const maxModules = flags['max-modules'];
|
|
82
|
+
// Phase 1: Tree Structure Generation
|
|
83
|
+
if ((phase === 'all' || phase === 'tree') && !incremental) {
|
|
84
|
+
await this.runTreePhase(db, flags, dryRun, isJson, verbose, llmLogOptions, maxModules);
|
|
85
|
+
}
|
|
86
|
+
// Phase 2: Symbol Assignment
|
|
87
|
+
if (phase === 'all' || phase === 'assign') {
|
|
88
|
+
await this.runAssignmentPhase(db, flags, dryRun, isJson, verbose, llmLogOptions);
|
|
89
|
+
// Coverage gate: check unassigned % and run catch-up passes if needed
|
|
90
|
+
if (!dryRun) {
|
|
91
|
+
const maxUnassignedPct = flags['max-unassigned-pct'];
|
|
92
|
+
const maxGateRetries = flags['max-gate-retries'];
|
|
93
|
+
await this.runAssignmentCoverageGate(db, flags, maxUnassignedPct, maxGateRetries, isJson, verbose);
|
|
94
|
+
}
|
|
95
|
+
// Deterministic fallback for symbols LLM couldn't assign
|
|
96
|
+
if (!dryRun) {
|
|
97
|
+
const remaining = db.modules.getUnassigned();
|
|
98
|
+
if (remaining.length > 0) {
|
|
99
|
+
const fallbackCount = this.assignByFileCohortFallback(db, isJson, verbose);
|
|
100
|
+
if (fallbackCount > 0 && !isJson) {
|
|
101
|
+
this.log(chalk.green(` Deterministic fallback: assigned ${fallbackCount} remaining symbols`));
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
// Prune empty leaf modules after assignment
|
|
106
|
+
if (!dryRun) {
|
|
107
|
+
const pruned = db.modules.pruneEmptyLeaves();
|
|
108
|
+
if (pruned > 0 && !isJson) {
|
|
109
|
+
this.log(chalk.green(` Pruned ${pruned} empty leaf modules`));
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
// Phase 3: Deepening (automatic after assignment, unless disabled)
|
|
113
|
+
const deepenThreshold = flags['deepen-threshold'];
|
|
114
|
+
if (deepenThreshold > 0) {
|
|
115
|
+
await this.runDeepenPhase(db, flags, deepenThreshold, dryRun, isJson, verbose, llmLogOptions, maxModules);
|
|
116
|
+
// Prune any modules emptied by reassignment during deepening
|
|
117
|
+
if (!dryRun) {
|
|
118
|
+
const pruned = db.modules.pruneEmptyLeaves();
|
|
119
|
+
if (pruned > 0 && !isJson) {
|
|
120
|
+
this.log(chalk.green(` Pruned ${pruned} empty leaf modules after deepening`));
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
// Assign color indices for consistent cross-view coloring
|
|
126
|
+
if (!dryRun) {
|
|
127
|
+
db.modules.assignColorIndices();
|
|
128
|
+
}
|
|
129
|
+
// Final stats
|
|
130
|
+
if (!dryRun) {
|
|
131
|
+
const stats = db.modules.getStats();
|
|
132
|
+
if (isJson) {
|
|
133
|
+
this.log(JSON.stringify(stats));
|
|
134
|
+
}
|
|
135
|
+
else {
|
|
136
|
+
this.log('');
|
|
137
|
+
this.log(chalk.green('Module tree complete.'));
|
|
138
|
+
this.log(chalk.gray(` Modules: ${stats.moduleCount}`));
|
|
139
|
+
this.log(chalk.gray(` Assigned symbols: ${stats.assigned}`));
|
|
140
|
+
this.log(chalk.gray(` Unassigned symbols: ${stats.unassigned}`));
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
/**
|
|
145
|
+
* Phase 1: Generate the module tree structure.
|
|
146
|
+
*/
|
|
147
|
+
async runTreePhase(db, flags, dryRun, isJson, verbose, llmLogOptions, maxModules) {
|
|
148
|
+
if (!isJson) {
|
|
149
|
+
this.log(chalk.bold('Phase 1: Tree Structure Generation'));
|
|
150
|
+
}
|
|
151
|
+
// Ensure root module exists
|
|
152
|
+
if (!dryRun) {
|
|
153
|
+
db.modules.ensureRoot();
|
|
154
|
+
}
|
|
155
|
+
// Gather context for the LLM
|
|
156
|
+
const context = this.buildTreeContext(db, maxModules);
|
|
157
|
+
if (context.totalSymbolCount === 0) {
|
|
158
|
+
if (isJson) {
|
|
159
|
+
this.log(JSON.stringify({ error: 'No symbols found in database' }));
|
|
160
|
+
}
|
|
161
|
+
else {
|
|
162
|
+
this.log(chalk.yellow('No symbols found in database.'));
|
|
163
|
+
}
|
|
164
|
+
return;
|
|
165
|
+
}
|
|
166
|
+
if (!isJson && verbose) {
|
|
167
|
+
this.log(chalk.gray(` Total symbols: ${context.totalSymbolCount}`));
|
|
168
|
+
this.log(chalk.gray(` Domains found: ${context.domains.length}`));
|
|
169
|
+
}
|
|
170
|
+
// Build prompts
|
|
171
|
+
const systemPrompt = buildTreeSystemPrompt();
|
|
172
|
+
const userPrompt = buildTreeUserPrompt(context);
|
|
173
|
+
if (verbose && !isJson) {
|
|
174
|
+
this.log(chalk.gray(' Calling LLM for tree structure...'));
|
|
175
|
+
}
|
|
176
|
+
logLlmRequest(this, 'runTreePhase', systemPrompt, userPrompt, llmLogOptions);
|
|
177
|
+
// Call LLM
|
|
178
|
+
const response = await completeWithLogging({
|
|
179
|
+
model: flags.model,
|
|
180
|
+
systemPrompt,
|
|
181
|
+
userPrompt,
|
|
182
|
+
temperature: 0,
|
|
183
|
+
command: this,
|
|
184
|
+
isJson,
|
|
185
|
+
});
|
|
186
|
+
logLlmResponse(this, 'runTreePhase', response, llmLogOptions);
|
|
187
|
+
// Parse response
|
|
188
|
+
const { modules: parsedModules, errors } = parseTreeCsv(response);
|
|
189
|
+
if (errors.length > 0 && !isJson) {
|
|
190
|
+
this.log(chalk.yellow(` Parse warnings: ${errors.length}`));
|
|
191
|
+
if (verbose) {
|
|
192
|
+
for (const err of errors.slice(0, 5)) {
|
|
193
|
+
this.log(chalk.gray(` ${err}`));
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
if (parsedModules.length === 0) {
|
|
198
|
+
if (isJson) {
|
|
199
|
+
this.log(JSON.stringify({ error: 'No modules parsed from LLM response', parseErrors: errors }));
|
|
200
|
+
}
|
|
201
|
+
else {
|
|
202
|
+
this.log(chalk.red('No modules parsed from LLM response.'));
|
|
203
|
+
}
|
|
204
|
+
return;
|
|
205
|
+
}
|
|
206
|
+
if (dryRun) {
|
|
207
|
+
if (isJson) {
|
|
208
|
+
this.log(JSON.stringify({
|
|
209
|
+
phase: 'tree',
|
|
210
|
+
dryRun: true,
|
|
211
|
+
proposedModules: parsedModules,
|
|
212
|
+
parseErrors: errors,
|
|
213
|
+
}, null, 2));
|
|
214
|
+
}
|
|
215
|
+
else {
|
|
216
|
+
this.log(chalk.gray(` Proposed modules: ${parsedModules.length}`));
|
|
217
|
+
this.log('');
|
|
218
|
+
for (const mod of parsedModules) {
|
|
219
|
+
const fullPath = `${mod.parentPath}.${mod.slug}`;
|
|
220
|
+
this.log(chalk.cyan(` ${fullPath}: ${mod.name}`));
|
|
221
|
+
if (mod.description) {
|
|
222
|
+
this.log(chalk.gray(` ${mod.description}`));
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
return;
|
|
227
|
+
}
|
|
228
|
+
// Insert modules in order (parent before child)
|
|
229
|
+
// Sort by parentPath length to ensure parents are created first
|
|
230
|
+
const sortedModules = [...parsedModules].sort((a, b) => {
|
|
231
|
+
const aDepth = a.parentPath.split('.').length;
|
|
232
|
+
const bDepth = b.parentPath.split('.').length;
|
|
233
|
+
return aDepth - bDepth;
|
|
234
|
+
});
|
|
235
|
+
let insertedCount = 0;
|
|
236
|
+
for (const mod of sortedModules) {
|
|
237
|
+
if (maxModules > 0 && db.modules.getCount() >= maxModules) {
|
|
238
|
+
if (!isJson) {
|
|
239
|
+
this.log(chalk.yellow(` Reached max-modules limit (${maxModules}), stopping module creation`));
|
|
240
|
+
}
|
|
241
|
+
break;
|
|
242
|
+
}
|
|
243
|
+
const parent = db.modules.getByPath(mod.parentPath);
|
|
244
|
+
if (!parent) {
|
|
245
|
+
if (verbose && !isJson) {
|
|
246
|
+
this.log(chalk.yellow(` Skipping ${mod.slug}: parent ${mod.parentPath} not found`));
|
|
247
|
+
}
|
|
248
|
+
continue;
|
|
249
|
+
}
|
|
250
|
+
try {
|
|
251
|
+
db.modules.insert(parent.id, mod.slug, mod.name, mod.description, mod.isTest);
|
|
252
|
+
insertedCount++;
|
|
253
|
+
}
|
|
254
|
+
catch (error) {
|
|
255
|
+
if (verbose && !isJson) {
|
|
256
|
+
const message = getErrorMessage(error);
|
|
257
|
+
this.log(chalk.yellow(` Failed to insert ${mod.slug}: ${message}`));
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
if (!isJson) {
|
|
262
|
+
this.log(chalk.green(` Created ${insertedCount} modules`));
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
/**
|
|
266
|
+
* Phase 2: Assign symbols to modules.
|
|
267
|
+
*/
|
|
268
|
+
async runAssignmentPhase(db, flags, dryRun, isJson, verbose, llmLogOptions) {
|
|
269
|
+
if (!isJson) {
|
|
270
|
+
this.log('');
|
|
271
|
+
this.log(chalk.bold('Phase 2: Symbol Assignment'));
|
|
272
|
+
}
|
|
273
|
+
// Get all modules
|
|
274
|
+
const modules = db.modules.getAll();
|
|
275
|
+
if (modules.length === 0) {
|
|
276
|
+
if (isJson) {
|
|
277
|
+
this.log(JSON.stringify({ error: 'No modules found. Run tree phase first.' }));
|
|
278
|
+
}
|
|
279
|
+
else {
|
|
280
|
+
this.log(chalk.yellow('No modules found. Run tree phase first.'));
|
|
281
|
+
}
|
|
282
|
+
return;
|
|
283
|
+
}
|
|
284
|
+
// Build module path lookup
|
|
285
|
+
const moduleByPath = new Map(modules.map((m) => [m.fullPath, m]));
|
|
286
|
+
// Get unassigned symbols
|
|
287
|
+
const unassignedSymbols = db.modules.getUnassigned();
|
|
288
|
+
if (unassignedSymbols.length === 0) {
|
|
289
|
+
if (isJson) {
|
|
290
|
+
this.log(JSON.stringify({ message: 'All symbols already assigned' }));
|
|
291
|
+
}
|
|
292
|
+
else {
|
|
293
|
+
this.log(chalk.green(' All symbols already assigned.'));
|
|
294
|
+
}
|
|
295
|
+
return;
|
|
296
|
+
}
|
|
297
|
+
if (!isJson) {
|
|
298
|
+
this.log(chalk.gray(` Unassigned symbols: ${unassignedSymbols.length}`));
|
|
299
|
+
this.log(chalk.gray(` Available modules: ${modules.length}`));
|
|
300
|
+
}
|
|
301
|
+
const batchSize = flags['batch-size'];
|
|
302
|
+
const maxIterations = flags['max-iterations'];
|
|
303
|
+
const systemPrompt = buildAssignmentSystemPrompt();
|
|
304
|
+
// Auto-adjust max iterations to ensure every symbol gets at least one LLM attempt
|
|
305
|
+
const neededIterations = Math.ceil(unassignedSymbols.length / batchSize);
|
|
306
|
+
const effectiveMaxIterations = Math.max(maxIterations, neededIterations);
|
|
307
|
+
if (effectiveMaxIterations > maxIterations && !isJson) {
|
|
308
|
+
this.log(chalk.gray(` Auto-adjusted max iterations: ${maxIterations} → ${effectiveMaxIterations} (to cover all ${unassignedSymbols.length} symbols)`));
|
|
309
|
+
}
|
|
310
|
+
let totalAssigned = 0;
|
|
311
|
+
let iteration = 0;
|
|
312
|
+
const allAssignments = [];
|
|
313
|
+
let directoryHints;
|
|
314
|
+
// Process in batches
|
|
315
|
+
for (let i = 0; i < unassignedSymbols.length && iteration < effectiveMaxIterations; i += batchSize) {
|
|
316
|
+
iteration++;
|
|
317
|
+
const batch = unassignedSymbols.slice(i, i + batchSize);
|
|
318
|
+
const symbolsForAssignment = batch.map(toSymbolForAssignment);
|
|
319
|
+
// Recompute directory hints every 5 batches (first batch has no hints — no symbols assigned yet)
|
|
320
|
+
if (!dryRun && iteration > 1 && (iteration - 1) % 5 === 0) {
|
|
321
|
+
directoryHints = this.computeModuleDirectoryHints(db);
|
|
322
|
+
}
|
|
323
|
+
if (verbose && !isJson) {
|
|
324
|
+
this.log(chalk.gray(` Batch ${iteration}: ${batch.length} symbols...`));
|
|
325
|
+
}
|
|
326
|
+
const userPrompt = buildAssignmentUserPrompt(modules, symbolsForAssignment, directoryHints);
|
|
327
|
+
try {
|
|
328
|
+
logLlmRequest(this, `runAssignmentPhase-batch${iteration}`, systemPrompt, userPrompt, llmLogOptions);
|
|
329
|
+
const response = await completeWithLogging({
|
|
330
|
+
model: flags.model,
|
|
331
|
+
systemPrompt,
|
|
332
|
+
userPrompt,
|
|
333
|
+
temperature: 0,
|
|
334
|
+
command: this,
|
|
335
|
+
isJson,
|
|
336
|
+
iteration: { current: iteration, max: effectiveMaxIterations },
|
|
337
|
+
});
|
|
338
|
+
logLlmResponse(this, `runAssignmentPhase-batch${iteration}`, response, llmLogOptions);
|
|
339
|
+
const { assignments, errors } = parseAssignmentCsv(response);
|
|
340
|
+
if (errors.length > 0 && verbose && !isJson) {
|
|
341
|
+
this.log(chalk.yellow(` Parse warnings: ${errors.length}`));
|
|
342
|
+
}
|
|
343
|
+
// Validate and apply assignments
|
|
344
|
+
const result = this.applyParsedAssignments(assignments, moduleByPath, db, dryRun, allAssignments);
|
|
345
|
+
totalAssigned += result.assigned;
|
|
346
|
+
if (!isJson && (result.invalidPath > 0 || result.notFound > 0 || result.fuzzy > 0)) {
|
|
347
|
+
const parts = [];
|
|
348
|
+
if (result.fuzzy > 0)
|
|
349
|
+
parts.push(`${result.fuzzy} fuzzy-resolved`);
|
|
350
|
+
if (result.invalidPath > 0)
|
|
351
|
+
parts.push(`${result.invalidPath} invalid-path`);
|
|
352
|
+
if (result.notFound > 0)
|
|
353
|
+
parts.push(`${result.notFound} not-found`);
|
|
354
|
+
this.log(chalk.yellow(` Batch ${iteration}: ${parts.join(', ')}`));
|
|
355
|
+
}
|
|
356
|
+
// Detect omitted symbols and retry once
|
|
357
|
+
const returnedIds = new Set(assignments.map((a) => a.symbolId));
|
|
358
|
+
const omittedSymbols = batch.filter((s) => !returnedIds.has(s.id));
|
|
359
|
+
if (omittedSymbols.length > 0 && omittedSymbols.length <= batchSize / 2) {
|
|
360
|
+
const retrySymbols = omittedSymbols.map(toSymbolForAssignment);
|
|
361
|
+
const retryUserPrompt = buildAssignmentUserPrompt(modules, retrySymbols, directoryHints);
|
|
362
|
+
try {
|
|
363
|
+
const retryResponse = await completeWithLogging({
|
|
364
|
+
model: flags.model,
|
|
365
|
+
systemPrompt,
|
|
366
|
+
userPrompt: retryUserPrompt,
|
|
367
|
+
temperature: 0,
|
|
368
|
+
command: this,
|
|
369
|
+
isJson,
|
|
370
|
+
iteration: { current: iteration, max: effectiveMaxIterations },
|
|
371
|
+
});
|
|
372
|
+
const { assignments: retryAssignments } = parseAssignmentCsv(retryResponse);
|
|
373
|
+
const retryResult = this.applyParsedAssignments(retryAssignments, moduleByPath, db, dryRun, allAssignments);
|
|
374
|
+
totalAssigned += retryResult.assigned;
|
|
375
|
+
if (verbose && !isJson) {
|
|
376
|
+
this.log(chalk.gray(` Retry: ${omittedSymbols.length} omitted → ${retryResult.assigned} assigned`));
|
|
377
|
+
}
|
|
378
|
+
}
|
|
379
|
+
catch {
|
|
380
|
+
// Retry failed — will be caught by coverage gate or fallback
|
|
381
|
+
}
|
|
382
|
+
}
|
|
383
|
+
if (!isJson && !verbose) {
|
|
384
|
+
process.stdout.write(chalk.gray('.'));
|
|
385
|
+
}
|
|
386
|
+
}
|
|
387
|
+
catch (error) {
|
|
388
|
+
const message = getErrorMessage(error);
|
|
389
|
+
if (!isJson) {
|
|
390
|
+
this.log(chalk.red(` Batch ${iteration} failed: ${message}`));
|
|
391
|
+
}
|
|
392
|
+
}
|
|
393
|
+
}
|
|
394
|
+
if (!isJson && !verbose) {
|
|
395
|
+
this.log(''); // New line after dots
|
|
396
|
+
}
|
|
397
|
+
if (dryRun) {
|
|
398
|
+
if (isJson) {
|
|
399
|
+
this.log(JSON.stringify({
|
|
400
|
+
phase: 'assign',
|
|
401
|
+
dryRun: true,
|
|
402
|
+
proposedAssignments: allAssignments,
|
|
403
|
+
totalAssigned,
|
|
404
|
+
}, null, 2));
|
|
405
|
+
}
|
|
406
|
+
else {
|
|
407
|
+
this.log(chalk.gray(` Would assign ${totalAssigned} symbols`));
|
|
408
|
+
}
|
|
409
|
+
return;
|
|
410
|
+
}
|
|
411
|
+
if (!isJson) {
|
|
412
|
+
this.log(chalk.green(` Assigned ${totalAssigned} symbols`));
|
|
413
|
+
}
|
|
414
|
+
}
|
|
415
|
+
/**
|
|
416
|
+
* Coverage gate: check unassigned symbol % and run catch-up passes if needed.
|
|
417
|
+
*/
|
|
418
|
+
async runAssignmentCoverageGate(db, flags, maxUnassignedPct, maxGateRetries, isJson, _verbose) {
|
|
419
|
+
const stats = db.modules.getStats();
|
|
420
|
+
const total = stats.assigned + stats.unassigned;
|
|
421
|
+
if (total === 0)
|
|
422
|
+
return;
|
|
423
|
+
let unassignedPct = (stats.unassigned / total) * 100;
|
|
424
|
+
if (unassignedPct <= maxUnassignedPct)
|
|
425
|
+
return;
|
|
426
|
+
if (!isJson) {
|
|
427
|
+
this.log('');
|
|
428
|
+
this.log(chalk.yellow(` ${unassignedPct.toFixed(1)}% symbols still unassigned (threshold: ${maxUnassignedPct}%), running catch-up passes`));
|
|
429
|
+
}
|
|
430
|
+
const modules = db.modules.getAll();
|
|
431
|
+
const moduleByPath = new Map(modules.map((m) => [m.fullPath, m]));
|
|
432
|
+
const batchSize = flags['batch-size'];
|
|
433
|
+
const relaxedSystemPrompt = `You are a software architect assigning symbols to modules.
|
|
434
|
+
Each symbol must be assigned to exactly ONE module path.
|
|
435
|
+
|
|
436
|
+
## Your Task
|
|
437
|
+
These symbols were difficult to assign in prior passes. Use your best judgment.
|
|
438
|
+
If none of the existing modules fit perfectly, assign to the closest parent module.
|
|
439
|
+
|
|
440
|
+
## Output Format
|
|
441
|
+
Respond with **only** a CSV table:
|
|
442
|
+
|
|
443
|
+
\`\`\`csv
|
|
444
|
+
type,symbol_id,module_path
|
|
445
|
+
assignment,42,project.frontend.screens.login
|
|
446
|
+
\`\`\`
|
|
447
|
+
|
|
448
|
+
## Guidelines
|
|
449
|
+
- Every symbol must be assigned to exactly one module
|
|
450
|
+
- Module paths must match existing modules in the tree
|
|
451
|
+
- Prefer more specific modules, but if unsure use the closest parent
|
|
452
|
+
- Consider the file path as a strong hint
|
|
453
|
+
- CRITICAL: Output exactly one assignment row for every symbol listed. Do not skip any.`;
|
|
454
|
+
for (let retry = 0; retry < maxGateRetries; retry++) {
|
|
455
|
+
const unassigned = db.modules.getUnassigned();
|
|
456
|
+
if (unassigned.length === 0)
|
|
457
|
+
break;
|
|
458
|
+
const currentPct = (unassigned.length / total) * 100;
|
|
459
|
+
if (currentPct <= maxUnassignedPct)
|
|
460
|
+
break;
|
|
461
|
+
if (!isJson) {
|
|
462
|
+
this.log(chalk.gray(` Catch-up pass ${retry + 1}/${maxGateRetries}: ${unassigned.length} symbols remaining`));
|
|
463
|
+
}
|
|
464
|
+
let passAssigned = 0;
|
|
465
|
+
let passFuzzy = 0;
|
|
466
|
+
let passInvalidPath = 0;
|
|
467
|
+
let passNotFound = 0;
|
|
468
|
+
let passErrors = 0;
|
|
469
|
+
for (let i = 0; i < unassigned.length; i += batchSize) {
|
|
470
|
+
const batch = unassigned.slice(i, i + batchSize);
|
|
471
|
+
const symbolsForAssignment = batch.map(toSymbolForAssignment);
|
|
472
|
+
const userPrompt = buildAssignmentUserPrompt(modules, symbolsForAssignment);
|
|
473
|
+
try {
|
|
474
|
+
const response = await completeWithLogging({
|
|
475
|
+
model: flags.model,
|
|
476
|
+
systemPrompt: relaxedSystemPrompt,
|
|
477
|
+
userPrompt,
|
|
478
|
+
temperature: 0,
|
|
479
|
+
command: this,
|
|
480
|
+
isJson,
|
|
481
|
+
iteration: { current: retry + 1, max: maxGateRetries },
|
|
482
|
+
});
|
|
483
|
+
const { assignments } = parseAssignmentCsv(response);
|
|
484
|
+
for (const assignment of assignments) {
|
|
485
|
+
if (!isValidModulePath(assignment.modulePath)) {
|
|
486
|
+
passInvalidPath++;
|
|
487
|
+
continue;
|
|
488
|
+
}
|
|
489
|
+
let targetModule = moduleByPath.get(assignment.modulePath);
|
|
490
|
+
if (!targetModule) {
|
|
491
|
+
targetModule = this.resolveModulePath(assignment.modulePath, moduleByPath);
|
|
492
|
+
if (targetModule) {
|
|
493
|
+
passFuzzy++;
|
|
494
|
+
}
|
|
495
|
+
else {
|
|
496
|
+
passNotFound++;
|
|
497
|
+
continue;
|
|
498
|
+
}
|
|
499
|
+
}
|
|
500
|
+
db.modules.assignSymbol(assignment.symbolId, targetModule.id);
|
|
501
|
+
passAssigned++;
|
|
502
|
+
}
|
|
503
|
+
}
|
|
504
|
+
catch (error) {
|
|
505
|
+
passErrors++;
|
|
506
|
+
const message = getErrorMessage(error);
|
|
507
|
+
if (!isJson) {
|
|
508
|
+
this.log(chalk.red(` Catch-up batch error: ${message}`));
|
|
509
|
+
}
|
|
510
|
+
}
|
|
511
|
+
}
|
|
512
|
+
if (!isJson) {
|
|
513
|
+
const parts = [`${passAssigned} assigned`];
|
|
514
|
+
if (passFuzzy > 0)
|
|
515
|
+
parts.push(`${passFuzzy} fuzzy-resolved`);
|
|
516
|
+
if (passInvalidPath > 0)
|
|
517
|
+
parts.push(`${passInvalidPath} invalid-path`);
|
|
518
|
+
if (passNotFound > 0)
|
|
519
|
+
parts.push(`${passNotFound} not-found`);
|
|
520
|
+
if (passErrors > 0)
|
|
521
|
+
parts.push(`${passErrors} errors`);
|
|
522
|
+
this.log(chalk.gray(` Pass ${retry + 1} summary: ${parts.join(', ')}`));
|
|
523
|
+
}
|
|
524
|
+
// Early exit: no progress this pass
|
|
525
|
+
if (passAssigned === 0) {
|
|
526
|
+
if (!isJson) {
|
|
527
|
+
this.log(chalk.yellow(' No progress this pass \u2014 stopping early'));
|
|
528
|
+
}
|
|
529
|
+
break;
|
|
530
|
+
}
|
|
531
|
+
// Re-check
|
|
532
|
+
const updatedStats = db.modules.getStats();
|
|
533
|
+
unassignedPct = (updatedStats.unassigned / total) * 100;
|
|
534
|
+
if (unassignedPct <= maxUnassignedPct) {
|
|
535
|
+
if (!isJson) {
|
|
536
|
+
this.log(chalk.green(` Coverage gate passed: ${unassignedPct.toFixed(1)}% unassigned`));
|
|
537
|
+
}
|
|
538
|
+
return;
|
|
539
|
+
}
|
|
540
|
+
}
|
|
541
|
+
if (!isJson) {
|
|
542
|
+
const finalStats = db.modules.getStats();
|
|
543
|
+
const finalPct = (finalStats.unassigned / total) * 100;
|
|
544
|
+
this.log(chalk.yellow(` Coverage gate: ${finalPct.toFixed(1)}% still unassigned after ${maxGateRetries} retries`));
|
|
545
|
+
}
|
|
546
|
+
}
|
|
547
|
+
/**
|
|
548
|
+
* Phase 3: Deepen large modules by splitting them into sub-modules.
|
|
549
|
+
* Step 1: Rebalance branch modules (has children + direct members) — no new modules created.
|
|
550
|
+
* Step 2: Split leaf modules (largest first) — consumes module budget.
|
|
551
|
+
*/
|
|
552
|
+
async runDeepenPhase(db, flags, threshold, dryRun, isJson, verbose, llmLogOptions, maxModules) {
|
|
553
|
+
if (!isJson) {
|
|
554
|
+
this.log('');
|
|
555
|
+
this.log(chalk.bold('Phase 3: Module Deepening'));
|
|
556
|
+
}
|
|
557
|
+
let totalNewModules = 0;
|
|
558
|
+
let totalReassignments = 0;
|
|
559
|
+
let totalRebalanced = 0;
|
|
560
|
+
// Step 1: Rebalance branch modules (no new modules, no budget spent)
|
|
561
|
+
if (!dryRun) {
|
|
562
|
+
const branchModules = db.modules.getBranchModulesWithDirectMembers(threshold);
|
|
563
|
+
if (branchModules.length > 0 && !isJson) {
|
|
564
|
+
this.log(chalk.gray(` Rebalancing ${branchModules.length} branch modules with direct members`));
|
|
565
|
+
}
|
|
566
|
+
for (const mod of branchModules) {
|
|
567
|
+
if (verbose && !isJson) {
|
|
568
|
+
this.log(chalk.gray(` Rebalancing ${mod.fullPath} (${mod.members.length} direct members)...`));
|
|
569
|
+
}
|
|
570
|
+
// Get existing children paths
|
|
571
|
+
const children = db.modules.getChildren(mod.id);
|
|
572
|
+
const childPaths = children.map((c) => c.fullPath);
|
|
573
|
+
if (childPaths.length === 0)
|
|
574
|
+
continue;
|
|
575
|
+
try {
|
|
576
|
+
const rebalanced = await this.rebalanceAncestorSymbols(db, mod.fullPath, childPaths, flags, isJson, verbose, llmLogOptions, true // includeSelf: push branch's own members to children
|
|
577
|
+
);
|
|
578
|
+
totalRebalanced += rebalanced;
|
|
579
|
+
}
|
|
580
|
+
catch (error) {
|
|
581
|
+
const message = getErrorMessage(error);
|
|
582
|
+
if (!isJson) {
|
|
583
|
+
this.log(chalk.red(` Failed to rebalance ${mod.fullPath}: ${message}`));
|
|
584
|
+
}
|
|
585
|
+
}
|
|
586
|
+
}
|
|
587
|
+
}
|
|
588
|
+
// Step 2: Split leaf modules (budget consumed)
|
|
589
|
+
const maxIterations = 5; // Safety limit to prevent infinite loops
|
|
590
|
+
const maxDepth = flags['max-depth'];
|
|
591
|
+
let iteration = 0;
|
|
592
|
+
let hitModuleLimit = false;
|
|
593
|
+
while (iteration < maxIterations && !hitModuleLimit) {
|
|
594
|
+
iteration++;
|
|
595
|
+
// Query leaf modules exceeding threshold (largest first)
|
|
596
|
+
const allLargeLeaves = dryRun
|
|
597
|
+
? db.modules.getModulesExceedingThreshold(threshold)
|
|
598
|
+
: db.modules.getLeafModulesExceedingThreshold(threshold);
|
|
599
|
+
// Filter out modules already at max depth
|
|
600
|
+
const largeLeaves = allLargeLeaves.filter((m) => m.depth < maxDepth);
|
|
601
|
+
if (largeLeaves.length < allLargeLeaves.length && verbose && !isJson) {
|
|
602
|
+
this.log(chalk.gray(` Skipped ${allLargeLeaves.length - largeLeaves.length} modules at max depth ${maxDepth}`));
|
|
603
|
+
}
|
|
604
|
+
if (largeLeaves.length === 0) {
|
|
605
|
+
if (verbose && !isJson) {
|
|
606
|
+
this.log(chalk.gray(` Iteration ${iteration}: All leaf modules under threshold or at max depth`));
|
|
607
|
+
}
|
|
608
|
+
break;
|
|
609
|
+
}
|
|
610
|
+
if (!isJson) {
|
|
611
|
+
this.log(chalk.gray(` Iteration ${iteration}: ${largeLeaves.length} leaf modules exceed threshold`));
|
|
612
|
+
}
|
|
613
|
+
// Process each large leaf module
|
|
614
|
+
for (const mod of largeLeaves) {
|
|
615
|
+
if (hitModuleLimit)
|
|
616
|
+
break;
|
|
617
|
+
if (verbose && !isJson) {
|
|
618
|
+
this.log(chalk.gray(` Splitting ${mod.fullPath} (${mod.members.length} members)...`));
|
|
619
|
+
}
|
|
620
|
+
// Build prompt data
|
|
621
|
+
const moduleForDeepening = {
|
|
622
|
+
id: mod.id,
|
|
623
|
+
fullPath: mod.fullPath,
|
|
624
|
+
name: mod.name,
|
|
625
|
+
members: mod.members.map((m) => ({
|
|
626
|
+
definitionId: m.definitionId,
|
|
627
|
+
name: m.name,
|
|
628
|
+
kind: m.kind,
|
|
629
|
+
filePath: m.filePath,
|
|
630
|
+
isExported: m.isExported,
|
|
631
|
+
})),
|
|
632
|
+
};
|
|
633
|
+
try {
|
|
634
|
+
const deepenSystemPrompt = buildDeepenSystemPrompt();
|
|
635
|
+
const deepenUserPrompt = buildDeepenUserPrompt(moduleForDeepening);
|
|
636
|
+
logLlmRequest(this, `runDeepenPhase-${mod.fullPath}`, deepenSystemPrompt, deepenUserPrompt, llmLogOptions);
|
|
637
|
+
const response = await completeWithLogging({
|
|
638
|
+
model: flags.model,
|
|
639
|
+
systemPrompt: deepenSystemPrompt,
|
|
640
|
+
userPrompt: deepenUserPrompt,
|
|
641
|
+
temperature: 0,
|
|
642
|
+
command: this,
|
|
643
|
+
isJson,
|
|
644
|
+
});
|
|
645
|
+
logLlmResponse(this, `runDeepenPhase-${mod.fullPath}`, response, llmLogOptions);
|
|
646
|
+
// Parse response
|
|
647
|
+
const { newModules, reassignments, errors } = parseDeepenCsv(response);
|
|
648
|
+
if (errors.length > 0 && verbose && !isJson) {
|
|
649
|
+
this.log(chalk.yellow(` Parse warnings: ${errors.length}`));
|
|
650
|
+
for (const err of errors.slice(0, 3)) {
|
|
651
|
+
this.log(chalk.gray(` ${err}`));
|
|
652
|
+
}
|
|
653
|
+
}
|
|
654
|
+
if (newModules.length === 0) {
|
|
655
|
+
if (verbose && !isJson) {
|
|
656
|
+
this.log(chalk.yellow(` No sub-modules proposed for ${mod.fullPath}`));
|
|
657
|
+
}
|
|
658
|
+
continue;
|
|
659
|
+
}
|
|
660
|
+
if (dryRun) {
|
|
661
|
+
if (verbose && !isJson) {
|
|
662
|
+
this.log(chalk.gray(` Would create ${newModules.length} sub-modules`));
|
|
663
|
+
for (const sub of newModules) {
|
|
664
|
+
this.log(chalk.cyan(` ${mod.fullPath}.${sub.slug}: ${sub.name}`));
|
|
665
|
+
}
|
|
666
|
+
}
|
|
667
|
+
totalNewModules += newModules.length;
|
|
668
|
+
totalReassignments += reassignments.length;
|
|
669
|
+
continue;
|
|
670
|
+
}
|
|
671
|
+
// Create sub-modules
|
|
672
|
+
const createdSubModulePaths = [];
|
|
673
|
+
for (const subMod of newModules) {
|
|
674
|
+
if (maxModules > 0 && db.modules.getCount() >= maxModules) {
|
|
675
|
+
if (!isJson) {
|
|
676
|
+
this.log(chalk.yellow(` Reached max-modules limit (${maxModules}), stopping module creation`));
|
|
677
|
+
}
|
|
678
|
+
hitModuleLimit = true;
|
|
679
|
+
break;
|
|
680
|
+
}
|
|
681
|
+
const parent = db.modules.getByPath(subMod.parentPath);
|
|
682
|
+
if (!parent) {
|
|
683
|
+
if (verbose && !isJson) {
|
|
684
|
+
this.log(chalk.yellow(` Parent not found: ${subMod.parentPath}`));
|
|
685
|
+
}
|
|
686
|
+
continue;
|
|
687
|
+
}
|
|
688
|
+
try {
|
|
689
|
+
// isTest is inherited from parent in ModuleRepository.insert()
|
|
690
|
+
db.modules.insert(parent.id, subMod.slug, subMod.name, subMod.description);
|
|
691
|
+
totalNewModules++;
|
|
692
|
+
createdSubModulePaths.push(`${subMod.parentPath}.${subMod.slug}`);
|
|
693
|
+
}
|
|
694
|
+
catch (error) {
|
|
695
|
+
if (verbose && !isJson) {
|
|
696
|
+
const message = getErrorMessage(error);
|
|
697
|
+
this.log(chalk.yellow(` Failed to create ${subMod.slug}: ${message}`));
|
|
698
|
+
}
|
|
699
|
+
}
|
|
700
|
+
}
|
|
701
|
+
// Reassign symbols to new sub-modules
|
|
702
|
+
for (const reassignment of reassignments) {
|
|
703
|
+
const targetModule = db.modules.getByPath(reassignment.targetModulePath);
|
|
704
|
+
if (!targetModule) {
|
|
705
|
+
if (verbose && !isJson) {
|
|
706
|
+
this.log(chalk.yellow(` Target module not found: ${reassignment.targetModulePath}`));
|
|
707
|
+
}
|
|
708
|
+
continue;
|
|
709
|
+
}
|
|
710
|
+
db.modules.assignSymbol(reassignment.definitionId, targetModule.id);
|
|
711
|
+
totalReassignments++;
|
|
712
|
+
}
|
|
713
|
+
// Rebalance ancestor symbols into new sub-modules
|
|
714
|
+
if (createdSubModulePaths.length > 0 && !hitModuleLimit) {
|
|
715
|
+
const rebalanced = await this.rebalanceAncestorSymbols(db, mod.fullPath, createdSubModulePaths, flags, isJson, verbose, llmLogOptions);
|
|
716
|
+
totalRebalanced += rebalanced;
|
|
717
|
+
}
|
|
718
|
+
}
|
|
719
|
+
catch (error) {
|
|
720
|
+
const message = getErrorMessage(error);
|
|
721
|
+
if (!isJson) {
|
|
722
|
+
this.log(chalk.red(` Failed to process ${mod.fullPath}: ${message}`));
|
|
723
|
+
}
|
|
724
|
+
}
|
|
725
|
+
}
|
|
726
|
+
}
|
|
727
|
+
if (iteration >= maxIterations && !isJson) {
|
|
728
|
+
this.log(chalk.yellow(` Warning: Reached max iterations (${maxIterations})`));
|
|
729
|
+
}
|
|
730
|
+
// Deterministic fallback: push remaining branch members to children by file/directory cohort
|
|
731
|
+
if (!dryRun) {
|
|
732
|
+
const fallbackPushed = this.pushdownBranchMembersFallback(db, isJson, verbose);
|
|
733
|
+
if (fallbackPushed > 0) {
|
|
734
|
+
totalRebalanced += fallbackPushed;
|
|
735
|
+
}
|
|
736
|
+
}
|
|
737
|
+
if (dryRun) {
|
|
738
|
+
if (isJson) {
|
|
739
|
+
this.log(JSON.stringify({
|
|
740
|
+
phase: 'deepen',
|
|
741
|
+
dryRun: true,
|
|
742
|
+
proposedNewModules: totalNewModules,
|
|
743
|
+
proposedReassignments: totalReassignments,
|
|
744
|
+
}));
|
|
745
|
+
}
|
|
746
|
+
else {
|
|
747
|
+
this.log(chalk.gray(` Would create ${totalNewModules} sub-modules`));
|
|
748
|
+
this.log(chalk.gray(` Would reassign ${totalReassignments} symbols`));
|
|
749
|
+
}
|
|
750
|
+
}
|
|
751
|
+
else if (!isJson) {
|
|
752
|
+
this.log(chalk.green(` Created ${totalNewModules} sub-modules`));
|
|
753
|
+
this.log(chalk.green(` Reassigned ${totalReassignments} symbols`));
|
|
754
|
+
if (totalRebalanced > 0) {
|
|
755
|
+
this.log(chalk.green(` Rebalanced ${totalRebalanced} symbols from ancestors`));
|
|
756
|
+
}
|
|
757
|
+
}
|
|
758
|
+
}
|
|
759
|
+
/**
|
|
760
|
+
* Rebalance symbols from ancestor modules into newly created sub-modules.
|
|
761
|
+
* Walks up from the deepened module collecting symbols from ancestors,
|
|
762
|
+
* then asks the LLM if any should be moved into the new sub-structure.
|
|
763
|
+
* Returns the number of symbols rebalanced.
|
|
764
|
+
*/
|
|
765
|
+
async rebalanceAncestorSymbols(db, deepenedModulePath, newSubModulePaths, flags, isJson, verbose, llmLogOptions, includeSelf = false) {
|
|
766
|
+
// Walk up from the deepened module to collect ancestor paths (excluding root "project")
|
|
767
|
+
const segments = deepenedModulePath.split('.');
|
|
768
|
+
const ancestorPaths = [];
|
|
769
|
+
// Include the module's own path for branch pushdown
|
|
770
|
+
if (includeSelf) {
|
|
771
|
+
ancestorPaths.push(deepenedModulePath);
|
|
772
|
+
}
|
|
773
|
+
for (let i = segments.length - 1; i >= 1; i--) {
|
|
774
|
+
const ancestorPath = segments.slice(0, i).join('.');
|
|
775
|
+
if (ancestorPath === 'project')
|
|
776
|
+
break; // don't rebalance from root
|
|
777
|
+
ancestorPaths.push(ancestorPath);
|
|
778
|
+
}
|
|
779
|
+
if (ancestorPaths.length === 0)
|
|
780
|
+
return 0;
|
|
781
|
+
// Collect symbols from each ancestor
|
|
782
|
+
const ancestorSymbols = [];
|
|
783
|
+
for (const p of ancestorPaths) {
|
|
784
|
+
const mod = db.modules.getByPath(p);
|
|
785
|
+
if (!mod)
|
|
786
|
+
continue;
|
|
787
|
+
const symbols = db.modules.getSymbols(mod.id);
|
|
788
|
+
if (symbols.length === 0)
|
|
789
|
+
continue;
|
|
790
|
+
ancestorSymbols.push({ moduleId: mod.id, modulePath: p, symbols });
|
|
791
|
+
}
|
|
792
|
+
if (ancestorSymbols.length === 0)
|
|
793
|
+
return 0;
|
|
794
|
+
const totalSymbols = ancestorSymbols.reduce((sum, g) => sum + g.symbols.length, 0);
|
|
795
|
+
if (verbose && !isJson) {
|
|
796
|
+
this.log(chalk.gray(` Rebalancing: ${totalSymbols} ancestor symbols across ${ancestorSymbols.length} modules`));
|
|
797
|
+
}
|
|
798
|
+
// Build info about new sub-modules
|
|
799
|
+
const newSubModules = [];
|
|
800
|
+
for (const subPath of newSubModulePaths) {
|
|
801
|
+
const mod = db.modules.getByPath(subPath);
|
|
802
|
+
if (!mod)
|
|
803
|
+
continue;
|
|
804
|
+
newSubModules.push({ path: mod.fullPath, name: mod.name, description: mod.description });
|
|
805
|
+
}
|
|
806
|
+
if (newSubModules.length === 0)
|
|
807
|
+
return 0;
|
|
808
|
+
// Call LLM for rebalancing — use aggressive prompt for branch pushdown
|
|
809
|
+
const systemPrompt = includeSelf ? buildBranchPushdownSystemPrompt() : buildRebalanceSystemPrompt();
|
|
810
|
+
const userPrompt = buildRebalanceUserPrompt(ancestorSymbols, newSubModules);
|
|
811
|
+
logLlmRequest(this, `rebalance-${deepenedModulePath}`, systemPrompt, userPrompt, llmLogOptions);
|
|
812
|
+
try {
|
|
813
|
+
const response = await completeWithLogging({
|
|
814
|
+
model: flags.model,
|
|
815
|
+
systemPrompt,
|
|
816
|
+
userPrompt,
|
|
817
|
+
temperature: 0,
|
|
818
|
+
command: this,
|
|
819
|
+
isJson,
|
|
820
|
+
});
|
|
821
|
+
logLlmResponse(this, `rebalance-${deepenedModulePath}`, response, llmLogOptions);
|
|
822
|
+
const { assignments, errors } = parseAssignmentCsv(response);
|
|
823
|
+
if (errors.length > 0 && verbose && !isJson) {
|
|
824
|
+
this.log(chalk.yellow(` Rebalance parse warnings: ${errors.length}`));
|
|
825
|
+
}
|
|
826
|
+
// Apply reassignments — only allow moves into the new sub-structure
|
|
827
|
+
const validSubPaths = new Set(newSubModulePaths);
|
|
828
|
+
const subModuleByPath = new Map();
|
|
829
|
+
for (const p of newSubModulePaths) {
|
|
830
|
+
const mod = db.modules.getByPath(p);
|
|
831
|
+
if (mod)
|
|
832
|
+
subModuleByPath.set(p, { id: mod.id, fullPath: mod.fullPath });
|
|
833
|
+
}
|
|
834
|
+
let rebalanced = 0;
|
|
835
|
+
for (const assignment of assignments) {
|
|
836
|
+
let targetModule;
|
|
837
|
+
if (validSubPaths.has(assignment.modulePath)) {
|
|
838
|
+
targetModule = subModuleByPath.get(assignment.modulePath);
|
|
839
|
+
}
|
|
840
|
+
else {
|
|
841
|
+
// Fuzzy resolve constrained to the deepened module prefix
|
|
842
|
+
targetModule = this.resolveModulePath(assignment.modulePath, subModuleByPath, deepenedModulePath);
|
|
843
|
+
}
|
|
844
|
+
if (!targetModule) {
|
|
845
|
+
if (verbose && !isJson) {
|
|
846
|
+
this.log(chalk.yellow(` Rebalance: skipping move to ${assignment.modulePath} (not a new sub-module)`));
|
|
847
|
+
}
|
|
848
|
+
continue;
|
|
849
|
+
}
|
|
850
|
+
db.modules.assignSymbol(assignment.symbolId, targetModule.id);
|
|
851
|
+
rebalanced++;
|
|
852
|
+
}
|
|
853
|
+
if (rebalanced > 0 && verbose && !isJson) {
|
|
854
|
+
this.log(chalk.gray(` Rebalanced ${rebalanced} symbols from ancestors`));
|
|
855
|
+
}
|
|
856
|
+
return rebalanced;
|
|
857
|
+
}
|
|
858
|
+
catch (error) {
|
|
859
|
+
const message = getErrorMessage(error);
|
|
860
|
+
if (verbose && !isJson) {
|
|
861
|
+
this.log(chalk.yellow(` Rebalance failed: ${message}`));
|
|
862
|
+
}
|
|
863
|
+
return 0;
|
|
864
|
+
}
|
|
865
|
+
}
|
|
866
|
+
/**
|
|
867
|
+
* Validate and apply parsed assignment rows.
|
|
868
|
+
* Returns counts of assigned, fuzzy-resolved, invalid-path, and not-found assignments.
|
|
869
|
+
*/
|
|
870
|
+
applyParsedAssignments(assignments, moduleByPath, db, dryRun, allAssignments) {
|
|
871
|
+
let assigned = 0;
|
|
872
|
+
let fuzzy = 0;
|
|
873
|
+
let invalidPath = 0;
|
|
874
|
+
let notFound = 0;
|
|
875
|
+
for (const assignment of assignments) {
|
|
876
|
+
if (!isValidModulePath(assignment.modulePath)) {
|
|
877
|
+
invalidPath++;
|
|
878
|
+
continue;
|
|
879
|
+
}
|
|
880
|
+
let targetModule = moduleByPath.get(assignment.modulePath);
|
|
881
|
+
if (!targetModule) {
|
|
882
|
+
targetModule = this.resolveModulePath(assignment.modulePath, moduleByPath);
|
|
883
|
+
if (targetModule) {
|
|
884
|
+
fuzzy++;
|
|
885
|
+
}
|
|
886
|
+
else {
|
|
887
|
+
notFound++;
|
|
888
|
+
continue;
|
|
889
|
+
}
|
|
890
|
+
}
|
|
891
|
+
if (!dryRun) {
|
|
892
|
+
db.modules.assignSymbol(assignment.symbolId, targetModule.id);
|
|
893
|
+
}
|
|
894
|
+
allAssignments.push({ symbolId: assignment.symbolId, modulePath: targetModule.fullPath });
|
|
895
|
+
assigned++;
|
|
896
|
+
}
|
|
897
|
+
return { assigned, fuzzy, invalidPath, notFound };
|
|
898
|
+
}
|
|
899
|
+
/**
|
|
900
|
+
* Resolve a module path against the lookup map.
|
|
901
|
+
* Tries exact match first, then falls back to matching by final segment(s).
|
|
902
|
+
* Returns undefined if no match or ambiguous (multiple candidates).
|
|
903
|
+
*/
|
|
904
|
+
resolveModulePath(modulePath, moduleByPath, constrainPrefix) {
|
|
905
|
+
// Exact match
|
|
906
|
+
const exact = moduleByPath.get(modulePath);
|
|
907
|
+
if (exact)
|
|
908
|
+
return exact;
|
|
909
|
+
// Fuzzy: match by final segment(s)
|
|
910
|
+
const segments = modulePath.split('.');
|
|
911
|
+
const candidates = [];
|
|
912
|
+
for (const [fullPath, mod] of moduleByPath) {
|
|
913
|
+
if (constrainPrefix && !fullPath.startsWith(constrainPrefix))
|
|
914
|
+
continue;
|
|
915
|
+
const fullSegments = fullPath.split('.');
|
|
916
|
+
// Check if the path's segments match the tail of the full path
|
|
917
|
+
if (fullSegments.length >= segments.length) {
|
|
918
|
+
const tail = fullSegments.slice(fullSegments.length - segments.length);
|
|
919
|
+
if (tail.every((s, i) => s === segments[i])) {
|
|
920
|
+
candidates.push(mod);
|
|
921
|
+
}
|
|
922
|
+
}
|
|
923
|
+
}
|
|
924
|
+
// Only return if exactly one candidate (avoid ambiguity)
|
|
925
|
+
return candidates.length === 1 ? candidates[0] : undefined;
|
|
926
|
+
}
|
|
927
|
+
/**
|
|
928
|
+
* Compute directory hints for each module based on current member file paths.
|
|
929
|
+
* Returns the top 3 directories per module by member count.
|
|
930
|
+
*/
|
|
931
|
+
computeModuleDirectoryHints(db) {
|
|
932
|
+
const hints = new Map();
|
|
933
|
+
for (const mod of db.modules.getAllWithMembers()) {
|
|
934
|
+
if (mod.members.length === 0)
|
|
935
|
+
continue;
|
|
936
|
+
const dirCounts = new Map();
|
|
937
|
+
for (const m of mod.members) {
|
|
938
|
+
const dir = m.filePath.split('/').slice(0, -1).join('/');
|
|
939
|
+
if (dir)
|
|
940
|
+
dirCounts.set(dir, (dirCounts.get(dir) ?? 0) + 1);
|
|
941
|
+
}
|
|
942
|
+
hints.set(mod.id, Array.from(dirCounts.entries())
|
|
943
|
+
.sort((a, b) => b[1] - a[1])
|
|
944
|
+
.slice(0, 3)
|
|
945
|
+
.map(([dir]) => dir));
|
|
946
|
+
}
|
|
947
|
+
return hints;
|
|
948
|
+
}
|
|
949
|
+
/**
|
|
950
|
+
* Deterministic fallback: assign remaining unassigned symbols using file/directory cohort majority.
|
|
951
|
+
* Tier 1: If other symbols in the same file are assigned to a module, assign there.
|
|
952
|
+
* Tier 2: If other symbols in the same directory are assigned to a module, assign there.
|
|
953
|
+
* Walks up parent directories if no match at the immediate level.
|
|
954
|
+
* Test-file guard: test file symbols only assigned to test modules.
|
|
955
|
+
*/
|
|
956
|
+
assignByFileCohortFallback(db, isJson, verbose) {
|
|
957
|
+
const allModulesWithMembers = db.modules.getAllWithMembers();
|
|
958
|
+
const allModules = db.modules.getAll();
|
|
959
|
+
const moduleById = new Map(allModules.map((m) => [m.id, m]));
|
|
960
|
+
// Build per-file and per-directory module counts from assigned symbols
|
|
961
|
+
const fileModuleCounts = new Map();
|
|
962
|
+
const dirModuleCounts = new Map();
|
|
963
|
+
for (const mod of allModulesWithMembers) {
|
|
964
|
+
for (const member of mod.members) {
|
|
965
|
+
// Per-file counts
|
|
966
|
+
let fileCounts = fileModuleCounts.get(member.filePath);
|
|
967
|
+
if (!fileCounts) {
|
|
968
|
+
fileCounts = new Map();
|
|
969
|
+
fileModuleCounts.set(member.filePath, fileCounts);
|
|
970
|
+
}
|
|
971
|
+
fileCounts.set(mod.id, (fileCounts.get(mod.id) ?? 0) + 1);
|
|
972
|
+
// Per-directory counts
|
|
973
|
+
const dir = path.dirname(member.filePath);
|
|
974
|
+
if (dir) {
|
|
975
|
+
let dirCounts = dirModuleCounts.get(dir);
|
|
976
|
+
if (!dirCounts) {
|
|
977
|
+
dirCounts = new Map();
|
|
978
|
+
dirModuleCounts.set(dir, dirCounts);
|
|
979
|
+
}
|
|
980
|
+
dirCounts.set(mod.id, (dirCounts.get(mod.id) ?? 0) + 1);
|
|
981
|
+
}
|
|
982
|
+
}
|
|
983
|
+
}
|
|
984
|
+
// Resolve majority module per file
|
|
985
|
+
const fileMajority = new Map();
|
|
986
|
+
for (const [filePath, moduleCounts] of fileModuleCounts) {
|
|
987
|
+
let bestModuleId = -1;
|
|
988
|
+
let bestCount = 0;
|
|
989
|
+
for (const [moduleId, count] of moduleCounts) {
|
|
990
|
+
if (count > bestCount) {
|
|
991
|
+
bestModuleId = moduleId;
|
|
992
|
+
bestCount = count;
|
|
993
|
+
}
|
|
994
|
+
}
|
|
995
|
+
if (bestModuleId >= 0) {
|
|
996
|
+
fileMajority.set(filePath, { moduleId: bestModuleId, count: bestCount });
|
|
997
|
+
}
|
|
998
|
+
}
|
|
999
|
+
// Resolve majority module per directory
|
|
1000
|
+
const dirMajority = new Map();
|
|
1001
|
+
for (const [dir, moduleCounts] of dirModuleCounts) {
|
|
1002
|
+
let bestModuleId = -1;
|
|
1003
|
+
let bestCount = 0;
|
|
1004
|
+
for (const [moduleId, count] of moduleCounts) {
|
|
1005
|
+
if (count > bestCount) {
|
|
1006
|
+
bestModuleId = moduleId;
|
|
1007
|
+
bestCount = count;
|
|
1008
|
+
}
|
|
1009
|
+
}
|
|
1010
|
+
if (bestModuleId >= 0) {
|
|
1011
|
+
dirMajority.set(dir, { moduleId: bestModuleId, count: bestCount });
|
|
1012
|
+
}
|
|
1013
|
+
}
|
|
1014
|
+
const unassigned = db.modules.getUnassigned();
|
|
1015
|
+
let tier1Count = 0;
|
|
1016
|
+
let tier2Count = 0;
|
|
1017
|
+
const stillUnassigned = [];
|
|
1018
|
+
for (const sym of unassigned) {
|
|
1019
|
+
const symIsTest = isTestFile(sym.filePath);
|
|
1020
|
+
// Tier 1: Same-file majority
|
|
1021
|
+
const fileMaj = fileMajority.get(sym.filePath);
|
|
1022
|
+
if (fileMaj) {
|
|
1023
|
+
const mod = moduleById.get(fileMaj.moduleId);
|
|
1024
|
+
if (mod && (!symIsTest || mod.isTest)) {
|
|
1025
|
+
db.modules.assignSymbol(sym.id, fileMaj.moduleId);
|
|
1026
|
+
tier1Count++;
|
|
1027
|
+
continue;
|
|
1028
|
+
}
|
|
1029
|
+
}
|
|
1030
|
+
// Tier 2: Same-directory majority, walking up parent dirs
|
|
1031
|
+
let dir = path.dirname(sym.filePath);
|
|
1032
|
+
let assigned = false;
|
|
1033
|
+
while (dir && dir !== '.' && dir !== '/') {
|
|
1034
|
+
const dirMaj = dirMajority.get(dir);
|
|
1035
|
+
if (dirMaj) {
|
|
1036
|
+
const mod = moduleById.get(dirMaj.moduleId);
|
|
1037
|
+
if (mod && (!symIsTest || mod.isTest)) {
|
|
1038
|
+
db.modules.assignSymbol(sym.id, dirMaj.moduleId);
|
|
1039
|
+
tier2Count++;
|
|
1040
|
+
assigned = true;
|
|
1041
|
+
break;
|
|
1042
|
+
}
|
|
1043
|
+
}
|
|
1044
|
+
dir = path.dirname(dir);
|
|
1045
|
+
}
|
|
1046
|
+
if (!assigned) {
|
|
1047
|
+
stillUnassigned.push(sym);
|
|
1048
|
+
}
|
|
1049
|
+
}
|
|
1050
|
+
if (verbose && !isJson) {
|
|
1051
|
+
this.log(chalk.gray(' Deterministic fallback:'));
|
|
1052
|
+
this.log(chalk.gray(` Tier 1 (file cohort): ${tier1Count} assigned`));
|
|
1053
|
+
this.log(chalk.gray(` Tier 2 (directory cohort): ${tier2Count} assigned`));
|
|
1054
|
+
if (stillUnassigned.length > 0) {
|
|
1055
|
+
this.log(chalk.gray(` Still unassigned: ${stillUnassigned.length}`));
|
|
1056
|
+
}
|
|
1057
|
+
}
|
|
1058
|
+
return tier1Count + tier2Count;
|
|
1059
|
+
}
|
|
1060
|
+
/**
|
|
1061
|
+
* Deterministic fallback: push direct members of branch modules to their children
|
|
1062
|
+
* using file/directory cohort voting. Loops until no more progress.
|
|
1063
|
+
*/
|
|
1064
|
+
pushdownBranchMembersFallback(db, isJson, verbose) {
|
|
1065
|
+
let totalPushed = 0;
|
|
1066
|
+
let progress = true;
|
|
1067
|
+
while (progress) {
|
|
1068
|
+
progress = false;
|
|
1069
|
+
const branchModules = db.modules.getBranchModulesWithDirectMembers(0);
|
|
1070
|
+
if (branchModules.length === 0)
|
|
1071
|
+
break;
|
|
1072
|
+
for (const branch of branchModules) {
|
|
1073
|
+
const children = db.modules.getChildren(branch.id);
|
|
1074
|
+
if (children.length === 0)
|
|
1075
|
+
continue;
|
|
1076
|
+
// Build file/directory vote maps from children's members
|
|
1077
|
+
const fileVotes = new Map();
|
|
1078
|
+
const dirVotes = new Map();
|
|
1079
|
+
for (const child of children) {
|
|
1080
|
+
const childMembers = db.modules.getMemberInfo(child.id);
|
|
1081
|
+
for (const member of childMembers) {
|
|
1082
|
+
// File votes
|
|
1083
|
+
let fv = fileVotes.get(member.filePath);
|
|
1084
|
+
if (!fv) {
|
|
1085
|
+
fv = new Map();
|
|
1086
|
+
fileVotes.set(member.filePath, fv);
|
|
1087
|
+
}
|
|
1088
|
+
fv.set(child.id, (fv.get(child.id) ?? 0) + 1);
|
|
1089
|
+
// Directory votes
|
|
1090
|
+
const dir = path.dirname(member.filePath);
|
|
1091
|
+
if (dir) {
|
|
1092
|
+
let dv = dirVotes.get(dir);
|
|
1093
|
+
if (!dv) {
|
|
1094
|
+
dv = new Map();
|
|
1095
|
+
dirVotes.set(dir, dv);
|
|
1096
|
+
}
|
|
1097
|
+
dv.set(child.id, (dv.get(child.id) ?? 0) + 1);
|
|
1098
|
+
}
|
|
1099
|
+
}
|
|
1100
|
+
}
|
|
1101
|
+
// Resolve majority child per file
|
|
1102
|
+
const fileMajority = new Map();
|
|
1103
|
+
for (const [filePath, votes] of fileVotes) {
|
|
1104
|
+
let bestId = -1;
|
|
1105
|
+
let bestCount = 0;
|
|
1106
|
+
for (const [childId, count] of votes) {
|
|
1107
|
+
if (count > bestCount) {
|
|
1108
|
+
bestId = childId;
|
|
1109
|
+
bestCount = count;
|
|
1110
|
+
}
|
|
1111
|
+
}
|
|
1112
|
+
if (bestId >= 0)
|
|
1113
|
+
fileMajority.set(filePath, bestId);
|
|
1114
|
+
}
|
|
1115
|
+
// Resolve majority child per directory
|
|
1116
|
+
const dirMajority = new Map();
|
|
1117
|
+
for (const [dir, votes] of dirVotes) {
|
|
1118
|
+
let bestId = -1;
|
|
1119
|
+
let bestCount = 0;
|
|
1120
|
+
for (const [childId, count] of votes) {
|
|
1121
|
+
if (count > bestCount) {
|
|
1122
|
+
bestId = childId;
|
|
1123
|
+
bestCount = count;
|
|
1124
|
+
}
|
|
1125
|
+
}
|
|
1126
|
+
if (bestId >= 0)
|
|
1127
|
+
dirMajority.set(dir, bestId);
|
|
1128
|
+
}
|
|
1129
|
+
const childById = new Map(children.map((c) => [c.id, c]));
|
|
1130
|
+
for (const member of branch.members) {
|
|
1131
|
+
const symIsTest = isTestFile(member.filePath);
|
|
1132
|
+
let targetChildId;
|
|
1133
|
+
// Tier 1: Same-file majority
|
|
1134
|
+
const fileTarget = fileMajority.get(member.filePath);
|
|
1135
|
+
if (fileTarget !== undefined) {
|
|
1136
|
+
const child = childById.get(fileTarget);
|
|
1137
|
+
if (child && (!symIsTest || child.isTest)) {
|
|
1138
|
+
targetChildId = fileTarget;
|
|
1139
|
+
}
|
|
1140
|
+
}
|
|
1141
|
+
// Tier 2: Same-directory majority (walk up)
|
|
1142
|
+
if (targetChildId === undefined) {
|
|
1143
|
+
let dir = path.dirname(member.filePath);
|
|
1144
|
+
while (dir && dir !== '.' && dir !== '/') {
|
|
1145
|
+
const dirTarget = dirMajority.get(dir);
|
|
1146
|
+
if (dirTarget !== undefined) {
|
|
1147
|
+
const child = childById.get(dirTarget);
|
|
1148
|
+
if (child && (!symIsTest || child.isTest)) {
|
|
1149
|
+
targetChildId = dirTarget;
|
|
1150
|
+
break;
|
|
1151
|
+
}
|
|
1152
|
+
}
|
|
1153
|
+
dir = path.dirname(dir);
|
|
1154
|
+
}
|
|
1155
|
+
}
|
|
1156
|
+
// Tier 3: Single child — move unconditionally
|
|
1157
|
+
if (targetChildId === undefined && children.length === 1) {
|
|
1158
|
+
const child = children[0];
|
|
1159
|
+
if (!symIsTest || child.isTest) {
|
|
1160
|
+
targetChildId = child.id;
|
|
1161
|
+
}
|
|
1162
|
+
}
|
|
1163
|
+
if (targetChildId !== undefined) {
|
|
1164
|
+
db.modules.assignSymbol(member.definitionId, targetChildId);
|
|
1165
|
+
totalPushed++;
|
|
1166
|
+
progress = true;
|
|
1167
|
+
}
|
|
1168
|
+
}
|
|
1169
|
+
}
|
|
1170
|
+
}
|
|
1171
|
+
if (totalPushed > 0 && verbose && !isJson) {
|
|
1172
|
+
this.log(chalk.gray(` Branch pushdown fallback: ${totalPushed} symbols pushed to children`));
|
|
1173
|
+
}
|
|
1174
|
+
return totalPushed;
|
|
1175
|
+
}
|
|
1176
|
+
/**
|
|
1177
|
+
* Build context for tree generation from database.
|
|
1178
|
+
*/
|
|
1179
|
+
buildTreeContext(db, maxModules) {
|
|
1180
|
+
// Get all annotated symbols
|
|
1181
|
+
const allSymbols = db.modules.getUnassigned();
|
|
1182
|
+
// Aggregate by domain
|
|
1183
|
+
const domainMap = new Map();
|
|
1184
|
+
for (const sym of allSymbols) {
|
|
1185
|
+
const domains = sym.domain ?? ['untagged'];
|
|
1186
|
+
for (const domain of domains) {
|
|
1187
|
+
const existing = domainMap.get(domain) ?? { count: 0, symbols: [] };
|
|
1188
|
+
existing.count++;
|
|
1189
|
+
if (existing.symbols.length < 10) {
|
|
1190
|
+
existing.symbols.push({ name: sym.name, kind: sym.kind, role: sym.role });
|
|
1191
|
+
}
|
|
1192
|
+
domainMap.set(domain, existing);
|
|
1193
|
+
}
|
|
1194
|
+
}
|
|
1195
|
+
// Convert to DomainSummary array, sorted by count
|
|
1196
|
+
const domains = Array.from(domainMap.entries())
|
|
1197
|
+
.map(([domain, data]) => ({
|
|
1198
|
+
domain,
|
|
1199
|
+
count: data.count,
|
|
1200
|
+
sampleSymbols: data.symbols,
|
|
1201
|
+
}))
|
|
1202
|
+
.sort((a, b) => b.count - a.count);
|
|
1203
|
+
// Count symbols per leaf directory
|
|
1204
|
+
const dirCounts = new Map();
|
|
1205
|
+
for (const sym of allSymbols) {
|
|
1206
|
+
const dir = sym.filePath.split('/').slice(0, -1).join('/');
|
|
1207
|
+
if (dir)
|
|
1208
|
+
dirCounts.set(dir, (dirCounts.get(dir) ?? 0) + 1);
|
|
1209
|
+
}
|
|
1210
|
+
// Build DirectoryInfo[] — include all ancestor directories too, with cumulative counts
|
|
1211
|
+
const allDirs = new Set();
|
|
1212
|
+
for (const sym of allSymbols) {
|
|
1213
|
+
const parts = sym.filePath.split('/');
|
|
1214
|
+
let dirPath = '';
|
|
1215
|
+
for (let i = 0; i < parts.length - 1; i++) {
|
|
1216
|
+
dirPath = dirPath ? `${dirPath}/${parts[i]}` : parts[i];
|
|
1217
|
+
allDirs.add(dirPath);
|
|
1218
|
+
}
|
|
1219
|
+
}
|
|
1220
|
+
const directoryStructure = Array.from(allDirs)
|
|
1221
|
+
.sort()
|
|
1222
|
+
.map((dir) => ({
|
|
1223
|
+
path: dir,
|
|
1224
|
+
symbolCount: dirCounts.get(dir) ?? 0,
|
|
1225
|
+
}));
|
|
1226
|
+
return {
|
|
1227
|
+
totalSymbolCount: allSymbols.length,
|
|
1228
|
+
domains,
|
|
1229
|
+
directoryStructure,
|
|
1230
|
+
maxModules: maxModules && maxModules > 0 ? maxModules : undefined,
|
|
1231
|
+
};
|
|
1232
|
+
}
|
|
1233
|
+
}
|
|
1234
|
+
//# sourceMappingURL=generate.js.map
|