@planu/cli 0.63.7 → 0.64.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/dist/config/license-plans.json +16 -1
- package/dist/engine/a2a/capability-card.d.ts +16 -0
- package/dist/engine/a2a/capability-card.d.ts.map +1 -0
- package/dist/engine/a2a/capability-card.js +69 -0
- package/dist/engine/a2a/capability-card.js.map +1 -0
- package/dist/engine/a2a/delegate.d.ts +15 -0
- package/dist/engine/a2a/delegate.d.ts.map +1 -0
- package/dist/engine/a2a/delegate.js +47 -0
- package/dist/engine/a2a/delegate.js.map +1 -0
- package/dist/engine/a2a/fallback.d.ts +12 -0
- package/dist/engine/a2a/fallback.d.ts.map +1 -0
- package/dist/engine/a2a/fallback.js +52 -0
- package/dist/engine/a2a/fallback.js.map +1 -0
- package/dist/engine/a2a/index.d.ts +5 -0
- package/dist/engine/a2a/index.d.ts.map +1 -0
- package/dist/engine/a2a/index.js +6 -0
- package/dist/engine/a2a/index.js.map +1 -0
- package/dist/engine/a2a/task-manager.d.ts +39 -0
- package/dist/engine/a2a/task-manager.d.ts.map +1 -0
- package/dist/engine/a2a/task-manager.js +84 -0
- package/dist/engine/a2a/task-manager.js.map +1 -0
- package/dist/engine/ac-gap-detector/analyze-gaps.d.ts +13 -0
- package/dist/engine/ac-gap-detector/analyze-gaps.d.ts.map +1 -0
- package/dist/engine/ac-gap-detector/analyze-gaps.js +43 -0
- package/dist/engine/ac-gap-detector/analyze-gaps.js.map +1 -0
- package/dist/engine/ac-gap-detector/constants.d.ts +22 -0
- package/dist/engine/ac-gap-detector/constants.d.ts.map +1 -0
- package/dist/engine/ac-gap-detector/constants.js +143 -0
- package/dist/engine/ac-gap-detector/constants.js.map +1 -0
- package/dist/engine/ac-gap-detector/gap-rules.d.ts +16 -0
- package/dist/engine/ac-gap-detector/gap-rules.d.ts.map +1 -0
- package/dist/engine/ac-gap-detector/gap-rules.js +180 -0
- package/dist/engine/ac-gap-detector/gap-rules.js.map +1 -0
- package/dist/engine/ac-gap-detector/pattern-matcher.d.ts +16 -0
- package/dist/engine/ac-gap-detector/pattern-matcher.d.ts.map +1 -0
- package/dist/engine/ac-gap-detector/pattern-matcher.js +62 -0
- package/dist/engine/ac-gap-detector/pattern-matcher.js.map +1 -0
- package/dist/engine/ac-gap-detector.d.ts +3 -0
- package/dist/engine/ac-gap-detector.d.ts.map +1 -0
- package/dist/engine/ac-gap-detector.js +5 -0
- package/dist/engine/ac-gap-detector.js.map +1 -0
- package/dist/engine/audit-trail/attestation.d.ts +11 -0
- package/dist/engine/audit-trail/attestation.d.ts.map +1 -0
- package/dist/engine/audit-trail/attestation.js +47 -0
- package/dist/engine/audit-trail/attestation.js.map +1 -0
- package/dist/engine/audit-trail/index.d.ts +6 -0
- package/dist/engine/audit-trail/index.d.ts.map +1 -0
- package/dist/engine/audit-trail/index.js +6 -0
- package/dist/engine/audit-trail/index.js.map +1 -0
- package/dist/engine/audit-trail/logger.d.ts +17 -0
- package/dist/engine/audit-trail/logger.d.ts.map +1 -0
- package/dist/engine/audit-trail/logger.js +78 -0
- package/dist/engine/audit-trail/logger.js.map +1 -0
- package/dist/engine/audit-trail/query.d.ts +7 -0
- package/dist/engine/audit-trail/query.d.ts.map +1 -0
- package/dist/engine/audit-trail/query.js +61 -0
- package/dist/engine/audit-trail/query.js.map +1 -0
- package/dist/engine/audit-trail/utils.d.ts +18 -0
- package/dist/engine/audit-trail/utils.d.ts.map +1 -0
- package/dist/engine/audit-trail/utils.js +44 -0
- package/dist/engine/audit-trail/utils.js.map +1 -0
- package/dist/engine/audit-trail/verifier.d.ts +10 -0
- package/dist/engine/audit-trail/verifier.d.ts.map +1 -0
- package/dist/engine/audit-trail/verifier.js +78 -0
- package/dist/engine/audit-trail/verifier.js.map +1 -0
- package/dist/engine/auth/config.d.ts +20 -0
- package/dist/engine/auth/config.d.ts.map +1 -0
- package/dist/engine/auth/config.js +49 -0
- package/dist/engine/auth/config.js.map +1 -0
- package/dist/engine/auth/index.d.ts +6 -0
- package/dist/engine/auth/index.d.ts.map +1 -0
- package/dist/engine/auth/index.js +7 -0
- package/dist/engine/auth/index.js.map +1 -0
- package/dist/engine/auth/middleware.d.ts +19 -0
- package/dist/engine/auth/middleware.d.ts.map +1 -0
- package/dist/engine/auth/middleware.js +64 -0
- package/dist/engine/auth/middleware.js.map +1 -0
- package/dist/engine/auth/pkce.d.ts +17 -0
- package/dist/engine/auth/pkce.d.ts.map +1 -0
- package/dist/engine/auth/pkce.js +33 -0
- package/dist/engine/auth/pkce.js.map +1 -0
- package/dist/engine/auth/scope-mapper.d.ts +21 -0
- package/dist/engine/auth/scope-mapper.d.ts.map +1 -0
- package/dist/engine/auth/scope-mapper.js +124 -0
- package/dist/engine/auth/scope-mapper.js.map +1 -0
- package/dist/engine/auth/token-validator.d.ts +15 -0
- package/dist/engine/auth/token-validator.d.ts.map +1 -0
- package/dist/engine/auth/token-validator.js +121 -0
- package/dist/engine/auth/token-validator.js.map +1 -0
- package/dist/engine/ci-generator/index.d.ts.map +1 -1
- package/dist/engine/ci-generator/index.js +8 -2
- package/dist/engine/ci-generator/index.js.map +1 -1
- package/dist/engine/ci-generator/yaml-builder.d.ts +7 -2
- package/dist/engine/ci-generator/yaml-builder.d.ts.map +1 -1
- package/dist/engine/ci-generator/yaml-builder.js +49 -1
- package/dist/engine/ci-generator/yaml-builder.js.map +1 -1
- package/dist/engine/design-to-spec/ac-generator.d.ts +21 -0
- package/dist/engine/design-to-spec/ac-generator.d.ts.map +1 -0
- package/dist/engine/design-to-spec/ac-generator.js +185 -0
- package/dist/engine/design-to-spec/ac-generator.js.map +1 -0
- package/dist/engine/design-to-spec/index.d.ts +11 -0
- package/dist/engine/design-to-spec/index.d.ts.map +1 -0
- package/dist/engine/design-to-spec/index.js +19 -0
- package/dist/engine/design-to-spec/index.js.map +1 -0
- package/dist/engine/design-to-spec/parser.d.ts +7 -0
- package/dist/engine/design-to-spec/parser.d.ts.map +1 -0
- package/dist/engine/design-to-spec/parser.js +290 -0
- package/dist/engine/design-to-spec/parser.js.map +1 -0
- package/dist/engine/design-to-spec/spec-builder.d.ts +12 -0
- package/dist/engine/design-to-spec/spec-builder.d.ts.map +1 -0
- package/dist/engine/design-to-spec/spec-builder.js +148 -0
- package/dist/engine/design-to-spec/spec-builder.js.map +1 -0
- package/dist/engine/design-to-spec/ui-contract-builder.d.ts +17 -0
- package/dist/engine/design-to-spec/ui-contract-builder.d.ts.map +1 -0
- package/dist/engine/design-to-spec/ui-contract-builder.js +175 -0
- package/dist/engine/design-to-spec/ui-contract-builder.js.map +1 -0
- package/dist/engine/elicitation/builder.d.ts +37 -0
- package/dist/engine/elicitation/builder.d.ts.map +1 -0
- package/dist/engine/elicitation/builder.js +115 -0
- package/dist/engine/elicitation/builder.js.map +1 -0
- package/dist/engine/elicitation/fallback.d.ts +20 -0
- package/dist/engine/elicitation/fallback.d.ts.map +1 -0
- package/dist/engine/elicitation/fallback.js +72 -0
- package/dist/engine/elicitation/fallback.js.map +1 -0
- package/dist/engine/elicitation/index.d.ts +4 -0
- package/dist/engine/elicitation/index.d.ts.map +1 -0
- package/dist/engine/elicitation/index.js +5 -0
- package/dist/engine/elicitation/index.js.map +1 -0
- package/dist/engine/elicitation/response-parser.d.ts +9 -0
- package/dist/engine/elicitation/response-parser.d.ts.map +1 -0
- package/dist/engine/elicitation/response-parser.js +163 -0
- package/dist/engine/elicitation/response-parser.js.map +1 -0
- package/dist/engine/federation/cross-repo-resolver.d.ts +21 -0
- package/dist/engine/federation/cross-repo-resolver.d.ts.map +1 -0
- package/dist/engine/federation/cross-repo-resolver.js +75 -0
- package/dist/engine/federation/cross-repo-resolver.js.map +1 -0
- package/dist/engine/federation/drift-checker.d.ts +19 -0
- package/dist/engine/federation/drift-checker.d.ts.map +1 -0
- package/dist/engine/federation/drift-checker.js +114 -0
- package/dist/engine/federation/drift-checker.js.map +1 -0
- package/dist/engine/federation/federation-store.d.ts +25 -0
- package/dist/engine/federation/federation-store.d.ts.map +1 -0
- package/dist/engine/federation/federation-store.js +58 -0
- package/dist/engine/federation/federation-store.js.map +1 -0
- package/dist/engine/federation/index.d.ts +4 -0
- package/dist/engine/federation/index.d.ts.map +1 -0
- package/dist/engine/federation/index.js +5 -0
- package/dist/engine/federation/index.js.map +1 -0
- package/dist/engine/github/spec-ac-analyzer.d.ts +40 -0
- package/dist/engine/github/spec-ac-analyzer.d.ts.map +1 -0
- package/dist/engine/github/spec-ac-analyzer.js +181 -0
- package/dist/engine/github/spec-ac-analyzer.js.map +1 -0
- package/dist/engine/hooks/handlers/on-impl-change.d.ts +3 -1
- package/dist/engine/hooks/handlers/on-impl-change.d.ts.map +1 -1
- package/dist/engine/hooks/handlers/on-impl-change.js +25 -1
- package/dist/engine/hooks/handlers/on-impl-change.js.map +1 -1
- package/dist/engine/infrastructure/component-mapper.d.ts +9 -0
- package/dist/engine/infrastructure/component-mapper.d.ts.map +1 -0
- package/dist/engine/infrastructure/component-mapper.js +162 -0
- package/dist/engine/infrastructure/component-mapper.js.map +1 -0
- package/dist/engine/infrastructure/cost-estimator.d.ts +6 -0
- package/dist/engine/infrastructure/cost-estimator.d.ts.map +1 -0
- package/dist/engine/infrastructure/cost-estimator.js +48 -0
- package/dist/engine/infrastructure/cost-estimator.js.map +1 -0
- package/dist/engine/infrastructure/docker-compose-generator.d.ts +6 -0
- package/dist/engine/infrastructure/docker-compose-generator.d.ts.map +1 -0
- package/dist/engine/infrastructure/docker-compose-generator.js +201 -0
- package/dist/engine/infrastructure/docker-compose-generator.js.map +1 -0
- package/dist/engine/infrastructure/index.d.ts +15 -0
- package/dist/engine/infrastructure/index.d.ts.map +1 -0
- package/dist/engine/infrastructure/index.js +67 -0
- package/dist/engine/infrastructure/index.js.map +1 -0
- package/dist/engine/infrastructure/kubernetes-generator.d.ts +6 -0
- package/dist/engine/infrastructure/kubernetes-generator.d.ts.map +1 -0
- package/dist/engine/infrastructure/kubernetes-generator.js +141 -0
- package/dist/engine/infrastructure/kubernetes-generator.js.map +1 -0
- package/dist/engine/infrastructure/railway-generator.d.ts +6 -0
- package/dist/engine/infrastructure/railway-generator.d.ts.map +1 -0
- package/dist/engine/infrastructure/railway-generator.js +87 -0
- package/dist/engine/infrastructure/railway-generator.js.map +1 -0
- package/dist/engine/infrastructure/signal-detector.d.ts +7 -0
- package/dist/engine/infrastructure/signal-detector.d.ts.map +1 -0
- package/dist/engine/infrastructure/signal-detector.js +174 -0
- package/dist/engine/infrastructure/signal-detector.js.map +1 -0
- package/dist/engine/infrastructure/terraform-generator.d.ts +6 -0
- package/dist/engine/infrastructure/terraform-generator.d.ts.map +1 -0
- package/dist/engine/infrastructure/terraform-generator.js +241 -0
- package/dist/engine/infrastructure/terraform-generator.js.map +1 -0
- package/dist/engine/living-spec/annotation-parser.d.ts.map +1 -1
- package/dist/engine/living-spec/annotation-parser.js.map +1 -1
- package/dist/engine/living-spec/auto-updater.d.ts +58 -0
- package/dist/engine/living-spec/auto-updater.d.ts.map +1 -0
- package/dist/engine/living-spec/auto-updater.js +311 -0
- package/dist/engine/living-spec/auto-updater.js.map +1 -0
- package/dist/engine/living-spec/conflict-resolver.d.ts +46 -0
- package/dist/engine/living-spec/conflict-resolver.d.ts.map +1 -0
- package/dist/engine/living-spec/conflict-resolver.js +301 -0
- package/dist/engine/living-spec/conflict-resolver.js.map +1 -0
- package/dist/engine/living-spec/hash-tracker.d.ts.map +1 -1
- package/dist/engine/living-spec/hash-tracker.js.map +1 -1
- package/dist/engine/living-spec/index.d.ts +1 -0
- package/dist/engine/living-spec/index.d.ts.map +1 -1
- package/dist/engine/living-spec/index.js +1 -0
- package/dist/engine/living-spec/index.js.map +1 -1
- package/dist/engine/living-spec/signature-tracker.d.ts.map +1 -1
- package/dist/engine/living-spec/signature-tracker.js.map +1 -1
- package/dist/engine/observability/config.d.ts +16 -0
- package/dist/engine/observability/config.d.ts.map +1 -0
- package/dist/engine/observability/config.js +44 -0
- package/dist/engine/observability/config.js.map +1 -0
- package/dist/engine/observability/index.d.ts +7 -0
- package/dist/engine/observability/index.d.ts.map +1 -0
- package/dist/engine/observability/index.js +8 -0
- package/dist/engine/observability/index.js.map +1 -0
- package/dist/engine/observability/metrics.d.ts +12 -0
- package/dist/engine/observability/metrics.d.ts.map +1 -0
- package/dist/engine/observability/metrics.js +61 -0
- package/dist/engine/observability/metrics.js.map +1 -0
- package/dist/engine/observability/noop-tracer.d.ts +13 -0
- package/dist/engine/observability/noop-tracer.d.ts.map +1 -0
- package/dist/engine/observability/noop-tracer.js +41 -0
- package/dist/engine/observability/noop-tracer.js.map +1 -0
- package/dist/engine/observability/otel-tracer.d.ts +19 -0
- package/dist/engine/observability/otel-tracer.d.ts.map +1 -0
- package/dist/engine/observability/otel-tracer.js +134 -0
- package/dist/engine/observability/otel-tracer.js.map +1 -0
- package/dist/engine/observability/span-helpers.d.ts +28 -0
- package/dist/engine/observability/span-helpers.d.ts.map +1 -0
- package/dist/engine/observability/span-helpers.js +68 -0
- package/dist/engine/observability/span-helpers.js.map +1 -0
- package/dist/engine/observability/tracer.d.ts +26 -0
- package/dist/engine/observability/tracer.d.ts.map +1 -0
- package/dist/engine/observability/tracer.js +45 -0
- package/dist/engine/observability/tracer.js.map +1 -0
- package/dist/engine/rbac/index.d.ts +3 -0
- package/dist/engine/rbac/index.d.ts.map +1 -0
- package/dist/engine/rbac/index.js +4 -0
- package/dist/engine/rbac/index.js.map +1 -0
- package/dist/engine/rbac/permission-checker.d.ts +21 -0
- package/dist/engine/rbac/permission-checker.d.ts.map +1 -0
- package/dist/engine/rbac/permission-checker.js +74 -0
- package/dist/engine/rbac/permission-checker.js.map +1 -0
- package/dist/engine/rbac/roles.d.ts +12 -0
- package/dist/engine/rbac/roles.d.ts.map +1 -0
- package/dist/engine/rbac/roles.js +37 -0
- package/dist/engine/rbac/roles.js.map +1 -0
- package/dist/engine/shared/ac-extractor.d.ts +9 -0
- package/dist/engine/shared/ac-extractor.d.ts.map +1 -0
- package/dist/engine/shared/ac-extractor.js +36 -0
- package/dist/engine/shared/ac-extractor.js.map +1 -0
- package/dist/engine/shared/line-diff.d.ts +11 -0
- package/dist/engine/shared/line-diff.d.ts.map +1 -0
- package/dist/engine/shared/line-diff.js +32 -0
- package/dist/engine/shared/line-diff.js.map +1 -0
- package/dist/engine/spec-decomposer/analyzer.d.ts +18 -0
- package/dist/engine/spec-decomposer/analyzer.d.ts.map +1 -0
- package/dist/engine/spec-decomposer/analyzer.js +263 -0
- package/dist/engine/spec-decomposer/analyzer.js.map +1 -0
- package/dist/engine/spec-decomposer/file-mapper.d.ts +17 -0
- package/dist/engine/spec-decomposer/file-mapper.d.ts.map +1 -0
- package/dist/engine/spec-decomposer/file-mapper.js +96 -0
- package/dist/engine/spec-decomposer/file-mapper.js.map +1 -0
- package/dist/engine/spec-decomposer/index.d.ts +14 -0
- package/dist/engine/spec-decomposer/index.d.ts.map +1 -0
- package/dist/engine/spec-decomposer/index.js +50 -0
- package/dist/engine/spec-decomposer/index.js.map +1 -0
- package/dist/engine/spec-decomposer/ownership-resolver.d.ts +7 -0
- package/dist/engine/spec-decomposer/ownership-resolver.d.ts.map +1 -0
- package/dist/engine/spec-decomposer/ownership-resolver.js +169 -0
- package/dist/engine/spec-decomposer/ownership-resolver.js.map +1 -0
- package/dist/engine/spec-observability/index.d.ts +4 -0
- package/dist/engine/spec-observability/index.d.ts.map +1 -0
- package/dist/engine/spec-observability/index.js +4 -0
- package/dist/engine/spec-observability/index.js.map +1 -0
- package/dist/engine/spec-observability/metrics.d.ts +8 -0
- package/dist/engine/spec-observability/metrics.d.ts.map +1 -0
- package/dist/engine/spec-observability/metrics.js +116 -0
- package/dist/engine/spec-observability/metrics.js.map +1 -0
- package/dist/engine/spec-observability/tracker.d.ts +22 -0
- package/dist/engine/spec-observability/tracker.d.ts.map +1 -0
- package/dist/engine/spec-observability/tracker.js +77 -0
- package/dist/engine/spec-observability/tracker.js.map +1 -0
- package/dist/engine/spec-reader.d.ts +7 -0
- package/dist/engine/spec-reader.d.ts.map +1 -0
- package/dist/engine/spec-reader.js +23 -0
- package/dist/engine/spec-reader.js.map +1 -0
- package/dist/engine/spec-repair.d.ts +10 -0
- package/dist/engine/spec-repair.d.ts.map +1 -0
- package/dist/engine/spec-repair.js +388 -0
- package/dist/engine/spec-repair.js.map +1 -0
- package/dist/engine/spec-versioning/brancher.d.ts +17 -0
- package/dist/engine/spec-versioning/brancher.d.ts.map +1 -0
- package/dist/engine/spec-versioning/brancher.js +113 -0
- package/dist/engine/spec-versioning/brancher.js.map +1 -0
- package/dist/engine/spec-versioning/differ.d.ts +19 -0
- package/dist/engine/spec-versioning/differ.d.ts.map +1 -0
- package/dist/engine/spec-versioning/differ.js +151 -0
- package/dist/engine/spec-versioning/differ.js.map +1 -0
- package/dist/engine/spec-versioning/index.d.ts +5 -0
- package/dist/engine/spec-versioning/index.d.ts.map +1 -0
- package/dist/engine/spec-versioning/index.js +6 -0
- package/dist/engine/spec-versioning/index.js.map +1 -0
- package/dist/engine/spec-versioning/merger.d.ts +18 -0
- package/dist/engine/spec-versioning/merger.d.ts.map +1 -0
- package/dist/engine/spec-versioning/merger.js +113 -0
- package/dist/engine/spec-versioning/merger.js.map +1 -0
- package/dist/engine/spec-versioning/version-store.d.ts +18 -0
- package/dist/engine/spec-versioning/version-store.d.ts.map +1 -0
- package/dist/engine/spec-versioning/version-store.js +96 -0
- package/dist/engine/spec-versioning/version-store.js.map +1 -0
- package/dist/engine/well-known/discovery.d.ts +7 -0
- package/dist/engine/well-known/discovery.d.ts.map +1 -0
- package/dist/engine/well-known/discovery.js +109 -0
- package/dist/engine/well-known/discovery.js.map +1 -0
- package/dist/engine/well-known/index.d.ts +6 -0
- package/dist/engine/well-known/index.d.ts.map +1 -0
- package/dist/engine/well-known/index.js +5 -0
- package/dist/engine/well-known/index.js.map +1 -0
- package/dist/engine/well-known/manifest-generator.d.ts +7 -0
- package/dist/engine/well-known/manifest-generator.d.ts.map +1 -0
- package/dist/engine/well-known/manifest-generator.js +60 -0
- package/dist/engine/well-known/manifest-generator.js.map +1 -0
- package/dist/engine/well-known/manifest-schema.d.ts +92 -0
- package/dist/engine/well-known/manifest-schema.d.ts.map +1 -0
- package/dist/engine/well-known/manifest-schema.js +70 -0
- package/dist/engine/well-known/manifest-schema.js.map +1 -0
- package/dist/resources/spec-granular.d.ts +33 -0
- package/dist/resources/spec-granular.d.ts.map +1 -0
- package/dist/resources/spec-granular.js +299 -0
- package/dist/resources/spec-granular.js.map +1 -0
- package/dist/storage/federation-store.d.ts +29 -0
- package/dist/storage/federation-store.d.ts.map +1 -0
- package/dist/storage/federation-store.js +111 -0
- package/dist/storage/federation-store.js.map +1 -0
- package/dist/storage/index.d.ts +3 -0
- package/dist/storage/index.d.ts.map +1 -1
- package/dist/storage/index.js +3 -0
- package/dist/storage/index.js.map +1 -1
- package/dist/storage/rbac-store.d.ts +8 -0
- package/dist/storage/rbac-store.d.ts.map +1 -0
- package/dist/storage/rbac-store.js +75 -0
- package/dist/storage/rbac-store.js.map +1 -0
- package/dist/storage/spec-observability-store.d.ts +16 -0
- package/dist/storage/spec-observability-store.d.ts.map +1 -0
- package/dist/storage/spec-observability-store.js +55 -0
- package/dist/storage/spec-observability-store.js.map +1 -0
- package/dist/tools/a2a-handler.d.ts +14 -0
- package/dist/tools/a2a-handler.d.ts.map +1 -0
- package/dist/tools/a2a-handler.js +100 -0
- package/dist/tools/a2a-handler.js.map +1 -0
- package/dist/tools/assign-role-handler.d.ts +3 -0
- package/dist/tools/assign-role-handler.d.ts.map +1 -0
- package/dist/tools/assign-role-handler.js +25 -0
- package/dist/tools/assign-role-handler.js.map +1 -0
- package/dist/tools/audit-trail-handler.d.ts +4 -0
- package/dist/tools/audit-trail-handler.d.ts.map +1 -0
- package/dist/tools/audit-trail-handler.js +91 -0
- package/dist/tools/audit-trail-handler.js.map +1 -0
- package/dist/tools/auto-update-spec.d.ts +3 -0
- package/dist/tools/auto-update-spec.d.ts.map +1 -0
- package/dist/tools/auto-update-spec.js +43 -0
- package/dist/tools/auto-update-spec.js.map +1 -0
- package/dist/tools/branch-spec.d.ts +3 -0
- package/dist/tools/branch-spec.d.ts.map +1 -0
- package/dist/tools/branch-spec.js +68 -0
- package/dist/tools/branch-spec.js.map +1 -0
- package/dist/tools/configure-auth-handler.d.ts +15 -0
- package/dist/tools/configure-auth-handler.d.ts.map +1 -0
- package/dist/tools/configure-auth-handler.js +113 -0
- package/dist/tools/configure-auth-handler.js.map +1 -0
- package/dist/tools/configure-observability.d.ts +14 -0
- package/dist/tools/configure-observability.d.ts.map +1 -0
- package/dist/tools/configure-observability.js +96 -0
- package/dist/tools/configure-observability.js.map +1 -0
- package/dist/tools/configure-roles-handler.d.ts +4 -0
- package/dist/tools/configure-roles-handler.d.ts.map +1 -0
- package/dist/tools/configure-roles-handler.js +36 -0
- package/dist/tools/configure-roles-handler.js.map +1 -0
- package/dist/tools/create-spec-hu/ac-adapters/architecture-adapter.d.ts +7 -0
- package/dist/tools/create-spec-hu/ac-adapters/architecture-adapter.d.ts.map +1 -0
- package/dist/tools/create-spec-hu/ac-adapters/architecture-adapter.js +114 -0
- package/dist/tools/create-spec-hu/ac-adapters/architecture-adapter.js.map +1 -0
- package/dist/tools/create-spec-hu/ac-adapters/database-adapter.d.ts +7 -0
- package/dist/tools/create-spec-hu/ac-adapters/database-adapter.d.ts.map +1 -0
- package/dist/tools/create-spec-hu/ac-adapters/database-adapter.js +48 -0
- package/dist/tools/create-spec-hu/ac-adapters/database-adapter.js.map +1 -0
- package/dist/tools/create-spec-hu/ac-adapters/index.d.ts +14 -0
- package/dist/tools/create-spec-hu/ac-adapters/index.d.ts.map +1 -0
- package/dist/tools/create-spec-hu/ac-adapters/index.js +28 -0
- package/dist/tools/create-spec-hu/ac-adapters/index.js.map +1 -0
- package/dist/tools/create-spec-hu/ac-adapters/stack-adapter.d.ts +7 -0
- package/dist/tools/create-spec-hu/ac-adapters/stack-adapter.d.ts.map +1 -0
- package/dist/tools/create-spec-hu/ac-adapters/stack-adapter.js +99 -0
- package/dist/tools/create-spec-hu/ac-adapters/stack-adapter.js.map +1 -0
- package/dist/tools/create-spec-hu/ac-adapters/testing-adapter.d.ts +7 -0
- package/dist/tools/create-spec-hu/ac-adapters/testing-adapter.d.ts.map +1 -0
- package/dist/tools/create-spec-hu/ac-adapters/testing-adapter.js +62 -0
- package/dist/tools/create-spec-hu/ac-adapters/testing-adapter.js.map +1 -0
- package/dist/tools/create-spec-hu/hu-body-generators.d.ts.map +1 -1
- package/dist/tools/create-spec-hu/hu-body-generators.js +41 -19
- package/dist/tools/create-spec-hu/hu-body-generators.js.map +1 -1
- package/dist/tools/create-spec-tech/ficha-content.d.ts.map +1 -1
- package/dist/tools/create-spec-tech/ficha-content.js +235 -5
- package/dist/tools/create-spec-tech/ficha-content.js.map +1 -1
- package/dist/tools/decompose-spec.d.ts +7 -0
- package/dist/tools/decompose-spec.d.ts.map +1 -0
- package/dist/tools/decompose-spec.js +49 -0
- package/dist/tools/decompose-spec.js.map +1 -0
- package/dist/tools/design-to-spec.d.ts +12 -0
- package/dist/tools/design-to-spec.d.ts.map +1 -0
- package/dist/tools/design-to-spec.js +73 -0
- package/dist/tools/design-to-spec.js.map +1 -0
- package/dist/tools/detect-ac-gaps.d.ts +7 -0
- package/dist/tools/detect-ac-gaps.d.ts.map +1 -0
- package/dist/tools/detect-ac-gaps.js +63 -0
- package/dist/tools/detect-ac-gaps.js.map +1 -0
- package/dist/tools/discover-registry.d.ts +8 -0
- package/dist/tools/discover-registry.d.ts.map +1 -0
- package/dist/tools/discover-registry.js +79 -0
- package/dist/tools/discover-registry.js.map +1 -0
- package/dist/tools/federate-specs.d.ts +6 -0
- package/dist/tools/federate-specs.d.ts.map +1 -0
- package/dist/tools/federate-specs.js +41 -0
- package/dist/tools/federate-specs.js.map +1 -0
- package/dist/tools/federation-status.d.ts +6 -0
- package/dist/tools/federation-status.d.ts.map +1 -0
- package/dist/tools/federation-status.js +56 -0
- package/dist/tools/federation-status.js.map +1 -0
- package/dist/tools/generate-annotations.d.ts.map +1 -1
- package/dist/tools/generate-annotations.js +3 -1
- package/dist/tools/generate-annotations.js.map +1 -1
- package/dist/tools/generate-infrastructure.d.ts +3 -0
- package/dist/tools/generate-infrastructure.d.ts.map +1 -0
- package/dist/tools/generate-infrastructure.js +60 -0
- package/dist/tools/generate-infrastructure.js.map +1 -0
- package/dist/tools/merge-spec-branch.d.ts +3 -0
- package/dist/tools/merge-spec-branch.d.ts.map +1 -0
- package/dist/tools/merge-spec-branch.js +103 -0
- package/dist/tools/merge-spec-branch.js.map +1 -0
- package/dist/tools/publish-registry.d.ts +8 -0
- package/dist/tools/publish-registry.d.ts.map +1 -0
- package/dist/tools/publish-registry.js +76 -0
- package/dist/tools/publish-registry.js.map +1 -0
- package/dist/tools/register-a2a-tools.d.ts +3 -0
- package/dist/tools/register-a2a-tools.d.ts.map +1 -0
- package/dist/tools/register-a2a-tools.js +66 -0
- package/dist/tools/register-a2a-tools.js.map +1 -0
- package/dist/tools/register-audit-trail-tools.d.ts +3 -0
- package/dist/tools/register-audit-trail-tools.d.ts.map +1 -0
- package/dist/tools/register-audit-trail-tools.js +62 -0
- package/dist/tools/register-audit-trail-tools.js.map +1 -0
- package/dist/tools/register-decompose-tools.d.ts +3 -0
- package/dist/tools/register-decompose-tools.d.ts.map +1 -0
- package/dist/tools/register-decompose-tools.js +31 -0
- package/dist/tools/register-decompose-tools.js.map +1 -0
- package/dist/tools/register-federation-tools.d.ts +6 -0
- package/dist/tools/register-federation-tools.d.ts.map +1 -0
- package/dist/tools/register-federation-tools.js +48 -0
- package/dist/tools/register-federation-tools.js.map +1 -0
- package/dist/tools/register-infrastructure-tools.d.ts +3 -0
- package/dist/tools/register-infrastructure-tools.d.ts.map +1 -0
- package/dist/tools/register-infrastructure-tools.js +34 -0
- package/dist/tools/register-infrastructure-tools.js.map +1 -0
- package/dist/tools/register-living-spec-tools.d.ts.map +1 -1
- package/dist/tools/register-living-spec-tools.js +2 -8
- package/dist/tools/register-living-spec-tools.js.map +1 -1
- package/dist/tools/register-observability-tools.d.ts +3 -0
- package/dist/tools/register-observability-tools.d.ts.map +1 -0
- package/dist/tools/register-observability-tools.js +48 -0
- package/dist/tools/register-observability-tools.js.map +1 -0
- package/dist/tools/register-rbac-tools.d.ts +3 -0
- package/dist/tools/register-rbac-tools.d.ts.map +1 -0
- package/dist/tools/register-rbac-tools.js +36 -0
- package/dist/tools/register-rbac-tools.js.map +1 -0
- package/dist/tools/register-spec-observability-tools.d.ts +3 -0
- package/dist/tools/register-spec-observability-tools.d.ts.map +1 -0
- package/dist/tools/register-spec-observability-tools.js +24 -0
- package/dist/tools/register-spec-observability-tools.js.map +1 -0
- package/dist/tools/register-versioning-tools.d.ts +3 -0
- package/dist/tools/register-versioning-tools.d.ts.map +1 -0
- package/dist/tools/register-versioning-tools.js +93 -0
- package/dist/tools/register-versioning-tools.js.map +1 -0
- package/dist/tools/register-well-known-tools.d.ts +3 -0
- package/dist/tools/register-well-known-tools.d.ts.map +1 -0
- package/dist/tools/register-well-known-tools.js +36 -0
- package/dist/tools/register-well-known-tools.js.map +1 -0
- package/dist/tools/repair-spec.d.ts +9 -0
- package/dist/tools/repair-spec.d.ts.map +1 -0
- package/dist/tools/repair-spec.js +93 -0
- package/dist/tools/repair-spec.js.map +1 -0
- package/dist/tools/resolve-spec-conflict.d.ts +7 -0
- package/dist/tools/resolve-spec-conflict.d.ts.map +1 -0
- package/dist/tools/resolve-spec-conflict.js +63 -0
- package/dist/tools/resolve-spec-conflict.js.map +1 -0
- package/dist/tools/response-helpers.d.ts +42 -0
- package/dist/tools/response-helpers.d.ts.map +1 -1
- package/dist/tools/response-helpers.js +29 -0
- package/dist/tools/response-helpers.js.map +1 -1
- package/dist/tools/schemas/auth-schema.d.ts +12 -0
- package/dist/tools/schemas/auth-schema.d.ts.map +1 -0
- package/dist/tools/schemas/auth-schema.js +38 -0
- package/dist/tools/schemas/auth-schema.js.map +1 -0
- package/dist/tools/schemas/rbac.d.ts +26 -0
- package/dist/tools/schemas/rbac.d.ts.map +1 -0
- package/dist/tools/schemas/rbac.js +25 -0
- package/dist/tools/schemas/rbac.js.map +1 -0
- package/dist/tools/schemas/well-known.d.ts +12 -0
- package/dist/tools/schemas/well-known.d.ts.map +1 -0
- package/dist/tools/schemas/well-known.js +31 -0
- package/dist/tools/schemas/well-known.js.map +1 -0
- package/dist/tools/snapshot-spec-hashes.d.ts.map +1 -1
- package/dist/tools/snapshot-spec-hashes.js.map +1 -1
- package/dist/tools/spec-usage-report.d.ts +3 -0
- package/dist/tools/spec-usage-report.d.ts.map +1 -0
- package/dist/tools/spec-usage-report.js +95 -0
- package/dist/tools/spec-usage-report.js.map +1 -0
- package/dist/tools/start-hooks.d.ts.map +1 -1
- package/dist/tools/start-hooks.js +93 -16
- package/dist/tools/start-hooks.js.map +1 -1
- package/dist/tools/version-spec.d.ts +3 -0
- package/dist/tools/version-spec.d.ts.map +1 -0
- package/dist/tools/version-spec.js +54 -0
- package/dist/tools/version-spec.js.map +1 -0
- package/dist/types/a2a.d.ts +125 -0
- package/dist/types/a2a.d.ts.map +1 -0
- package/dist/types/a2a.js +3 -0
- package/dist/types/a2a.js.map +1 -0
- package/dist/types/ac-gap.d.ts +57 -0
- package/dist/types/ac-gap.d.ts.map +1 -0
- package/dist/types/ac-gap.js +3 -0
- package/dist/types/ac-gap.js.map +1 -0
- package/dist/types/audit-trail.d.ts +77 -0
- package/dist/types/audit-trail.d.ts.map +1 -0
- package/dist/types/audit-trail.js +3 -0
- package/dist/types/audit-trail.js.map +1 -0
- package/dist/types/auth.d.ts +82 -0
- package/dist/types/auth.d.ts.map +1 -0
- package/dist/types/auth.js +3 -0
- package/dist/types/auth.js.map +1 -0
- package/dist/types/ci.d.ts +10 -25
- package/dist/types/ci.d.ts.map +1 -1
- package/dist/types/design-to-spec.d.ts +89 -0
- package/dist/types/design-to-spec.d.ts.map +1 -0
- package/dist/types/design-to-spec.js +3 -0
- package/dist/types/design-to-spec.js.map +1 -0
- package/dist/types/elicitation.d.ts +109 -0
- package/dist/types/elicitation.d.ts.map +1 -0
- package/dist/types/elicitation.js +3 -0
- package/dist/types/elicitation.js.map +1 -0
- package/dist/types/federation.d.ts +95 -0
- package/dist/types/federation.d.ts.map +1 -0
- package/dist/types/federation.js +3 -0
- package/dist/types/federation.js.map +1 -0
- package/dist/types/file-hooks.d.ts +8 -6
- package/dist/types/file-hooks.d.ts.map +1 -1
- package/dist/types/github.d.ts +17 -0
- package/dist/types/github.d.ts.map +1 -1
- package/dist/types/index.d.ts +16 -0
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/index.js +16 -0
- package/dist/types/index.js.map +1 -1
- package/dist/types/infrastructure.d.ts +71 -0
- package/dist/types/infrastructure.d.ts.map +1 -0
- package/dist/types/infrastructure.js +3 -0
- package/dist/types/infrastructure.js.map +1 -0
- package/dist/types/living-spec.d.ts +100 -0
- package/dist/types/living-spec.d.ts.map +1 -1
- package/dist/types/observability.d.ts +105 -0
- package/dist/types/observability.d.ts.map +1 -0
- package/dist/types/observability.js +3 -0
- package/dist/types/observability.js.map +1 -0
- package/dist/types/rbac.d.ts +51 -0
- package/dist/types/rbac.d.ts.map +1 -0
- package/dist/types/rbac.js +4 -0
- package/dist/types/rbac.js.map +1 -0
- package/dist/types/resources.d.ts +20 -0
- package/dist/types/resources.d.ts.map +1 -0
- package/dist/types/resources.js +3 -0
- package/dist/types/resources.js.map +1 -0
- package/dist/types/spec/repair.d.ts +33 -0
- package/dist/types/spec/repair.d.ts.map +1 -0
- package/dist/types/spec/repair.js +3 -0
- package/dist/types/spec/repair.js.map +1 -0
- package/dist/types/spec-decomposer.d.ts +108 -0
- package/dist/types/spec-decomposer.d.ts.map +1 -0
- package/dist/types/spec-decomposer.js +4 -0
- package/dist/types/spec-decomposer.js.map +1 -0
- package/dist/types/spec-observability.d.ts +71 -0
- package/dist/types/spec-observability.d.ts.map +1 -0
- package/dist/types/spec-observability.js +4 -0
- package/dist/types/spec-observability.js.map +1 -0
- package/dist/types/spec-versioning.d.ts +117 -0
- package/dist/types/spec-versioning.d.ts.map +1 -0
- package/dist/types/spec-versioning.js +3 -0
- package/dist/types/spec-versioning.js.map +1 -0
- package/dist/types/well-known.d.ts +70 -0
- package/dist/types/well-known.d.ts.map +1 -0
- package/dist/types/well-known.js +3 -0
- package/dist/types/well-known.js.map +1 -0
- package/package.json +1 -1
- package/src/config/license-plans.json +16 -1
|
@@ -0,0 +1,263 @@
|
|
|
1
|
+
// engine/spec-decomposer/analyzer.ts — Analyze spec content into work units (SPEC-157)
|
|
2
|
+
// Reads spec.md acceptance criteria and technical.md file lists, then groups
|
|
3
|
+
// criteria into independent work units suitable for parallel agent execution.
|
|
4
|
+
import { readFile } from 'node:fs/promises';
|
|
5
|
+
import { extractAcceptanceCriteria } from '../shared/ac-extractor.js';
|
|
6
|
+
// ---------------------------------------------------------------------------
|
|
7
|
+
// Criterion classification
|
|
8
|
+
// ---------------------------------------------------------------------------
|
|
9
|
+
/** Keywords that suggest architecture/planning work → opus. */
|
|
10
|
+
const OPUS_KEYWORDS = [
|
|
11
|
+
'architect',
|
|
12
|
+
'design',
|
|
13
|
+
'schema',
|
|
14
|
+
'interface',
|
|
15
|
+
'type',
|
|
16
|
+
'pattern',
|
|
17
|
+
'structure',
|
|
18
|
+
'strategy',
|
|
19
|
+
'dependency',
|
|
20
|
+
'integration',
|
|
21
|
+
];
|
|
22
|
+
/** Keywords that suggest read-only or search work → haiku. */
|
|
23
|
+
const HAIKU_KEYWORDS = [
|
|
24
|
+
'list',
|
|
25
|
+
'read',
|
|
26
|
+
'search',
|
|
27
|
+
'find',
|
|
28
|
+
'query',
|
|
29
|
+
'display',
|
|
30
|
+
'show',
|
|
31
|
+
'report',
|
|
32
|
+
'summary',
|
|
33
|
+
'status',
|
|
34
|
+
];
|
|
35
|
+
function classifyModel(text) {
|
|
36
|
+
const lower = text.toLowerCase();
|
|
37
|
+
if (OPUS_KEYWORDS.some((kw) => lower.includes(kw))) {
|
|
38
|
+
return 'opus';
|
|
39
|
+
}
|
|
40
|
+
if (HAIKU_KEYWORDS.some((kw) => lower.includes(kw))) {
|
|
41
|
+
return 'haiku';
|
|
42
|
+
}
|
|
43
|
+
return 'sonnet';
|
|
44
|
+
}
|
|
45
|
+
// ---------------------------------------------------------------------------
|
|
46
|
+
// File path extraction helpers
|
|
47
|
+
// ---------------------------------------------------------------------------
|
|
48
|
+
const FILE_PATTERN = /`((?:src|tests)\/[^`]+\.(?:ts|js|tsx|jsx))`/g;
|
|
49
|
+
const MD_FILE_PATTERN = /^\s*[-*]\s+`?((?:src|tests)\/[\w./-]+\.(?:ts|js|tsx|jsx))`?/gm;
|
|
50
|
+
const SECTION_PATTERN = /^#{2,4}\s+(.+)$/gm;
|
|
51
|
+
function extractFilesFromText(text) {
|
|
52
|
+
const files = new Set();
|
|
53
|
+
let match;
|
|
54
|
+
const pattern1 = new RegExp(FILE_PATTERN.source, 'g');
|
|
55
|
+
while ((match = pattern1.exec(text)) !== null) {
|
|
56
|
+
if (match[1]) {
|
|
57
|
+
files.add(match[1]);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
const pattern2 = new RegExp(MD_FILE_PATTERN.source, 'gm');
|
|
61
|
+
while ((match = pattern2.exec(text)) !== null) {
|
|
62
|
+
if (match[1]) {
|
|
63
|
+
files.add(match[1]);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
return [...files];
|
|
67
|
+
}
|
|
68
|
+
// ---------------------------------------------------------------------------
|
|
69
|
+
// Spec content parsers
|
|
70
|
+
// ---------------------------------------------------------------------------
|
|
71
|
+
/** Extract acceptance criteria lines from spec.md content. */
|
|
72
|
+
export function extractCriteriaFromContent(content) {
|
|
73
|
+
return extractAcceptanceCriteria(content);
|
|
74
|
+
}
|
|
75
|
+
/** Extract all file paths mentioned in technical.md content. */
|
|
76
|
+
export function extractFilesFromTechnical(content) {
|
|
77
|
+
return extractFilesFromText(content);
|
|
78
|
+
}
|
|
79
|
+
// ---------------------------------------------------------------------------
|
|
80
|
+
// Work unit grouping heuristics
|
|
81
|
+
// ---------------------------------------------------------------------------
|
|
82
|
+
/**
|
|
83
|
+
* Categories used to cluster criteria into work units.
|
|
84
|
+
* Each entry has a label and keywords that identify it.
|
|
85
|
+
*/
|
|
86
|
+
const CATEGORY_RULES = [
|
|
87
|
+
{
|
|
88
|
+
id: 'types',
|
|
89
|
+
title: 'Types and interfaces',
|
|
90
|
+
keywords: ['type', 'interface', 'schema', 'model', 'struct'],
|
|
91
|
+
},
|
|
92
|
+
{
|
|
93
|
+
id: 'engine',
|
|
94
|
+
title: 'Engine / business logic',
|
|
95
|
+
keywords: ['engine', 'logic', 'algorithm', 'process', 'compute', 'analyze', 'detect'],
|
|
96
|
+
},
|
|
97
|
+
{
|
|
98
|
+
id: 'storage',
|
|
99
|
+
title: 'Storage / persistence',
|
|
100
|
+
keywords: ['storage', 'store', 'persist', 'save', 'load', 'database', 'file', 'read', 'write'],
|
|
101
|
+
},
|
|
102
|
+
{
|
|
103
|
+
id: 'tool',
|
|
104
|
+
title: 'MCP tool / handler',
|
|
105
|
+
keywords: ['tool', 'handler', 'endpoint', 'api', 'register', 'input', 'output'],
|
|
106
|
+
},
|
|
107
|
+
{
|
|
108
|
+
id: 'tests',
|
|
109
|
+
title: 'Tests',
|
|
110
|
+
keywords: ['test', 'spec', 'unit', 'coverage', 'mock', 'fixture', 'assert'],
|
|
111
|
+
},
|
|
112
|
+
];
|
|
113
|
+
function categorize(criterion) {
|
|
114
|
+
const lower = criterion.toLowerCase();
|
|
115
|
+
for (const rule of CATEGORY_RULES) {
|
|
116
|
+
if (rule.keywords.some((kw) => lower.includes(kw))) {
|
|
117
|
+
return rule.id;
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
return 'general';
|
|
121
|
+
}
|
|
122
|
+
// ---------------------------------------------------------------------------
|
|
123
|
+
// Public API
|
|
124
|
+
// ---------------------------------------------------------------------------
|
|
125
|
+
/** Read spec.md file and return its content, or empty string on error. */
|
|
126
|
+
async function safeReadFile(filePath) {
|
|
127
|
+
try {
|
|
128
|
+
return await readFile(filePath, 'utf-8');
|
|
129
|
+
/* v8 ignore next 3 */
|
|
130
|
+
}
|
|
131
|
+
catch {
|
|
132
|
+
return '';
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
/**
|
|
136
|
+
* Analyze spec content from disk and produce raw work units.
|
|
137
|
+
* Groups acceptance criteria by category heuristics.
|
|
138
|
+
*/
|
|
139
|
+
export async function analyzeSpec(specPath, technicalPath, maxTasks) {
|
|
140
|
+
const [specContent, techContent] = await Promise.all([
|
|
141
|
+
safeReadFile(specPath),
|
|
142
|
+
safeReadFile(technicalPath),
|
|
143
|
+
]);
|
|
144
|
+
const criteria = extractCriteriaFromContent(specContent);
|
|
145
|
+
const allFiles = extractFilesFromTechnical(techContent);
|
|
146
|
+
return groupCriteriaIntoUnits(criteria, allFiles, maxTasks);
|
|
147
|
+
}
|
|
148
|
+
/**
|
|
149
|
+
* Group criteria lines into work units, respecting maxTasks limit.
|
|
150
|
+
* Exported for unit-testing without touching the filesystem.
|
|
151
|
+
*/
|
|
152
|
+
export function groupCriteriaIntoUnits(criteria, allFiles, maxTasks) {
|
|
153
|
+
if (criteria.length === 0) {
|
|
154
|
+
// Generate a single fallback unit so orchestration always has something to run
|
|
155
|
+
return [
|
|
156
|
+
{
|
|
157
|
+
id: 'unit-general',
|
|
158
|
+
title: 'General implementation',
|
|
159
|
+
criteria: [],
|
|
160
|
+
suggestedFiles: allFiles,
|
|
161
|
+
recommendedModel: 'sonnet',
|
|
162
|
+
estimatedHours: 4,
|
|
163
|
+
},
|
|
164
|
+
];
|
|
165
|
+
}
|
|
166
|
+
// Bucket criteria by category
|
|
167
|
+
const buckets = new Map();
|
|
168
|
+
for (const criterion of criteria) {
|
|
169
|
+
const cat = categorize(criterion);
|
|
170
|
+
const existing = buckets.get(cat) ?? [];
|
|
171
|
+
existing.push(criterion);
|
|
172
|
+
buckets.set(cat, existing);
|
|
173
|
+
}
|
|
174
|
+
// Assign files by rough path matching per category
|
|
175
|
+
const filesByCategory = buildFileCategoryMap(allFiles);
|
|
176
|
+
const units = [];
|
|
177
|
+
for (const entry of buckets.entries()) {
|
|
178
|
+
const catId = entry[0];
|
|
179
|
+
const catCriteria = entry[1];
|
|
180
|
+
const categoryInfo = CATEGORY_RULES.find((r) => r.id === catId) ?? {
|
|
181
|
+
id: catId,
|
|
182
|
+
title: catId,
|
|
183
|
+
};
|
|
184
|
+
const suggestedFiles = filesByCategory.get(catId) ?? [];
|
|
185
|
+
const combinedText = catCriteria.join(' ');
|
|
186
|
+
const model = classifyModel(combinedText);
|
|
187
|
+
const hours = Math.max(1, Math.ceil(catCriteria.length * 1.5));
|
|
188
|
+
units.push({
|
|
189
|
+
id: `unit-${catId}`,
|
|
190
|
+
title: categoryInfo.title,
|
|
191
|
+
criteria: catCriteria,
|
|
192
|
+
suggestedFiles,
|
|
193
|
+
recommendedModel: model,
|
|
194
|
+
estimatedHours: hours,
|
|
195
|
+
});
|
|
196
|
+
}
|
|
197
|
+
// If fewer than 2 units were produced, add uncategorized files to general
|
|
198
|
+
if (units.length === 0) {
|
|
199
|
+
units.push({
|
|
200
|
+
id: 'unit-general',
|
|
201
|
+
title: 'General implementation',
|
|
202
|
+
criteria,
|
|
203
|
+
suggestedFiles: allFiles,
|
|
204
|
+
recommendedModel: 'sonnet',
|
|
205
|
+
estimatedHours: Math.max(2, criteria.length * 1.5),
|
|
206
|
+
});
|
|
207
|
+
}
|
|
208
|
+
// Enforce maxTasks by merging excess units into the last one
|
|
209
|
+
return mergeExcessUnits(units, maxTasks);
|
|
210
|
+
}
|
|
211
|
+
/** Map file paths to category IDs based on path segments. */
|
|
212
|
+
function buildFileCategoryMap(files) {
|
|
213
|
+
const map = new Map();
|
|
214
|
+
for (const file of files) {
|
|
215
|
+
const lower = file.toLowerCase();
|
|
216
|
+
let assigned = false;
|
|
217
|
+
for (const rule of CATEGORY_RULES) {
|
|
218
|
+
if (rule.keywords.some((kw) => lower.includes(kw))) {
|
|
219
|
+
const existing = map.get(rule.id) ?? [];
|
|
220
|
+
existing.push(file);
|
|
221
|
+
map.set(rule.id, existing);
|
|
222
|
+
assigned = true;
|
|
223
|
+
break;
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
if (!assigned) {
|
|
227
|
+
const existing = map.get('general') ?? [];
|
|
228
|
+
existing.push(file);
|
|
229
|
+
map.set('general', existing);
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
return map;
|
|
233
|
+
}
|
|
234
|
+
/** Merge units beyond maxTasks into the last retained unit. */
|
|
235
|
+
function mergeExcessUnits(units, maxTasks) {
|
|
236
|
+
if (units.length <= maxTasks) {
|
|
237
|
+
return units;
|
|
238
|
+
}
|
|
239
|
+
const retained = units.slice(0, maxTasks - 1);
|
|
240
|
+
const overflow = units.slice(maxTasks - 1);
|
|
241
|
+
const merged = {
|
|
242
|
+
id: 'unit-general',
|
|
243
|
+
title: 'Combined implementation',
|
|
244
|
+
criteria: overflow.flatMap((u) => u.criteria),
|
|
245
|
+
suggestedFiles: [...new Set(overflow.flatMap((u) => u.suggestedFiles))],
|
|
246
|
+
recommendedModel: 'sonnet',
|
|
247
|
+
estimatedHours: overflow.reduce((acc, u) => acc + u.estimatedHours, 0),
|
|
248
|
+
};
|
|
249
|
+
return [...retained, merged];
|
|
250
|
+
}
|
|
251
|
+
/** Extract section headers from markdown content (used by file-mapper). */
|
|
252
|
+
export function extractSectionHeaders(content) {
|
|
253
|
+
const headers = [];
|
|
254
|
+
let match;
|
|
255
|
+
const pattern = new RegExp(SECTION_PATTERN.source, 'gm');
|
|
256
|
+
while ((match = pattern.exec(content)) !== null) {
|
|
257
|
+
if (match[1]) {
|
|
258
|
+
headers.push(match[1].trim());
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
return headers;
|
|
262
|
+
}
|
|
263
|
+
//# sourceMappingURL=analyzer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"analyzer.js","sourceRoot":"","sources":["../../../src/engine/spec-decomposer/analyzer.ts"],"names":[],"mappings":"AAAA,uFAAuF;AACvF,6EAA6E;AAC7E,8EAA8E;AAE9E,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAG5C,OAAO,EAAE,yBAAyB,EAAE,MAAM,2BAA2B,CAAC;AAEtE,8EAA8E;AAC9E,2BAA2B;AAC3B,8EAA8E;AAE9E,+DAA+D;AAC/D,MAAM,aAAa,GAAG;IACpB,WAAW;IACX,QAAQ;IACR,QAAQ;IACR,WAAW;IACX,MAAM;IACN,SAAS;IACT,WAAW;IACX,UAAU;IACV,YAAY;IACZ,aAAa;CACd,CAAC;AAEF,8DAA8D;AAC9D,MAAM,cAAc,GAAG;IACrB,MAAM;IACN,MAAM;IACN,QAAQ;IACR,MAAM;IACN,OAAO;IACP,SAAS;IACT,MAAM;IACN,QAAQ;IACR,SAAS;IACT,QAAQ;CACT,CAAC;AAEF,SAAS,aAAa,CAAC,IAAY;IACjC,MAAM,KAAK,GAAG,IAAI,CAAC,WAAW,EAAE,CAAC;IACjC,IAAI,aAAa,CAAC,IAAI,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,KAAK,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC;QACnD,OAAO,MAAM,CAAC;IAChB,CAAC;IACD,IAAI,cAAc,CAAC,IAAI,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,KAAK,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC;QACpD,OAAO,OAAO,CAAC;IACjB,CAAC;IACD,OAAO,QAAQ,CAAC;AAClB,CAAC;AAED,8EAA8E;AAC9E,+BAA+B;AAC/B,8EAA8E;AAE9E,MAAM,YAAY,GAAG,8CAA8C,CAAC;AACpE,MAAM,eAAe,GAAG,+DAA+D,CAAC;AACxF,MAAM,eAAe,GAAG,mBAAmB,CAAC;AAE5C,SAAS,oBAAoB,CAAC,IAAY;IACxC,MAAM,KAAK,GAAG,IAAI,GAAG,EAAU,CAAC;IAEhC,IAAI,KAA6B,CAAC;IAClC,MAAM,QAAQ,GAAG,IAAI,MAAM,CAAC,YAAY,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IACtD,OAAO,CAAC,KAAK,GAAG,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,KAAK,IAAI,EAAE,CAAC;QAC9C,IAAI,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC;YACb,KAAK,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;QACtB,CAAC;IACH,CAAC;IAED,MAAM,QAAQ,GAAG,IAAI,MAAM,CAAC,eAAe,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;IAC1D,OAAO,CAAC,KAAK,GAAG,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,KAAK,IAAI,EAAE,CAAC;QAC9C,IAAI,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC;YACb,KAAK,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;QACtB,CAAC;IACH,CAAC;IAED,OAAO,CAAC,GAAG,KAAK,CAAC,CAAC;AACpB,CAAC;AAED,8EAA8E;AAC9E,uBAAuB;AACvB,8EAA8E;AAE9E,8DAA8D;AAC9D,MAAM,UAAU,0BAA0B,CAAC,OAAe;IACxD,OAAO,yBAAyB,CAAC,OAAO,CAAC,CAAC;AAC5C,CAAC;AAED,gEAAgE;AAChE,MAAM,UAAU,yBAAyB,CAAC,OAAe;IACvD,OAAO,oBAAoB,CAAC,OAAO,CAAC,CAAC;AACvC,CAAC;AAED,8EAA8E;AAC9E,gCAAgC;AAChC,8EAA8E;AAE9E;;;GAGG;AACH,MAAM,cAAc,GAAwD;IAC1E;QACE,EAAE,EAAE,OAAO;QACX,KAAK,EAAE,sBAAsB;QAC7B,QAAQ,EAAE,CAAC,MAAM,EAAE,WAAW,EAAE,QAAQ,EAAE,OAAO,EAAE,QAAQ,CAAC;KAC7D;IACD;QACE,EAAE,EAAE,QAAQ;QACZ,KAAK,EAAE,yBAAyB;QAChC,QAAQ,EAAE,CAAC,QAAQ,EAAE,OAAO,EAAE,WAAW,EAAE,SAAS,EAAE,SAAS,EAAE,SAAS,EAAE,QAAQ,CAAC;KACtF;IACD;QACE,EAAE,EAAE,SAAS;QACb,KAAK,EAAE,uBAAuB;QAC9B,QAAQ,EAAE,CAAC,SAAS,EAAE,OAAO,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,CAAC;KAC/F;IACD;QACE,EAAE,EAAE,MAAM;QACV,KAAK,EAAE,oBAAoB;QAC3B,QAAQ,EAAE,CAAC,MAAM,EAAE,SAAS,EAAE,UAAU,EAAE,KAAK,EAAE,UAAU,EAAE,OAAO,EAAE,QAAQ,CAAC;KAChF;IACD;QACE,EAAE,EAAE,OAAO;QACX,KAAK,EAAE,OAAO;QACd,QAAQ,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,SAAS,EAAE,QAAQ,CAAC;KAC5E;CACF,CAAC;AAEF,SAAS,UAAU,CAAC,SAAiB;IACnC,MAAM,KAAK,GAAG,SAAS,CAAC,WAAW,EAAE,CAAC;IACtC,KAAK,MAAM,IAAI,IAAI,cAAc,EAAE,CAAC;QAClC,IAAI,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,KAAK,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC;YACnD,OAAO,IAAI,CAAC,EAAE,CAAC;QACjB,CAAC;IACH,CAAC;IACD,OAAO,SAAS,CAAC;AACnB,CAAC;AAED,8EAA8E;AAC9E,aAAa;AACb,8EAA8E;AAE9E,0EAA0E;AAC1E,KAAK,UAAU,YAAY,CAAC,QAAgB;IAC1C,IAAI,CAAC;QACH,OAAO,MAAM,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;QACzC,sBAAsB;IACxB,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,CAAC;IACZ,CAAC;AACH,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,WAAW,CAC/B,QAAgB,EAChB,aAAqB,EACrB,QAAgB;IAEhB,MAAM,CAAC,WAAW,EAAE,WAAW,CAAC,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC;QACnD,YAAY,CAAC,QAAQ,CAAC;QACtB,YAAY,CAAC,aAAa,CAAC;KAC5B,CAAC,CAAC;IAEH,MAAM,QAAQ,GAAG,0BAA0B,CAAC,WAAW,CAAC,CAAC;IACzD,MAAM,QAAQ,GAAG,yBAAyB,CAAC,WAAW,CAAC,CAAC;IAExD,OAAO,sBAAsB,CAAC,QAAQ,EAAE,QAAQ,EAAE,QAAQ,CAAC,CAAC;AAC9D,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,sBAAsB,CACpC,QAAkB,EAClB,QAAkB,EAClB,QAAgB;IAEhB,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC1B,+EAA+E;QAC/E,OAAO;YACL;gBACE,EAAE,EAAE,cAAc;gBAClB,KAAK,EAAE,wBAAwB;gBAC/B,QAAQ,EAAE,EAAE;gBACZ,cAAc,EAAE,QAAQ;gBACxB,gBAAgB,EAAE,QAAQ;gBAC1B,cAAc,EAAE,CAAC;aAClB;SACF,CAAC;IACJ,CAAC;IAED,8BAA8B;IAC9B,MAAM,OAAO,GAAG,IAAI,GAAG,EAAoB,CAAC;IAC5C,KAAK,MAAM,SAAS,IAAI,QAAQ,EAAE,CAAC;QACjC,MAAM,GAAG,GAAG,UAAU,CAAC,SAAS,CAAC,CAAC;QAClC,MAAM,QAAQ,GAAG,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC;QACxC,QAAQ,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;QACzB,OAAO,CAAC,GAAG,CAAC,GAAG,EAAE,QAAQ,CAAC,CAAC;IAC7B,CAAC;IAED,mDAAmD;IACnD,MAAM,eAAe,GAAG,oBAAoB,CAAC,QAAQ,CAAC,CAAC;IAEvD,MAAM,KAAK,GAAe,EAAE,CAAC;IAC7B,KAAK,MAAM,KAAK,IAAI,OAAO,CAAC,OAAO,EAAE,EAAE,CAAC;QACtC,MAAM,KAAK,GAAW,KAAK,CAAC,CAAC,CAAC,CAAC;QAC/B,MAAM,WAAW,GAAa,KAAK,CAAC,CAAC,CAAC,CAAC;QACvC,MAAM,YAAY,GAAG,cAAc,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,KAAK,CAAC,IAAI;YACjE,EAAE,EAAE,KAAK;YACT,KAAK,EAAE,KAAK;SACb,CAAC;QACF,MAAM,cAAc,GAAa,eAAe,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC;QAClE,MAAM,YAAY,GAAG,WAAW,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QAC3C,MAAM,KAAK,GAAc,aAAa,CAAC,YAAY,CAAC,CAAC;QACrD,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,IAAI,CAAC,WAAW,CAAC,MAAM,GAAG,GAAG,CAAC,CAAC,CAAC;QAE/D,KAAK,CAAC,IAAI,CAAC;YACT,EAAE,EAAE,QAAQ,KAAK,EAAE;YACnB,KAAK,EAAE,YAAY,CAAC,KAAK;YACzB,QAAQ,EAAE,WAAW;YACrB,cAAc;YACd,gBAAgB,EAAE,KAAK;YACvB,cAAc,EAAE,KAAK;SACtB,CAAC,CAAC;IACL,CAAC;IAED,0EAA0E;IAC1E,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACvB,KAAK,CAAC,IAAI,CAAC;YACT,EAAE,EAAE,cAAc;YAClB,KAAK,EAAE,wBAAwB;YAC/B,QAAQ;YACR,cAAc,EAAE,QAAQ;YACxB,gBAAgB,EAAE,QAAQ;YAC1B,cAAc,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,QAAQ,CAAC,MAAM,GAAG,GAAG,CAAC;SACnD,CAAC,CAAC;IACL,CAAC;IAED,6DAA6D;IAC7D,OAAO,gBAAgB,CAAC,KAAK,EAAE,QAAQ,CAAC,CAAC;AAC3C,CAAC;AAED,6DAA6D;AAC7D,SAAS,oBAAoB,CAAC,KAAe;IAC3C,MAAM,GAAG,GAAG,IAAI,GAAG,EAAoB,CAAC;IAExC,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,MAAM,KAAK,GAAG,IAAI,CAAC,WAAW,EAAE,CAAC;QACjC,IAAI,QAAQ,GAAG,KAAK,CAAC;QAErB,KAAK,MAAM,IAAI,IAAI,cAAc,EAAE,CAAC;YAClC,IAAI,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,KAAK,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC;gBACnD,MAAM,QAAQ,GAAG,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,EAAE,CAAC;gBACxC,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;gBACpB,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,EAAE,QAAQ,CAAC,CAAC;gBAC3B,QAAQ,GAAG,IAAI,CAAC;gBAChB,MAAM;YACR,CAAC;QACH,CAAC;QAED,IAAI,CAAC,QAAQ,EAAE,CAAC;YACd,MAAM,QAAQ,GAAG,GAAG,CAAC,GAAG,CAAC,SAAS,CAAC,IAAI,EAAE,CAAC;YAC1C,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YACpB,GAAG,CAAC,GAAG,CAAC,SAAS,EAAE,QAAQ,CAAC,CAAC;QAC/B,CAAC;IACH,CAAC;IAED,OAAO,GAAG,CAAC;AACb,CAAC;AAED,+DAA+D;AAC/D,SAAS,gBAAgB,CAAC,KAAiB,EAAE,QAAgB;IAC3D,IAAI,KAAK,CAAC,MAAM,IAAI,QAAQ,EAAE,CAAC;QAC7B,OAAO,KAAK,CAAC;IACf,CAAC;IAED,MAAM,QAAQ,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,QAAQ,GAAG,CAAC,CAAC,CAAC;IAC9C,MAAM,QAAQ,GAAG,KAAK,CAAC,KAAK,CAAC,QAAQ,GAAG,CAAC,CAAC,CAAC;IAE3C,MAAM,MAAM,GAAa;QACvB,EAAE,EAAE,cAAc;QAClB,KAAK,EAAE,yBAAyB;QAChC,QAAQ,EAAE,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC;QAC7C,cAAc,EAAE,CAAC,GAAG,IAAI,GAAG,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,cAAc,CAAC,CAAC,CAAC;QACvE,gBAAgB,EAAE,QAAQ;QAC1B,cAAc,EAAE,QAAQ,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC,GAAG,GAAG,CAAC,CAAC,cAAc,EAAE,CAAC,CAAC;KACvE,CAAC;IAEF,OAAO,CAAC,GAAG,QAAQ,EAAE,MAAM,CAAC,CAAC;AAC/B,CAAC;AAED,2EAA2E;AAC3E,MAAM,UAAU,qBAAqB,CAAC,OAAe;IACnD,MAAM,OAAO,GAAa,EAAE,CAAC;IAC7B,IAAI,KAA6B,CAAC;IAClC,MAAM,OAAO,GAAG,IAAI,MAAM,CAAC,eAAe,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;IACzD,OAAO,CAAC,KAAK,GAAG,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,KAAK,IAAI,EAAE,CAAC;QAChD,IAAI,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC;YACb,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC;QAChC,CAAC;IACH,CAAC;IACD,OAAO,OAAO,CAAC;AACjB,CAAC"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { WorkUnit, MappedUnit } from '../../types/spec-decomposer.js';
|
|
2
|
+
/**
|
|
3
|
+
* Map work units to concrete file paths.
|
|
4
|
+
*
|
|
5
|
+
* Strategy:
|
|
6
|
+
* 1. Each unit starts with its suggestedFiles (from analyzer).
|
|
7
|
+
* 2. For remaining files in allFiles not yet assigned, we use path-hint scoring
|
|
8
|
+
* to assign them to the best-matching unit.
|
|
9
|
+
* 3. Files with score 0 for all units are distributed to the last unit (fallback).
|
|
10
|
+
*/
|
|
11
|
+
export declare function mapUnitsToFiles(units: WorkUnit[], allFiles: string[]): MappedUnit[];
|
|
12
|
+
/**
|
|
13
|
+
* De-duplicate files within each mapped unit and ensure uniqueness.
|
|
14
|
+
* Called after mapUnitsToFiles() as a clean-up step.
|
|
15
|
+
*/
|
|
16
|
+
export declare function deduplicateMappedFiles(units: MappedUnit[]): MappedUnit[];
|
|
17
|
+
//# sourceMappingURL=file-mapper.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"file-mapper.d.ts","sourceRoot":"","sources":["../../../src/engine/spec-decomposer/file-mapper.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,QAAQ,EAAE,UAAU,EAAE,MAAM,gCAAgC,CAAC;AAwC3E;;;;;;;;GAQG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,QAAQ,EAAE,EAAE,QAAQ,EAAE,MAAM,EAAE,GAAG,UAAU,EAAE,CA+CnF;AAED;;;GAGG;AACH,wBAAgB,sBAAsB,CAAC,KAAK,EAAE,UAAU,EAAE,GAAG,UAAU,EAAE,CAKxE"}
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
// engine/spec-decomposer/file-mapper.ts — Map work units to specific files (SPEC-157)
|
|
2
|
+
// Given work units and a full list of project files, assigns concrete file paths
|
|
3
|
+
// to each unit based on path segment heuristics.
|
|
4
|
+
// ---------------------------------------------------------------------------
|
|
5
|
+
// Path segment heuristics
|
|
6
|
+
// ---------------------------------------------------------------------------
|
|
7
|
+
/** Map unit IDs to path segment patterns that indicate file relevance. */
|
|
8
|
+
const UNIT_PATH_HINTS = {
|
|
9
|
+
types: ['types/', '/types.ts', 'type.ts'],
|
|
10
|
+
engine: ['engine/', 'analyzer', 'calculator', 'processor', 'resolver', 'detector'],
|
|
11
|
+
storage: ['storage/', 'store.ts', '-store.ts', 'repository', 'persistence'],
|
|
12
|
+
tool: ['tools/', 'handler.ts', 'register-'],
|
|
13
|
+
tests: ['tests/', '.test.ts', '.spec.ts'],
|
|
14
|
+
general: [],
|
|
15
|
+
};
|
|
16
|
+
/**
|
|
17
|
+
* Score how relevant a file path is for a given unit ID.
|
|
18
|
+
* Returns 0 for irrelevant, higher values for stronger matches.
|
|
19
|
+
*/
|
|
20
|
+
function scoreFilePath(filePath, unitId) {
|
|
21
|
+
const lower = filePath.toLowerCase();
|
|
22
|
+
const categoryId = unitId.replace(/^unit-/, '');
|
|
23
|
+
const hints = UNIT_PATH_HINTS[categoryId] ?? UNIT_PATH_HINTS.general ?? [];
|
|
24
|
+
let score = 0;
|
|
25
|
+
for (const hint of hints) {
|
|
26
|
+
if (lower.includes(hint)) {
|
|
27
|
+
score += 2;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
// Bonus: file path contains a keyword from the unit's criteria (caller may inject)
|
|
31
|
+
return score;
|
|
32
|
+
}
|
|
33
|
+
// ---------------------------------------------------------------------------
|
|
34
|
+
// Public API
|
|
35
|
+
// ---------------------------------------------------------------------------
|
|
36
|
+
/**
|
|
37
|
+
* Map work units to concrete file paths.
|
|
38
|
+
*
|
|
39
|
+
* Strategy:
|
|
40
|
+
* 1. Each unit starts with its suggestedFiles (from analyzer).
|
|
41
|
+
* 2. For remaining files in allFiles not yet assigned, we use path-hint scoring
|
|
42
|
+
* to assign them to the best-matching unit.
|
|
43
|
+
* 3. Files with score 0 for all units are distributed to the last unit (fallback).
|
|
44
|
+
*/
|
|
45
|
+
export function mapUnitsToFiles(units, allFiles) {
|
|
46
|
+
if (units.length === 0) {
|
|
47
|
+
return [];
|
|
48
|
+
}
|
|
49
|
+
// Seed each mapped unit with its suggestedFiles
|
|
50
|
+
const mapped = units.map((u) => ({
|
|
51
|
+
id: u.id,
|
|
52
|
+
title: u.title,
|
|
53
|
+
criteria: u.criteria,
|
|
54
|
+
files: [...u.suggestedFiles],
|
|
55
|
+
recommendedModel: u.recommendedModel,
|
|
56
|
+
estimatedHours: u.estimatedHours,
|
|
57
|
+
}));
|
|
58
|
+
// Track which files are already covered
|
|
59
|
+
const assignedFiles = new Set(units.flatMap((u) => u.suggestedFiles));
|
|
60
|
+
// Assign remaining files to best-matching unit
|
|
61
|
+
for (const file of allFiles) {
|
|
62
|
+
if (assignedFiles.has(file)) {
|
|
63
|
+
continue;
|
|
64
|
+
}
|
|
65
|
+
let bestUnitIndex = mapped.length - 1; // fallback: last unit
|
|
66
|
+
let bestScore = -1;
|
|
67
|
+
for (let i = 0; i < mapped.length; i++) {
|
|
68
|
+
const unit = mapped[i];
|
|
69
|
+
if (!unit) {
|
|
70
|
+
continue;
|
|
71
|
+
}
|
|
72
|
+
const score = scoreFilePath(file, unit.id);
|
|
73
|
+
if (score > bestScore) {
|
|
74
|
+
bestScore = score;
|
|
75
|
+
bestUnitIndex = i;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
const target = mapped[bestUnitIndex];
|
|
79
|
+
if (target && !target.files.includes(file)) {
|
|
80
|
+
target.files.push(file);
|
|
81
|
+
assignedFiles.add(file);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
return mapped;
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* De-duplicate files within each mapped unit and ensure uniqueness.
|
|
88
|
+
* Called after mapUnitsToFiles() as a clean-up step.
|
|
89
|
+
*/
|
|
90
|
+
export function deduplicateMappedFiles(units) {
|
|
91
|
+
return units.map((unit) => ({
|
|
92
|
+
...unit,
|
|
93
|
+
files: [...new Set(unit.files)],
|
|
94
|
+
}));
|
|
95
|
+
}
|
|
96
|
+
//# sourceMappingURL=file-mapper.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"file-mapper.js","sourceRoot":"","sources":["../../../src/engine/spec-decomposer/file-mapper.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export { analyzeSpec, groupCriteriaIntoUnits, extractCriteriaFromContent, extractFilesFromTechnical, } from './analyzer.js';
|
|
2
|
+
export { mapUnitsToFiles, deduplicateMappedFiles } from './file-mapper.js';
|
|
3
|
+
export { resolveFileOwnership } from './ownership-resolver.js';
|
|
4
|
+
import type { SpecDecomposeResult } from '../../types/spec-decomposer.js';
|
|
5
|
+
/**
|
|
6
|
+
* Main entry point: decompose a spec into parallelizable agent tasks.
|
|
7
|
+
*
|
|
8
|
+
* @param specPath Absolute path to the spec's spec.md file.
|
|
9
|
+
* @param technicalPath Absolute path to the spec's technical.md file.
|
|
10
|
+
* @param specId Spec identifier (e.g. "SPEC-042").
|
|
11
|
+
* @param maxTasks Maximum number of tasks to generate (default: 5).
|
|
12
|
+
*/
|
|
13
|
+
export declare function decomposeSpec(specPath: string, technicalPath: string, specId: string, maxTasks?: number): Promise<SpecDecomposeResult>;
|
|
14
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/engine/spec-decomposer/index.ts"],"names":[],"mappings":"AAEA,OAAO,EACL,WAAW,EACX,sBAAsB,EACtB,0BAA0B,EAC1B,yBAAyB,GAC1B,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,eAAe,EAAE,sBAAsB,EAAE,MAAM,kBAAkB,CAAC;AAC3E,OAAO,EAAE,oBAAoB,EAAE,MAAM,yBAAyB,CAAC;AAK/D,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,gCAAgC,CAAC;AAK1E;;;;;;;GAOG;AACH,wBAAsB,aAAa,CACjC,QAAQ,EAAE,MAAM,EAChB,aAAa,EAAE,MAAM,EACrB,MAAM,EAAE,MAAM,EACd,QAAQ,GAAE,MAA0B,GACnC,OAAO,CAAC,mBAAmB,CAAC,CAwC9B"}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
// engine/spec-decomposer/index.ts — Barrel export + main decomposeSpec() (SPEC-157)
|
|
2
|
+
export { analyzeSpec, groupCriteriaIntoUnits, extractCriteriaFromContent, extractFilesFromTechnical, } from './analyzer.js';
|
|
3
|
+
export { mapUnitsToFiles, deduplicateMappedFiles } from './file-mapper.js';
|
|
4
|
+
export { resolveFileOwnership } from './ownership-resolver.js';
|
|
5
|
+
import { analyzeSpec } from './analyzer.js';
|
|
6
|
+
import { mapUnitsToFiles, deduplicateMappedFiles } from './file-mapper.js';
|
|
7
|
+
import { resolveFileOwnership } from './ownership-resolver.js';
|
|
8
|
+
/** Default maximum number of agent tasks to generate. */
|
|
9
|
+
const DEFAULT_MAX_TASKS = 5;
|
|
10
|
+
/**
|
|
11
|
+
* Main entry point: decompose a spec into parallelizable agent tasks.
|
|
12
|
+
*
|
|
13
|
+
* @param specPath Absolute path to the spec's spec.md file.
|
|
14
|
+
* @param technicalPath Absolute path to the spec's technical.md file.
|
|
15
|
+
* @param specId Spec identifier (e.g. "SPEC-042").
|
|
16
|
+
* @param maxTasks Maximum number of tasks to generate (default: 5).
|
|
17
|
+
*/
|
|
18
|
+
export async function decomposeSpec(specPath, technicalPath, specId, maxTasks = DEFAULT_MAX_TASKS) {
|
|
19
|
+
const clampedMax = Math.max(1, Math.min(maxTasks, 20));
|
|
20
|
+
// Step 1: Analyze spec content → raw work units
|
|
21
|
+
const workUnits = await analyzeSpec(specPath, technicalPath, clampedMax);
|
|
22
|
+
// Step 2: Map each work unit to concrete file paths
|
|
23
|
+
const allFiles = workUnits.flatMap((u) => u.suggestedFiles);
|
|
24
|
+
const rawMapped = mapUnitsToFiles(workUnits, allFiles);
|
|
25
|
+
const mapped = deduplicateMappedFiles(rawMapped);
|
|
26
|
+
// Step 3: Resolve file ownership conflicts + build tasks
|
|
27
|
+
const { tasks, fileOwnership, conflicts, executionPhases } = resolveFileOwnership(mapped);
|
|
28
|
+
// Step 4: Build warnings
|
|
29
|
+
const warnings = [];
|
|
30
|
+
for (const task of tasks) {
|
|
31
|
+
if (task.ownedFiles.length === 0) {
|
|
32
|
+
warnings.push(`Task "${task.id}" has no owned files — it may be too abstract.`);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
if (tasks.length === 1) {
|
|
36
|
+
warnings.push('Only one task was generated — the spec may be too small for parallel execution.');
|
|
37
|
+
}
|
|
38
|
+
const orchestrationReady = tasks.length > 0 && warnings.filter((w) => w.includes('no owned')).length === 0;
|
|
39
|
+
return {
|
|
40
|
+
specId,
|
|
41
|
+
taskCount: tasks.length,
|
|
42
|
+
tasks,
|
|
43
|
+
fileOwnership,
|
|
44
|
+
conflicts,
|
|
45
|
+
executionPhases,
|
|
46
|
+
warnings,
|
|
47
|
+
orchestrationReady,
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/engine/spec-decomposer/index.ts"],"names":[],"mappings":"AAAA,oFAAoF;AAEpF,OAAO,EACL,WAAW,EACX,sBAAsB,EACtB,0BAA0B,EAC1B,yBAAyB,GAC1B,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,eAAe,EAAE,sBAAsB,EAAE,MAAM,kBAAkB,CAAC;AAC3E,OAAO,EAAE,oBAAoB,EAAE,MAAM,yBAAyB,CAAC;AAE/D,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAC5C,OAAO,EAAE,eAAe,EAAE,sBAAsB,EAAE,MAAM,kBAAkB,CAAC;AAC3E,OAAO,EAAE,oBAAoB,EAAE,MAAM,yBAAyB,CAAC;AAG/D,yDAAyD;AACzD,MAAM,iBAAiB,GAAG,CAAC,CAAC;AAE5B;;;;;;;GAOG;AACH,MAAM,CAAC,KAAK,UAAU,aAAa,CACjC,QAAgB,EAChB,aAAqB,EACrB,MAAc,EACd,WAAmB,iBAAiB;IAEpC,MAAM,UAAU,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC,CAAC;IAEvD,gDAAgD;IAChD,MAAM,SAAS,GAAG,MAAM,WAAW,CAAC,QAAQ,EAAE,aAAa,EAAE,UAAU,CAAC,CAAC;IAEzE,oDAAoD;IACpD,MAAM,QAAQ,GAAG,SAAS,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,cAAc,CAAC,CAAC;IAC5D,MAAM,SAAS,GAAG,eAAe,CAAC,SAAS,EAAE,QAAQ,CAAC,CAAC;IACvD,MAAM,MAAM,GAAG,sBAAsB,CAAC,SAAS,CAAC,CAAC;IAEjD,yDAAyD;IACzD,MAAM,EAAE,KAAK,EAAE,aAAa,EAAE,SAAS,EAAE,eAAe,EAAE,GAAG,oBAAoB,CAAC,MAAM,CAAC,CAAC;IAE1F,yBAAyB;IACzB,MAAM,QAAQ,GAAa,EAAE,CAAC;IAC9B,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,IAAI,IAAI,CAAC,UAAU,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACjC,QAAQ,CAAC,IAAI,CAAC,SAAS,IAAI,CAAC,EAAE,gDAAgD,CAAC,CAAC;QAClF,CAAC;IACH,CAAC;IACD,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACvB,QAAQ,CAAC,IAAI,CACX,iFAAiF,CAClF,CAAC;IACJ,CAAC;IAED,MAAM,kBAAkB,GACtB,KAAK,CAAC,MAAM,GAAG,CAAC,IAAI,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,UAAU,CAAC,CAAC,CAAC,MAAM,KAAK,CAAC,CAAC;IAElF,OAAO;QACL,MAAM;QACN,SAAS,EAAE,KAAK,CAAC,MAAM;QACvB,KAAK;QACL,aAAa;QACb,SAAS;QACT,eAAe;QACf,QAAQ;QACR,kBAAkB;KACnB,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { MappedUnit, OwnershipResolutionResult } from '../../types/spec-decomposer.js';
|
|
2
|
+
/**
|
|
3
|
+
* Resolve file ownership and produce final AgentTask list, FileOwnership records,
|
|
4
|
+
* detected conflicts, and execution phases.
|
|
5
|
+
*/
|
|
6
|
+
export declare function resolveFileOwnership(units: MappedUnit[]): OwnershipResolutionResult;
|
|
7
|
+
//# sourceMappingURL=ownership-resolver.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ownership-resolver.d.ts","sourceRoot":"","sources":["../../../src/engine/spec-decomposer/ownership-resolver.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EACV,UAAU,EAKV,yBAAyB,EAC1B,MAAM,gCAAgC,CAAC;AAiIxC;;;GAGG;AACH,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,UAAU,EAAE,GAAG,yBAAyB,CA2DnF"}
|
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
// engine/spec-decomposer/ownership-resolver.ts — Resolve file ownership conflicts (SPEC-157)
|
|
2
|
+
// Ensures no two agent tasks claim the same file. When conflicts exist, the task
|
|
3
|
+
// with the highest file count wins ownership; other tasks receive a dependency instead.
|
|
4
|
+
// ---------------------------------------------------------------------------
|
|
5
|
+
// Conflict detection
|
|
6
|
+
// ---------------------------------------------------------------------------
|
|
7
|
+
/**
|
|
8
|
+
* Find files claimed by more than one mapped unit.
|
|
9
|
+
* Returns a map of filePath → unitIds that claim it.
|
|
10
|
+
*/
|
|
11
|
+
function detectConflicts(units) {
|
|
12
|
+
const fileToUnits = new Map();
|
|
13
|
+
for (const unit of units) {
|
|
14
|
+
for (const file of unit.files) {
|
|
15
|
+
const existing = fileToUnits.get(file) ?? [];
|
|
16
|
+
existing.push(unit.id);
|
|
17
|
+
fileToUnits.set(file, existing);
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
// Keep only files with >1 claimant
|
|
21
|
+
const conflicts = new Map();
|
|
22
|
+
for (const [file, unitIds] of fileToUnits) {
|
|
23
|
+
if (unitIds.length > 1) {
|
|
24
|
+
conflicts.set(file, unitIds);
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
return conflicts;
|
|
28
|
+
}
|
|
29
|
+
// ---------------------------------------------------------------------------
|
|
30
|
+
// Ownership resolution
|
|
31
|
+
// ---------------------------------------------------------------------------
|
|
32
|
+
/**
|
|
33
|
+
* Resolve ownership conflicts by awarding each contested file to the unit with
|
|
34
|
+
* the most files (primary owner) and removing it from the others.
|
|
35
|
+
* Returns a clean map of unitId → Set<filePath>.
|
|
36
|
+
*/
|
|
37
|
+
function resolveOwnership(units, conflicts) {
|
|
38
|
+
// Start: each unit owns all its files
|
|
39
|
+
const ownership = new Map(units.map((u) => [u.id, new Set(u.files)]));
|
|
40
|
+
for (const [file, claimantIds] of conflicts) {
|
|
41
|
+
// Primary owner = unit with most files (acts as heaviest dependency)
|
|
42
|
+
const sorted = [...claimantIds].sort((a, b) => {
|
|
43
|
+
const aSize = ownership.get(a)?.size ?? 0;
|
|
44
|
+
const bSize = ownership.get(b)?.size ?? 0;
|
|
45
|
+
return bSize - aSize;
|
|
46
|
+
});
|
|
47
|
+
const winner = sorted[0];
|
|
48
|
+
if (!winner) {
|
|
49
|
+
continue;
|
|
50
|
+
}
|
|
51
|
+
// Remove file from all losers
|
|
52
|
+
for (const loserId of sorted.slice(1)) {
|
|
53
|
+
ownership.get(loserId)?.delete(file);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
return ownership;
|
|
57
|
+
}
|
|
58
|
+
// ---------------------------------------------------------------------------
|
|
59
|
+
// Execution phase planning
|
|
60
|
+
// ---------------------------------------------------------------------------
|
|
61
|
+
/**
|
|
62
|
+
* Assign tasks to execution phases.
|
|
63
|
+
* Tasks with no dependencies → phase 1 (parallel).
|
|
64
|
+
* Tasks with dependencies → subsequent phases.
|
|
65
|
+
*/
|
|
66
|
+
function buildExecutionPhases(tasks) {
|
|
67
|
+
if (tasks.length === 0) {
|
|
68
|
+
return [];
|
|
69
|
+
}
|
|
70
|
+
const phases = [];
|
|
71
|
+
const placed = new Set();
|
|
72
|
+
let remaining = [...tasks];
|
|
73
|
+
while (remaining.length > 0) {
|
|
74
|
+
const phaseNumber = phases.length + 1;
|
|
75
|
+
// Tasks whose dependencies are all placed
|
|
76
|
+
const ready = remaining.filter((t) => t.dependencies.every((dep) => placed.has(dep)));
|
|
77
|
+
if (ready.length === 0) {
|
|
78
|
+
// Circular dependency safety: place everything left in one phase
|
|
79
|
+
const ids = remaining.map((t) => t.id);
|
|
80
|
+
phases.push({
|
|
81
|
+
phase: phaseNumber,
|
|
82
|
+
taskIds: ids,
|
|
83
|
+
reason: 'Remaining tasks (possible circular dependency detected)',
|
|
84
|
+
});
|
|
85
|
+
break;
|
|
86
|
+
}
|
|
87
|
+
const reason = ready.length === 1
|
|
88
|
+
? `Single task with all dependencies satisfied`
|
|
89
|
+
: `${String(ready.length)} tasks with no file conflicts — run in parallel`;
|
|
90
|
+
phases.push({
|
|
91
|
+
phase: phaseNumber,
|
|
92
|
+
taskIds: ready.map((t) => t.id),
|
|
93
|
+
reason,
|
|
94
|
+
});
|
|
95
|
+
for (const t of ready) {
|
|
96
|
+
placed.add(t.id);
|
|
97
|
+
}
|
|
98
|
+
remaining = remaining.filter((t) => !placed.has(t.id));
|
|
99
|
+
}
|
|
100
|
+
return phases;
|
|
101
|
+
}
|
|
102
|
+
// ---------------------------------------------------------------------------
|
|
103
|
+
// Public API
|
|
104
|
+
// ---------------------------------------------------------------------------
|
|
105
|
+
/**
|
|
106
|
+
* Resolve file ownership and produce final AgentTask list, FileOwnership records,
|
|
107
|
+
* detected conflicts, and execution phases.
|
|
108
|
+
*/
|
|
109
|
+
export function resolveFileOwnership(units) {
|
|
110
|
+
const rawConflicts = detectConflicts(units);
|
|
111
|
+
const ownershipMap = resolveOwnership(units, rawConflicts);
|
|
112
|
+
// Build dependency edges: if unit B lost a file to unit A, B depends on A
|
|
113
|
+
const dependencyEdges = new Map();
|
|
114
|
+
for (const unit of units) {
|
|
115
|
+
dependencyEdges.set(unit.id, new Set());
|
|
116
|
+
}
|
|
117
|
+
const resolvedConflicts = [];
|
|
118
|
+
for (const [file, claimantIds] of rawConflicts) {
|
|
119
|
+
// Winner is the one that still owns the file after resolution
|
|
120
|
+
const winner = claimantIds.find((id) => ownershipMap.get(id)?.has(file));
|
|
121
|
+
if (!winner) {
|
|
122
|
+
continue;
|
|
123
|
+
}
|
|
124
|
+
const losers = claimantIds.filter((id) => id !== winner);
|
|
125
|
+
for (const loser of losers) {
|
|
126
|
+
dependencyEdges.get(loser)?.add(winner);
|
|
127
|
+
}
|
|
128
|
+
resolvedConflicts.push({
|
|
129
|
+
filePath: file,
|
|
130
|
+
conflictingTaskIds: claimantIds,
|
|
131
|
+
resolution: `Ownership awarded to ${winner}; ${losers.join(', ')} will depend on it.`,
|
|
132
|
+
});
|
|
133
|
+
}
|
|
134
|
+
// Build AgentTask array
|
|
135
|
+
const tasks = units.map((unit) => {
|
|
136
|
+
const ownedFiles = [...(ownershipMap.get(unit.id) ?? [])].sort();
|
|
137
|
+
const dependencies = [...(dependencyEdges.get(unit.id) ?? [])].sort();
|
|
138
|
+
// A task can run in parallel if it has no dependencies
|
|
139
|
+
const canRunParallel = dependencies.length === 0;
|
|
140
|
+
return {
|
|
141
|
+
id: unit.id,
|
|
142
|
+
title: unit.title,
|
|
143
|
+
description: buildDescription(unit, ownedFiles),
|
|
144
|
+
criteria: unit.criteria,
|
|
145
|
+
ownedFiles,
|
|
146
|
+
dependencies,
|
|
147
|
+
recommendedModel: unit.recommendedModel,
|
|
148
|
+
estimatedHours: unit.estimatedHours,
|
|
149
|
+
canRunParallel,
|
|
150
|
+
};
|
|
151
|
+
});
|
|
152
|
+
// Build FileOwnership records
|
|
153
|
+
const fileOwnership = tasks.flatMap((task) => task.ownedFiles.map((filePath) => ({ filePath, taskId: task.id })));
|
|
154
|
+
const executionPhases = buildExecutionPhases(tasks);
|
|
155
|
+
return { tasks, fileOwnership, conflicts: resolvedConflicts, executionPhases };
|
|
156
|
+
}
|
|
157
|
+
// ---------------------------------------------------------------------------
|
|
158
|
+
// Helpers
|
|
159
|
+
// ---------------------------------------------------------------------------
|
|
160
|
+
function buildDescription(unit, ownedFiles) {
|
|
161
|
+
const criteriaLines = unit.criteria.length > 0
|
|
162
|
+
? `\nAcceptance criteria:\n${unit.criteria.map((c) => `- ${c}`).join('\n')}`
|
|
163
|
+
: '';
|
|
164
|
+
const fileLines = ownedFiles.length > 0
|
|
165
|
+
? `\nOwned files (exclusive):\n${ownedFiles.map((f) => `- ${f}`).join('\n')}`
|
|
166
|
+
: '';
|
|
167
|
+
return `Implement ${unit.title}.${criteriaLines}${fileLines}`;
|
|
168
|
+
}
|
|
169
|
+
//# sourceMappingURL=ownership-resolver.js.map
|