@planu/cli 0.24.0 → 0.25.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/ai-model-pricing.json +81 -0
- package/dist/config/framework-registry/csharp-aspnet.json +67 -0
- package/dist/config/framework-registry/dart-flutter.json +61 -0
- package/dist/config/framework-registry/go-gin.json +62 -0
- package/dist/config/framework-registry/index.json +164 -0
- package/dist/config/framework-registry/java-springboot.json +67 -0
- package/dist/config/framework-registry/php-laravel.json +67 -0
- package/dist/config/framework-registry/python-django.json +72 -0
- package/dist/config/framework-registry/python-fastapi.json +72 -0
- package/dist/config/framework-registry/ruby-rails.json +67 -0
- package/dist/config/framework-registry/rust-actix.json +61 -0
- package/dist/config/framework-registry/swift-swiftui.json +67 -0
- package/dist/config/framework-registry/typescript-angular.json +67 -0
- package/dist/config/framework-registry/typescript-astro.json +61 -0
- package/dist/config/framework-registry/typescript-express.json +67 -0
- package/dist/config/framework-registry/typescript-nestjs.json +62 -0
- package/dist/config/framework-registry/typescript-nextjs.json +82 -0
- package/dist/config/framework-registry/typescript-nuxt.json +67 -0
- package/dist/config/framework-registry/typescript-react.json +77 -0
- package/dist/config/framework-registry/typescript-remix.json +61 -0
- package/dist/config/framework-registry/typescript-sveltekit.json +67 -0
- package/dist/config/framework-registry/typescript-vue.json +72 -0
- package/dist/config/license-plans.json +23 -3
- package/dist/engine/agile-config-builder.d.ts.map +1 -1
- package/dist/engine/agile-config-builder.js +3 -0
- package/dist/engine/agile-config-builder.js.map +1 -1
- package/dist/engine/ai-cost-estimator/core.d.ts +8 -0
- package/dist/engine/ai-cost-estimator/core.d.ts.map +1 -0
- package/dist/engine/ai-cost-estimator/core.js +257 -0
- package/dist/engine/ai-cost-estimator/core.js.map +1 -0
- package/dist/engine/ai-cost-estimator/index.d.ts +4 -0
- package/dist/engine/ai-cost-estimator/index.d.ts.map +1 -0
- package/dist/engine/ai-cost-estimator/index.js +5 -0
- package/dist/engine/ai-cost-estimator/index.js.map +1 -0
- package/dist/engine/ai-cost-estimator/model-pricing.d.ts +31 -0
- package/dist/engine/ai-cost-estimator/model-pricing.d.ts.map +1 -0
- package/dist/engine/ai-cost-estimator/model-pricing.js +96 -0
- package/dist/engine/ai-cost-estimator/model-pricing.js.map +1 -0
- package/dist/engine/ai-cost-estimator/token-estimator.d.ts +37 -0
- package/dist/engine/ai-cost-estimator/token-estimator.d.ts.map +1 -0
- package/dist/engine/ai-cost-estimator/token-estimator.js +194 -0
- package/dist/engine/ai-cost-estimator/token-estimator.js.map +1 -0
- package/dist/engine/ci-generator/context-builders.d.ts +4 -0
- package/dist/engine/ci-generator/context-builders.d.ts.map +1 -0
- package/dist/engine/ci-generator/context-builders.js +129 -0
- package/dist/engine/ci-generator/context-builders.js.map +1 -0
- package/dist/engine/ci-generator/index.d.ts +7 -0
- package/dist/engine/ci-generator/index.d.ts.map +1 -0
- package/dist/engine/ci-generator/index.js +44 -0
- package/dist/engine/ci-generator/index.js.map +1 -0
- package/dist/engine/ci-generator/stack-detector.d.ts +21 -0
- package/dist/engine/ci-generator/stack-detector.d.ts.map +1 -0
- package/dist/engine/ci-generator/stack-detector.js +203 -0
- package/dist/engine/ci-generator/stack-detector.js.map +1 -0
- package/dist/engine/ci-generator/yaml-builder.d.ts +8 -0
- package/dist/engine/ci-generator/yaml-builder.d.ts.map +1 -0
- package/dist/engine/ci-generator/yaml-builder.js +285 -0
- package/dist/engine/ci-generator/yaml-builder.js.map +1 -0
- package/dist/engine/dashboard/data-loader.d.ts +21 -0
- package/dist/engine/dashboard/data-loader.d.ts.map +1 -0
- package/dist/engine/dashboard/data-loader.js +196 -0
- package/dist/engine/dashboard/data-loader.js.map +1 -0
- package/dist/engine/dashboard/index.d.ts +5 -0
- package/dist/engine/dashboard/index.d.ts.map +1 -0
- package/dist/engine/dashboard/index.js +6 -0
- package/dist/engine/dashboard/index.js.map +1 -0
- package/dist/engine/dashboard/routes.d.ts +4 -0
- package/dist/engine/dashboard/routes.d.ts.map +1 -0
- package/dist/engine/dashboard/routes.js +120 -0
- package/dist/engine/dashboard/routes.js.map +1 -0
- package/dist/engine/dashboard/server.d.ts +14 -0
- package/dist/engine/dashboard/server.d.ts.map +1 -0
- package/dist/engine/dashboard/server.js +88 -0
- package/dist/engine/dashboard/server.js.map +1 -0
- package/dist/engine/dashboard/templates-layout.d.ts +11 -0
- package/dist/engine/dashboard/templates-layout.d.ts.map +1 -0
- package/dist/engine/dashboard/templates-layout.js +305 -0
- package/dist/engine/dashboard/templates-layout.js.map +1 -0
- package/dist/engine/dashboard/templates-project.d.ts +10 -0
- package/dist/engine/dashboard/templates-project.d.ts.map +1 -0
- package/dist/engine/dashboard/templates-project.js +163 -0
- package/dist/engine/dashboard/templates-project.js.map +1 -0
- package/dist/engine/dashboard/templates.d.ts +3 -0
- package/dist/engine/dashboard/templates.d.ts.map +1 -0
- package/dist/engine/dashboard/templates.js +4 -0
- package/dist/engine/dashboard/templates.js.map +1 -0
- package/dist/engine/focus-tracker.d.ts.map +1 -1
- package/dist/engine/focus-tracker.js +1 -0
- package/dist/engine/focus-tracker.js.map +1 -1
- package/dist/engine/hooks/core.d.ts +26 -0
- package/dist/engine/hooks/core.d.ts.map +1 -0
- package/dist/engine/hooks/core.js +164 -0
- package/dist/engine/hooks/core.js.map +1 -0
- package/dist/engine/hooks/git-hook-generator.d.ts +14 -0
- package/dist/engine/hooks/git-hook-generator.d.ts.map +1 -0
- package/dist/engine/hooks/git-hook-generator.js +119 -0
- package/dist/engine/hooks/git-hook-generator.js.map +1 -0
- package/dist/engine/hooks/index.d.ts +5 -0
- package/dist/engine/hooks/index.d.ts.map +1 -0
- package/dist/engine/hooks/index.js +6 -0
- package/dist/engine/hooks/index.js.map +1 -0
- package/dist/engine/hooks/templates.d.ts +14 -0
- package/dist/engine/hooks/templates.d.ts.map +1 -0
- package/dist/engine/hooks/templates.js +138 -0
- package/dist/engine/hooks/templates.js.map +1 -0
- package/dist/engine/hooks/triggers.d.ts +27 -0
- package/dist/engine/hooks/triggers.d.ts.map +1 -0
- package/dist/engine/hooks/triggers.js +104 -0
- package/dist/engine/hooks/triggers.js.map +1 -0
- package/dist/engine/registry/core.d.ts +32 -0
- package/dist/engine/registry/core.d.ts.map +1 -0
- package/dist/engine/registry/core.js +85 -0
- package/dist/engine/registry/core.js.map +1 -0
- package/dist/engine/registry/index.d.ts +6 -0
- package/dist/engine/registry/index.d.ts.map +1 -0
- package/dist/engine/registry/index.js +8 -0
- package/dist/engine/registry/index.js.map +1 -0
- package/dist/engine/registry/loader.d.ts +18 -0
- package/dist/engine/registry/loader.d.ts.map +1 -0
- package/dist/engine/registry/loader.js +81 -0
- package/dist/engine/registry/loader.js.map +1 -0
- package/dist/engine/registry/matcher.d.ts +19 -0
- package/dist/engine/registry/matcher.d.ts.map +1 -0
- package/dist/engine/registry/matcher.js +150 -0
- package/dist/engine/registry/matcher.js.map +1 -0
- package/dist/engine/registry/reporter.d.ts +10 -0
- package/dist/engine/registry/reporter.d.ts.map +1 -0
- package/dist/engine/registry/reporter.js +132 -0
- package/dist/engine/registry/reporter.js.map +1 -0
- package/dist/engine/registry/validator.d.ts +17 -0
- package/dist/engine/registry/validator.d.ts.map +1 -0
- package/dist/engine/registry/validator.js +103 -0
- package/dist/engine/registry/validator.js.map +1 -0
- package/dist/engine/spec-changelog/core.d.ts +16 -0
- package/dist/engine/spec-changelog/core.d.ts.map +1 -0
- package/dist/engine/spec-changelog/core.js +175 -0
- package/dist/engine/spec-changelog/core.js.map +1 -0
- package/dist/engine/spec-changelog/diff.d.ts +18 -0
- package/dist/engine/spec-changelog/diff.d.ts.map +1 -0
- package/dist/engine/spec-changelog/diff.js +116 -0
- package/dist/engine/spec-changelog/diff.js.map +1 -0
- package/dist/engine/spec-changelog/index.d.ts +3 -0
- package/dist/engine/spec-changelog/index.d.ts.map +1 -0
- package/dist/engine/spec-changelog/index.js +4 -0
- package/dist/engine/spec-changelog/index.js.map +1 -0
- package/dist/engine/spec-coverage/core.d.ts +14 -0
- package/dist/engine/spec-coverage/core.d.ts.map +1 -0
- package/dist/engine/spec-coverage/core.js +132 -0
- package/dist/engine/spec-coverage/core.js.map +1 -0
- package/dist/engine/spec-coverage/criteria-mapper.d.ts +18 -0
- package/dist/engine/spec-coverage/criteria-mapper.d.ts.map +1 -0
- package/dist/engine/spec-coverage/criteria-mapper.js +306 -0
- package/dist/engine/spec-coverage/criteria-mapper.js.map +1 -0
- package/dist/engine/spec-coverage/index.d.ts +4 -0
- package/dist/engine/spec-coverage/index.d.ts.map +1 -0
- package/dist/engine/spec-coverage/index.js +5 -0
- package/dist/engine/spec-coverage/index.js.map +1 -0
- package/dist/engine/spec-coverage/test-finder.d.ts +17 -0
- package/dist/engine/spec-coverage/test-finder.d.ts.map +1 -0
- package/dist/engine/spec-coverage/test-finder.js +250 -0
- package/dist/engine/spec-coverage/test-finder.js.map +1 -0
- package/dist/engine/spec-templates/catalog-extra.d.ts +4 -0
- package/dist/engine/spec-templates/catalog-extra.d.ts.map +1 -0
- package/dist/engine/spec-templates/catalog-extra.js +367 -0
- package/dist/engine/spec-templates/catalog-extra.js.map +1 -0
- package/dist/engine/spec-templates/catalog.d.ts +4 -0
- package/dist/engine/spec-templates/catalog.d.ts.map +1 -0
- package/dist/engine/spec-templates/catalog.js +386 -0
- package/dist/engine/spec-templates/catalog.js.map +1 -0
- package/dist/engine/spec-templates/index.d.ts +4 -0
- package/dist/engine/spec-templates/index.d.ts.map +1 -0
- package/dist/engine/spec-templates/index.js +5 -0
- package/dist/engine/spec-templates/index.js.map +1 -0
- package/dist/engine/spec-templates/query.d.ts +14 -0
- package/dist/engine/spec-templates/query.d.ts.map +1 -0
- package/dist/engine/spec-templates/query.js +56 -0
- package/dist/engine/spec-templates/query.js.map +1 -0
- package/dist/engine/spec-templates/renderer.d.ts +19 -0
- package/dist/engine/spec-templates/renderer.d.ts.map +1 -0
- package/dist/engine/spec-templates/renderer.js +45 -0
- package/dist/engine/spec-templates/renderer.js.map +1 -0
- package/dist/engine/usage-tracker/trial.d.ts +4 -4
- package/dist/engine/usage-tracker/trial.d.ts.map +1 -1
- package/dist/engine/usage-tracker/trial.js +4 -4
- package/dist/engine/usage-tracker/trial.js.map +1 -1
- package/dist/engine/webhook/event-handlers.d.ts +25 -0
- package/dist/engine/webhook/event-handlers.d.ts.map +1 -0
- package/dist/engine/webhook/event-handlers.js +89 -0
- package/dist/engine/webhook/event-handlers.js.map +1 -0
- package/dist/engine/webhook/index.d.ts +4 -0
- package/dist/engine/webhook/index.d.ts.map +1 -0
- package/dist/engine/webhook/index.js +5 -0
- package/dist/engine/webhook/index.js.map +1 -0
- package/dist/engine/webhook/server.d.ts +18 -0
- package/dist/engine/webhook/server.d.ts.map +1 -0
- package/dist/engine/webhook/server.js +187 -0
- package/dist/engine/webhook/server.js.map +1 -0
- package/dist/engine/webhook/signature.d.ts +16 -0
- package/dist/engine/webhook/signature.d.ts.map +1 -0
- package/dist/engine/webhook/signature.js +49 -0
- package/dist/engine/webhook/signature.js.map +1 -0
- package/dist/index.js +18 -0
- package/dist/index.js.map +1 -1
- package/dist/storage/hooks-store.d.ts +34 -0
- package/dist/storage/hooks-store.d.ts.map +1 -0
- package/dist/storage/hooks-store.js +128 -0
- package/dist/storage/hooks-store.js.map +1 -0
- package/dist/storage/index.d.ts +1 -0
- package/dist/storage/index.d.ts.map +1 -1
- package/dist/storage/index.js +1 -0
- package/dist/storage/index.js.map +1 -1
- package/dist/tools/check-spec-accuracy.d.ts +7 -0
- package/dist/tools/check-spec-accuracy.d.ts.map +1 -0
- package/dist/tools/check-spec-accuracy.js +28 -0
- package/dist/tools/check-spec-accuracy.js.map +1 -0
- package/dist/tools/ci-generator.d.ts +7 -0
- package/dist/tools/ci-generator.d.ts.map +1 -0
- package/dist/tools/ci-generator.js +49 -0
- package/dist/tools/ci-generator.js.map +1 -0
- package/dist/tools/create-spec.d.ts.map +1 -1
- package/dist/tools/create-spec.js +4 -0
- package/dist/tools/create-spec.js.map +1 -1
- package/dist/tools/dashboard.d.ts +6 -0
- package/dist/tools/dashboard.d.ts.map +1 -0
- package/dist/tools/dashboard.js +48 -0
- package/dist/tools/dashboard.js.map +1 -0
- package/dist/tools/detect-drift.d.ts.map +1 -1
- package/dist/tools/detect-drift.js +6 -0
- package/dist/tools/detect-drift.js.map +1 -1
- package/dist/tools/estimate-ai-cost.d.ts +8 -0
- package/dist/tools/estimate-ai-cost.d.ts.map +1 -0
- package/dist/tools/estimate-ai-cost.js +29 -0
- package/dist/tools/estimate-ai-cost.js.map +1 -0
- package/dist/tools/list-specs.d.ts.map +1 -1
- package/dist/tools/list-specs.js +15 -0
- package/dist/tools/list-specs.js.map +1 -1
- package/dist/tools/manage-hooks.d.ts +5 -0
- package/dist/tools/manage-hooks.d.ts.map +1 -0
- package/dist/tools/manage-hooks.js +247 -0
- package/dist/tools/manage-hooks.js.map +1 -0
- package/dist/tools/reconcile-spec.d.ts.map +1 -1
- package/dist/tools/reconcile-spec.js +24 -0
- package/dist/tools/reconcile-spec.js.map +1 -1
- package/dist/tools/register-ai-cost-tools.d.ts +3 -0
- package/dist/tools/register-ai-cost-tools.d.ts.map +1 -0
- package/dist/tools/register-ai-cost-tools.js +25 -0
- package/dist/tools/register-ai-cost-tools.js.map +1 -0
- package/dist/tools/register-changelog-tools.d.ts +3 -0
- package/dist/tools/register-changelog-tools.d.ts.map +1 -0
- package/dist/tools/register-changelog-tools.js +23 -0
- package/dist/tools/register-changelog-tools.js.map +1 -0
- package/dist/tools/register-ci-tools.d.ts +3 -0
- package/dist/tools/register-ci-tools.d.ts.map +1 -0
- package/dist/tools/register-ci-tools.js +50 -0
- package/dist/tools/register-ci-tools.js.map +1 -0
- package/dist/tools/register-coverage-tools.d.ts +7 -0
- package/dist/tools/register-coverage-tools.d.ts.map +1 -0
- package/dist/tools/register-coverage-tools.js +27 -0
- package/dist/tools/register-coverage-tools.js.map +1 -0
- package/dist/tools/register-dashboard-tools.d.ts +3 -0
- package/dist/tools/register-dashboard-tools.d.ts.map +1 -0
- package/dist/tools/register-dashboard-tools.js +29 -0
- package/dist/tools/register-dashboard-tools.js.map +1 -0
- package/dist/tools/register-hooks-tools.d.ts +3 -0
- package/dist/tools/register-hooks-tools.d.ts.map +1 -0
- package/dist/tools/register-hooks-tools.js +107 -0
- package/dist/tools/register-hooks-tools.js.map +1 -0
- package/dist/tools/register-registry-tools.d.ts +3 -0
- package/dist/tools/register-registry-tools.d.ts.map +1 -0
- package/dist/tools/register-registry-tools.js +43 -0
- package/dist/tools/register-registry-tools.js.map +1 -0
- package/dist/tools/register-template-tools.d.ts +8 -0
- package/dist/tools/register-template-tools.d.ts.map +1 -0
- package/dist/tools/register-template-tools.js +71 -0
- package/dist/tools/register-template-tools.js.map +1 -0
- package/dist/tools/register-webhook-tools.d.ts +3 -0
- package/dist/tools/register-webhook-tools.d.ts.map +1 -0
- package/dist/tools/register-webhook-tools.js +49 -0
- package/dist/tools/register-webhook-tools.js.map +1 -0
- package/dist/tools/schemas/index.d.ts +1 -0
- package/dist/tools/schemas/index.d.ts.map +1 -1
- package/dist/tools/schemas/index.js +1 -0
- package/dist/tools/schemas/index.js.map +1 -1
- package/dist/tools/schemas/registry.d.ts +41 -0
- package/dist/tools/schemas/registry.d.ts.map +1 -0
- package/dist/tools/schemas/registry.js +62 -0
- package/dist/tools/schemas/registry.js.map +1 -0
- package/dist/tools/spec-coverage.d.ts +3 -0
- package/dist/tools/spec-coverage.d.ts.map +1 -0
- package/dist/tools/spec-coverage.js +176 -0
- package/dist/tools/spec-coverage.js.map +1 -0
- package/dist/tools/spec-history.d.ts +3 -0
- package/dist/tools/spec-history.d.ts.map +1 -0
- package/dist/tools/spec-history.js +67 -0
- package/dist/tools/spec-history.js.map +1 -0
- package/dist/tools/spec-templates.d.ts +10 -0
- package/dist/tools/spec-templates.d.ts.map +1 -0
- package/dist/tools/spec-templates.js +155 -0
- package/dist/tools/spec-templates.js.map +1 -0
- package/dist/tools/update-registry.d.ts +8 -0
- package/dist/tools/update-registry.d.ts.map +1 -0
- package/dist/tools/update-registry.js +53 -0
- package/dist/tools/update-registry.js.map +1 -0
- package/dist/tools/update-status.d.ts.map +1 -1
- package/dist/tools/update-status.js +24 -0
- package/dist/tools/update-status.js.map +1 -1
- package/dist/tools/webhook.d.ts +6 -0
- package/dist/tools/webhook.d.ts.map +1 -0
- package/dist/tools/webhook.js +150 -0
- package/dist/tools/webhook.js.map +1 -0
- package/dist/types/ai-cost.d.ts +98 -0
- package/dist/types/ai-cost.d.ts.map +1 -0
- package/dist/types/ai-cost.js +4 -0
- package/dist/types/ai-cost.js.map +1 -0
- package/dist/types/analysis.d.ts +64 -0
- package/dist/types/analysis.d.ts.map +1 -1
- package/dist/types/changelog.d.ts +49 -0
- package/dist/types/changelog.d.ts.map +1 -0
- package/dist/types/changelog.js +3 -0
- package/dist/types/changelog.js.map +1 -0
- package/dist/types/ci.d.ts +105 -0
- package/dist/types/ci.d.ts.map +1 -0
- package/dist/types/ci.js +3 -0
- package/dist/types/ci.js.map +1 -0
- package/dist/types/coverage.d.ts +95 -0
- package/dist/types/coverage.d.ts.map +1 -0
- package/dist/types/coverage.js +4 -0
- package/dist/types/coverage.js.map +1 -0
- package/dist/types/hooks.d.ts +139 -0
- package/dist/types/hooks.d.ts.map +1 -0
- package/dist/types/hooks.js +3 -0
- package/dist/types/hooks.js.map +1 -0
- package/dist/types/index.d.ts +8 -0
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/index.js +8 -0
- package/dist/types/index.js.map +1 -1
- package/dist/types/registry.d.ts +90 -0
- package/dist/types/registry.d.ts.map +1 -0
- package/dist/types/registry.js +5 -0
- package/dist/types/registry.js.map +1 -0
- package/dist/types/spec-templates.d.ts +87 -0
- package/dist/types/spec-templates.d.ts.map +1 -0
- package/dist/types/spec-templates.js +3 -0
- package/dist/types/spec-templates.js.map +1 -0
- package/dist/types/ui.d.ts +76 -0
- package/dist/types/ui.d.ts.map +1 -1
- package/dist/types/webhook.d.ts +62 -0
- package/dist/types/webhook.d.ts.map +1 -0
- package/dist/types/webhook.js +4 -0
- package/dist/types/webhook.js.map +1 -0
- package/package.json +1 -1
- package/src/config/ai-model-pricing.json +81 -0
- package/src/config/framework-registry/csharp-aspnet.json +67 -0
- package/src/config/framework-registry/dart-flutter.json +61 -0
- package/src/config/framework-registry/go-gin.json +62 -0
- package/src/config/framework-registry/index.json +164 -0
- package/src/config/framework-registry/java-springboot.json +67 -0
- package/src/config/framework-registry/php-laravel.json +67 -0
- package/src/config/framework-registry/python-django.json +72 -0
- package/src/config/framework-registry/python-fastapi.json +72 -0
- package/src/config/framework-registry/ruby-rails.json +67 -0
- package/src/config/framework-registry/rust-actix.json +61 -0
- package/src/config/framework-registry/swift-swiftui.json +67 -0
- package/src/config/framework-registry/typescript-angular.json +67 -0
- package/src/config/framework-registry/typescript-astro.json +61 -0
- package/src/config/framework-registry/typescript-express.json +67 -0
- package/src/config/framework-registry/typescript-nestjs.json +62 -0
- package/src/config/framework-registry/typescript-nextjs.json +82 -0
- package/src/config/framework-registry/typescript-nuxt.json +67 -0
- package/src/config/framework-registry/typescript-react.json +77 -0
- package/src/config/framework-registry/typescript-remix.json +61 -0
- package/src/config/framework-registry/typescript-sveltekit.json +67 -0
- package/src/config/framework-registry/typescript-vue.json +72 -0
- package/src/config/license-plans.json +23 -3
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
// engine/ai-cost-estimator/token-estimator.ts — Token count estimation logic.
|
|
2
|
+
// Calculates input tokens (spec + codebase + tools) and output tokens (code generation).
|
|
3
|
+
import { readFile, readdir, stat } from 'node:fs/promises';
|
|
4
|
+
import { join } from 'node:path';
|
|
5
|
+
// ---------------------------------------------------------------------------
|
|
6
|
+
// Constants (overridden by config)
|
|
7
|
+
// ---------------------------------------------------------------------------
|
|
8
|
+
const DEFAULT_TOOL_DEFINITIONS_TOKENS = 4000;
|
|
9
|
+
const DEFAULT_CHARS_PER_TOKEN = 3.5;
|
|
10
|
+
const DEFAULT_AVG_LOC_CHARS = 45;
|
|
11
|
+
const DEFAULT_LOC_PER_AC = 50;
|
|
12
|
+
// ---------------------------------------------------------------------------
|
|
13
|
+
// Language detection
|
|
14
|
+
// ---------------------------------------------------------------------------
|
|
15
|
+
const LANGUAGE_FILE_EXTENSIONS = {
|
|
16
|
+
typescript: ['.ts', '.tsx'],
|
|
17
|
+
javascript: ['.js', '.jsx', '.mjs', '.cjs'],
|
|
18
|
+
python: ['.py'],
|
|
19
|
+
go: ['.go'],
|
|
20
|
+
rust: ['.rs'],
|
|
21
|
+
java: ['.java'],
|
|
22
|
+
kotlin: ['.kt', '.kts'],
|
|
23
|
+
swift: ['.swift'],
|
|
24
|
+
ruby: ['.rb'],
|
|
25
|
+
php: ['.php'],
|
|
26
|
+
csharp: ['.cs'],
|
|
27
|
+
dart: ['.dart'],
|
|
28
|
+
};
|
|
29
|
+
const LANGUAGE_CONFIG_FILES = {
|
|
30
|
+
typescript: ['tsconfig.json', 'package.json'],
|
|
31
|
+
python: ['pyproject.toml', 'setup.cfg', 'setup.py', 'requirements.txt'],
|
|
32
|
+
go: ['go.mod'],
|
|
33
|
+
rust: ['Cargo.toml'],
|
|
34
|
+
java: ['pom.xml', 'build.gradle'],
|
|
35
|
+
kotlin: ['build.gradle.kts'],
|
|
36
|
+
swift: ['Package.swift'],
|
|
37
|
+
ruby: ['Gemfile'],
|
|
38
|
+
php: ['composer.json'],
|
|
39
|
+
csharp: ['.csproj'],
|
|
40
|
+
dart: ['pubspec.yaml'],
|
|
41
|
+
};
|
|
42
|
+
/**
|
|
43
|
+
* Detects the primary programming language of a project by checking config files.
|
|
44
|
+
* Falls back to scanning source file extensions.
|
|
45
|
+
*/
|
|
46
|
+
export async function detectProjectLanguage(projectPath) {
|
|
47
|
+
// Check config file markers first (most reliable)
|
|
48
|
+
for (const [lang, markers] of Object.entries(LANGUAGE_CONFIG_FILES)) {
|
|
49
|
+
for (const marker of markers) {
|
|
50
|
+
try {
|
|
51
|
+
await stat(join(projectPath, marker));
|
|
52
|
+
return lang;
|
|
53
|
+
}
|
|
54
|
+
catch {
|
|
55
|
+
// File does not exist, continue
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
return 'default';
|
|
60
|
+
}
|
|
61
|
+
// ---------------------------------------------------------------------------
|
|
62
|
+
// Codebase scanning
|
|
63
|
+
// ---------------------------------------------------------------------------
|
|
64
|
+
const MAX_SCAN_DEPTH = 5;
|
|
65
|
+
const EXCLUDED_DIRS = new Set(['node_modules', '.git', 'dist', 'build', '__pycache__', '.next']);
|
|
66
|
+
/** Recursively counts total characters in source files up to a given depth. */
|
|
67
|
+
async function countCodebaseChars(dirPath, depth) {
|
|
68
|
+
if (depth > MAX_SCAN_DEPTH) {
|
|
69
|
+
return 0;
|
|
70
|
+
}
|
|
71
|
+
let totalChars = 0;
|
|
72
|
+
let entries;
|
|
73
|
+
try {
|
|
74
|
+
entries = await readdir(dirPath, { withFileTypes: true, encoding: 'utf-8' });
|
|
75
|
+
}
|
|
76
|
+
catch {
|
|
77
|
+
return 0;
|
|
78
|
+
}
|
|
79
|
+
for (const entry of entries) {
|
|
80
|
+
const entryName = entry.name;
|
|
81
|
+
if (EXCLUDED_DIRS.has(entryName)) {
|
|
82
|
+
continue;
|
|
83
|
+
}
|
|
84
|
+
const fullPath = join(dirPath, entryName);
|
|
85
|
+
if (entry.isDirectory()) {
|
|
86
|
+
totalChars += await countCodebaseChars(fullPath, depth + 1);
|
|
87
|
+
}
|
|
88
|
+
else if (entry.isFile() && isSourceFile(entryName)) {
|
|
89
|
+
try {
|
|
90
|
+
const content = await readFile(fullPath, 'utf-8');
|
|
91
|
+
totalChars += content.length;
|
|
92
|
+
}
|
|
93
|
+
catch {
|
|
94
|
+
// Skip unreadable files
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
return totalChars;
|
|
99
|
+
}
|
|
100
|
+
/** Returns true if the file extension is a known source file type. */
|
|
101
|
+
function isSourceFile(filename) {
|
|
102
|
+
const ext = filename.slice(filename.lastIndexOf('.'));
|
|
103
|
+
const allExtensions = Object.values(LANGUAGE_FILE_EXTENSIONS).flat();
|
|
104
|
+
return allExtensions.includes(ext);
|
|
105
|
+
}
|
|
106
|
+
// ---------------------------------------------------------------------------
|
|
107
|
+
// Input token estimation
|
|
108
|
+
// ---------------------------------------------------------------------------
|
|
109
|
+
/**
|
|
110
|
+
* Estimates input tokens for an AI agent session based on three components:
|
|
111
|
+
* 1. Spec content (HU.md + FICHA-TECNICA.md)
|
|
112
|
+
* 2. Codebase context (if projectPath is provided)
|
|
113
|
+
* 3. MCP tool definitions overhead (fixed constant)
|
|
114
|
+
*/
|
|
115
|
+
export async function estimateInputTokens(specContent, projectPath, config) {
|
|
116
|
+
const charsPerToken = config.constants.charsPerToken || DEFAULT_CHARS_PER_TOKEN;
|
|
117
|
+
const toolDefinitionsTokens = config.constants.toolDefinitionsOverheadTokens || DEFAULT_TOOL_DEFINITIONS_TOKENS;
|
|
118
|
+
// 1. Spec content tokens
|
|
119
|
+
const specContentTokens = Math.ceil(specContent.length / charsPerToken);
|
|
120
|
+
// 2. Codebase context tokens (optional)
|
|
121
|
+
let codebaseContextTokens = 0;
|
|
122
|
+
if (projectPath) {
|
|
123
|
+
const codebaseChars = await countCodebaseChars(projectPath, 0);
|
|
124
|
+
codebaseContextTokens = Math.ceil(codebaseChars / charsPerToken);
|
|
125
|
+
}
|
|
126
|
+
const inputTokens = specContentTokens + codebaseContextTokens + toolDefinitionsTokens;
|
|
127
|
+
return {
|
|
128
|
+
inputTokens,
|
|
129
|
+
specContentTokens,
|
|
130
|
+
codebaseContextTokens,
|
|
131
|
+
toolDefinitionsTokens,
|
|
132
|
+
};
|
|
133
|
+
}
|
|
134
|
+
// ---------------------------------------------------------------------------
|
|
135
|
+
// Output token estimation
|
|
136
|
+
// ---------------------------------------------------------------------------
|
|
137
|
+
/**
|
|
138
|
+
* Estimates output tokens (code to be generated) for a spec.
|
|
139
|
+
*
|
|
140
|
+
* Priority:
|
|
141
|
+
* 1. Use LOC from existing estimate if available
|
|
142
|
+
* 2. Fallback: number of ACs × DEFAULT_LOC_PER_AC
|
|
143
|
+
* 3. Calibrate with usage.json average if available
|
|
144
|
+
*/
|
|
145
|
+
export function estimateOutputTokens(locToGenerate, language, config, usageAvgTokensPerCall) {
|
|
146
|
+
const avgLOCChars = config.constants.avgLOCChars || DEFAULT_AVG_LOC_CHARS;
|
|
147
|
+
// Look up the language token ratio from config
|
|
148
|
+
const ratioKey = language.toLowerCase();
|
|
149
|
+
const tokensPerChar = config.languageTokenRatios[ratioKey] ??
|
|
150
|
+
config.languageTokenRatios.default ??
|
|
151
|
+
DEFAULT_CHARS_PER_TOKEN;
|
|
152
|
+
// Base estimate: LOC × chars/LOC × tokens/char
|
|
153
|
+
let outputTokens = Math.ceil(locToGenerate * avgLOCChars * tokensPerChar);
|
|
154
|
+
// Calibrate with usage data if available
|
|
155
|
+
if (usageAvgTokensPerCall !== undefined && usageAvgTokensPerCall > 0) {
|
|
156
|
+
// Blend: 70% formula estimate, 30% historical calibration
|
|
157
|
+
outputTokens = Math.ceil(outputTokens * 0.7 + usageAvgTokensPerCall * 0.3);
|
|
158
|
+
}
|
|
159
|
+
return outputTokens;
|
|
160
|
+
}
|
|
161
|
+
/**
|
|
162
|
+
* Estimates LOC to generate based on the number of acceptance criteria.
|
|
163
|
+
* Used as a fallback when no existing estimate is available.
|
|
164
|
+
*/
|
|
165
|
+
export function estimateLocFromAcCount(acCount) {
|
|
166
|
+
return acCount * DEFAULT_LOC_PER_AC;
|
|
167
|
+
}
|
|
168
|
+
// ---------------------------------------------------------------------------
|
|
169
|
+
// Full token estimate
|
|
170
|
+
// ---------------------------------------------------------------------------
|
|
171
|
+
/**
|
|
172
|
+
* Produces a complete TokenEstimate for a spec.
|
|
173
|
+
*/
|
|
174
|
+
export async function buildTokenEstimate(specContent, locToGenerate, acCount, projectPath, config, usageAvgTokensPerCall) {
|
|
175
|
+
// Detect language for token ratio lookup
|
|
176
|
+
const language = projectPath ? await detectProjectLanguage(projectPath) : 'default';
|
|
177
|
+
// Estimate input components
|
|
178
|
+
const { inputTokens, specContentTokens, codebaseContextTokens, toolDefinitionsTokens } = await estimateInputTokens(specContent, projectPath, config);
|
|
179
|
+
// Use provided LOC or fallback to AC-based estimate
|
|
180
|
+
const effectiveLOC = locToGenerate > 0 ? locToGenerate : estimateLocFromAcCount(acCount);
|
|
181
|
+
// Estimate output tokens
|
|
182
|
+
const outputTokens = estimateOutputTokens(effectiveLOC, language, config, usageAvgTokensPerCall);
|
|
183
|
+
return {
|
|
184
|
+
inputTokens,
|
|
185
|
+
outputTokens,
|
|
186
|
+
specContentTokens,
|
|
187
|
+
codebaseContextTokens,
|
|
188
|
+
toolDefinitionsTokens,
|
|
189
|
+
locToGenerate: effectiveLOC,
|
|
190
|
+
language,
|
|
191
|
+
calibratedFromUsage: usageAvgTokensPerCall !== undefined && usageAvgTokensPerCall > 0,
|
|
192
|
+
};
|
|
193
|
+
}
|
|
194
|
+
//# sourceMappingURL=token-estimator.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"token-estimator.js","sourceRoot":"","sources":["../../../src/engine/ai-cost-estimator/token-estimator.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { CIEcosystem, CIStackContext } from '../../types/index.js';
|
|
2
|
+
/** Build a CIStackContext for the detected ecosystem. */
|
|
3
|
+
export declare function buildContextForEcosystem(ecosystem: CIEcosystem, projectPath: string, hasDocker: boolean): Promise<CIStackContext>;
|
|
4
|
+
//# sourceMappingURL=context-builders.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"context-builders.d.ts","sourceRoot":"","sources":["../../../src/engine/ci-generator/context-builders.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,WAAW,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AA6HxE,yDAAyD;AACzD,wBAAsB,wBAAwB,CAC5C,SAAS,EAAE,WAAW,EACtB,WAAW,EAAE,MAAM,EACnB,SAAS,EAAE,OAAO,GACjB,OAAO,CAAC,cAAc,CAAC,CA0BzB"}
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
// ci-generator/context-builders.ts — Build CIStackContext per ecosystem (SPEC-066)
|
|
2
|
+
import { detectNodePackageManager, detectNodeVersion, buildNodeCommands, detectPythonPackageManager, detectPythonVersion, detectGoVersion, detectRustChannel, detectJavaVersion, detectJavaBuildTool, } from './stack-detector.js';
|
|
3
|
+
/** Build context for Node.js/TypeScript projects. */
|
|
4
|
+
async function buildNodeContext(projectPath, hasDocker) {
|
|
5
|
+
const pm = await detectNodePackageManager(projectPath);
|
|
6
|
+
const nodeVersion = await detectNodeVersion(projectPath);
|
|
7
|
+
const cmds = buildNodeCommands(pm);
|
|
8
|
+
return {
|
|
9
|
+
ecosystem: 'nodejs',
|
|
10
|
+
language: 'typescript',
|
|
11
|
+
packageManager: pm,
|
|
12
|
+
testCommand: cmds.test,
|
|
13
|
+
lintCommand: cmds.lint,
|
|
14
|
+
buildCommand: cmds.build,
|
|
15
|
+
hasDocker,
|
|
16
|
+
nodeVersion,
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
/** Build context for Python projects. */
|
|
20
|
+
async function buildPythonContext(projectPath, hasDocker) {
|
|
21
|
+
const pm = await detectPythonPackageManager(projectPath);
|
|
22
|
+
const pythonVersion = await detectPythonVersion(projectPath);
|
|
23
|
+
const lintCmd = pm === 'uv' ? 'uv run ruff check .' : 'ruff check .';
|
|
24
|
+
const testCmd = pm === 'poetry' ? 'poetry run pytest' : pm === 'uv' ? 'uv run pytest' : 'pytest';
|
|
25
|
+
const buildCmd = pm === 'poetry' ? 'poetry build' : pm === 'uv' ? 'uv build' : 'python -m build';
|
|
26
|
+
return {
|
|
27
|
+
ecosystem: 'python',
|
|
28
|
+
language: 'python',
|
|
29
|
+
packageManager: pm,
|
|
30
|
+
testCommand: testCmd,
|
|
31
|
+
lintCommand: lintCmd,
|
|
32
|
+
buildCommand: buildCmd,
|
|
33
|
+
hasDocker,
|
|
34
|
+
pythonVersion,
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
/** Build context for JVM-based projects (Java/Kotlin). */
|
|
38
|
+
async function buildJvmContext(ecosystem, projectPath, hasDocker) {
|
|
39
|
+
const javaVersion = await detectJavaVersion(projectPath);
|
|
40
|
+
const javaBuildTool = await detectJavaBuildTool(projectPath);
|
|
41
|
+
const isMaven = javaBuildTool === 'maven';
|
|
42
|
+
return {
|
|
43
|
+
ecosystem,
|
|
44
|
+
language: ecosystem,
|
|
45
|
+
packageManager: javaBuildTool,
|
|
46
|
+
testCommand: isMaven ? 'mvn test' : './gradlew test',
|
|
47
|
+
lintCommand: isMaven ? 'mvn checkstyle:check' : './gradlew checkstyleMain',
|
|
48
|
+
buildCommand: isMaven ? 'mvn package -DskipTests' : './gradlew build -x test',
|
|
49
|
+
hasDocker,
|
|
50
|
+
javaVersion,
|
|
51
|
+
javaDistribution: 'temurin',
|
|
52
|
+
javaBuildTool,
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
// -- Static ecosystem configs (no async detection needed) ---------------------
|
|
56
|
+
const STATIC_ECOSYSTEMS = {
|
|
57
|
+
go: ['go', 'go mod', 'go test ./...', 'golangci-lint run', 'go build ./...'],
|
|
58
|
+
rust: ['rust', 'cargo', 'cargo test', 'cargo clippy -- -D warnings', 'cargo build --release'],
|
|
59
|
+
ruby: ['ruby', 'bundler', 'bundle exec rspec', 'bundle exec rubocop', 'gem build *.gemspec'],
|
|
60
|
+
php: [
|
|
61
|
+
'php',
|
|
62
|
+
'composer',
|
|
63
|
+
'vendor/bin/phpunit',
|
|
64
|
+
'vendor/bin/phpstan analyse',
|
|
65
|
+
'composer install --no-dev --optimize-autoloader',
|
|
66
|
+
],
|
|
67
|
+
dart: ['dart', 'pub', 'flutter test', 'dart analyze', 'flutter build'],
|
|
68
|
+
dotnet: [
|
|
69
|
+
'csharp',
|
|
70
|
+
'nuget',
|
|
71
|
+
'dotnet test',
|
|
72
|
+
'dotnet format --verify-no-changes',
|
|
73
|
+
'dotnet build --configuration Release',
|
|
74
|
+
],
|
|
75
|
+
unknown: [
|
|
76
|
+
'unknown',
|
|
77
|
+
'unknown',
|
|
78
|
+
'echo "No test command configured"',
|
|
79
|
+
'echo "No lint command configured"',
|
|
80
|
+
'echo "No build command configured"',
|
|
81
|
+
],
|
|
82
|
+
};
|
|
83
|
+
function buildStaticContext(ecosystem, hasDocker) {
|
|
84
|
+
const cfg = STATIC_ECOSYSTEMS[ecosystem];
|
|
85
|
+
/* v8 ignore next 5 */
|
|
86
|
+
const lang = cfg?.[0] ?? 'unknown';
|
|
87
|
+
const pm = cfg?.[1] ?? 'unknown';
|
|
88
|
+
const test = cfg?.[2] ?? 'echo "No test command configured"';
|
|
89
|
+
const lint = cfg?.[3] ?? 'echo "No lint command configured"';
|
|
90
|
+
const build = cfg?.[4] ?? 'echo "No build command configured"';
|
|
91
|
+
return {
|
|
92
|
+
ecosystem,
|
|
93
|
+
language: lang,
|
|
94
|
+
packageManager: pm,
|
|
95
|
+
testCommand: test,
|
|
96
|
+
lintCommand: lint,
|
|
97
|
+
buildCommand: build,
|
|
98
|
+
hasDocker,
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
/** Build a CIStackContext for the detected ecosystem. */
|
|
102
|
+
export async function buildContextForEcosystem(ecosystem, projectPath, hasDocker) {
|
|
103
|
+
switch (ecosystem) {
|
|
104
|
+
case 'nodejs':
|
|
105
|
+
return buildNodeContext(projectPath, hasDocker);
|
|
106
|
+
case 'python':
|
|
107
|
+
return buildPythonContext(projectPath, hasDocker);
|
|
108
|
+
case 'go':
|
|
109
|
+
return {
|
|
110
|
+
...buildStaticContext(ecosystem, hasDocker),
|
|
111
|
+
goVersion: await detectGoVersion(projectPath),
|
|
112
|
+
};
|
|
113
|
+
case 'rust':
|
|
114
|
+
return {
|
|
115
|
+
...buildStaticContext(ecosystem, hasDocker),
|
|
116
|
+
rustChannel: await detectRustChannel(projectPath),
|
|
117
|
+
};
|
|
118
|
+
case 'java':
|
|
119
|
+
case 'kotlin':
|
|
120
|
+
return buildJvmContext(ecosystem, projectPath, hasDocker);
|
|
121
|
+
case 'ruby':
|
|
122
|
+
case 'php':
|
|
123
|
+
case 'dart':
|
|
124
|
+
case 'dotnet':
|
|
125
|
+
case 'unknown':
|
|
126
|
+
return buildStaticContext(ecosystem, hasDocker);
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
//# sourceMappingURL=context-builders.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"context-builders.js","sourceRoot":"","sources":["../../../src/engine/ci-generator/context-builders.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { GenerateCIInput, GenerateCIResult } from '../../types/index.js';
|
|
2
|
+
/**
|
|
3
|
+
* Generate a GitHub Actions CI workflow for a project.
|
|
4
|
+
* Detects the project stack and generates a valid workflow YAML.
|
|
5
|
+
*/
|
|
6
|
+
export declare function generateCI(input: GenerateCIInput): Promise<GenerateCIResult>;
|
|
7
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/engine/ci-generator/index.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAGV,eAAe,EACf,gBAAgB,EACjB,MAAM,sBAAsB,CAAC;AAS9B;;;GAGG;AACH,wBAAsB,UAAU,CAAC,KAAK,EAAE,eAAe,GAAG,OAAO,CAAC,gBAAgB,CAAC,CA+ClF"}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
// ci-generator/index.ts — Public API for the CI workflow generator (SPEC-066)
|
|
2
|
+
import { detectCIStack } from './stack-detector.js';
|
|
3
|
+
import { buildWorkflow, serializeWorkflow } from './yaml-builder.js';
|
|
4
|
+
const DEFAULT_JOBS = ['lint', 'test', 'build'];
|
|
5
|
+
const DEFAULT_TRIGGERS = ['push', 'pull_request'];
|
|
6
|
+
const DEFAULT_WORKFLOW_NAME = 'CI';
|
|
7
|
+
/**
|
|
8
|
+
* Generate a GitHub Actions CI workflow for a project.
|
|
9
|
+
* Detects the project stack and generates a valid workflow YAML.
|
|
10
|
+
*/
|
|
11
|
+
export async function generateCI(input) {
|
|
12
|
+
const { projectPath, jobs = DEFAULT_JOBS, triggers = DEFAULT_TRIGGERS, nodeVersion, pythonVersion, goVersion, rustChannel, javaVersion, workflowName = DEFAULT_WORKFLOW_NAME, } = input;
|
|
13
|
+
// Detect stack from project files, create a mutable copy
|
|
14
|
+
const detected = await detectCIStack(projectPath);
|
|
15
|
+
const stackContext = { ...detected };
|
|
16
|
+
// Override detected versions with explicit user inputs
|
|
17
|
+
if (nodeVersion !== undefined) {
|
|
18
|
+
stackContext.nodeVersion = nodeVersion;
|
|
19
|
+
}
|
|
20
|
+
if (pythonVersion !== undefined) {
|
|
21
|
+
stackContext.pythonVersion = pythonVersion;
|
|
22
|
+
}
|
|
23
|
+
if (goVersion !== undefined) {
|
|
24
|
+
stackContext.goVersion = goVersion;
|
|
25
|
+
}
|
|
26
|
+
if (rustChannel !== undefined) {
|
|
27
|
+
stackContext.rustChannel = rustChannel;
|
|
28
|
+
}
|
|
29
|
+
if (javaVersion !== undefined) {
|
|
30
|
+
stackContext.javaVersion = javaVersion;
|
|
31
|
+
}
|
|
32
|
+
// Build the workflow model
|
|
33
|
+
const workflow = buildWorkflow(stackContext, jobs, triggers, workflowName);
|
|
34
|
+
// Serialize to YAML
|
|
35
|
+
const yamlContent = serializeWorkflow(workflow);
|
|
36
|
+
return {
|
|
37
|
+
ecosystem: stackContext.ecosystem,
|
|
38
|
+
workflowPath: workflow.filename,
|
|
39
|
+
yamlContent,
|
|
40
|
+
jobs,
|
|
41
|
+
stackContext,
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/engine/ci-generator/index.ts"],"names":[],"mappings":"AAAA,8EAA8E;AAS9E,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACpD,OAAO,EAAE,aAAa,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AAErE,MAAM,YAAY,GAAgB,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,CAAC,CAAC;AAC5D,MAAM,gBAAgB,GAAqB,CAAC,MAAM,EAAE,cAAc,CAAC,CAAC;AACpE,MAAM,qBAAqB,GAAG,IAAI,CAAC;AAEnC;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,UAAU,CAAC,KAAsB;IACrD,MAAM,EACJ,WAAW,EACX,IAAI,GAAG,YAAY,EACnB,QAAQ,GAAG,gBAAgB,EAC3B,WAAW,EACX,aAAa,EACb,SAAS,EACT,WAAW,EACX,WAAW,EACX,YAAY,GAAG,qBAAqB,GACrC,GAAG,KAAK,CAAC;IAEV,yDAAyD;IACzD,MAAM,QAAQ,GAAG,MAAM,aAAa,CAAC,WAAW,CAAC,CAAC;IAClD,MAAM,YAAY,GAAG,EAAE,GAAG,QAAQ,EAAE,CAAC;IAErC,uDAAuD;IACvD,IAAI,WAAW,KAAK,SAAS,EAAE,CAAC;QAC9B,YAAY,CAAC,WAAW,GAAG,WAAW,CAAC;IACzC,CAAC;IACD,IAAI,aAAa,KAAK,SAAS,EAAE,CAAC;QAChC,YAAY,CAAC,aAAa,GAAG,aAAa,CAAC;IAC7C,CAAC;IACD,IAAI,SAAS,KAAK,SAAS,EAAE,CAAC;QAC5B,YAAY,CAAC,SAAS,GAAG,SAAS,CAAC;IACrC,CAAC;IACD,IAAI,WAAW,KAAK,SAAS,EAAE,CAAC;QAC9B,YAAY,CAAC,WAAW,GAAG,WAAW,CAAC;IACzC,CAAC;IACD,IAAI,WAAW,KAAK,SAAS,EAAE,CAAC;QAC9B,YAAY,CAAC,WAAW,GAAG,WAAW,CAAC;IACzC,CAAC;IAED,2BAA2B;IAC3B,MAAM,QAAQ,GAAG,aAAa,CAAC,YAAY,EAAE,IAAI,EAAE,QAAQ,EAAE,YAAY,CAAC,CAAC;IAE3E,oBAAoB;IACpB,MAAM,WAAW,GAAG,iBAAiB,CAAC,QAAQ,CAAC,CAAC;IAEhD,OAAO;QACL,SAAS,EAAE,YAAY,CAAC,SAAS;QACjC,YAAY,EAAE,QAAQ,CAAC,QAAQ;QAC/B,WAAW;QACX,IAAI;QACJ,YAAY;KACb,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { CIStackContext, JavaBuildTool } from '../../types/index.js';
|
|
2
|
+
export declare function detectNodePackageManager(projectPath: string): Promise<string>;
|
|
3
|
+
export declare function detectNodeVersion(projectPath: string): Promise<string>;
|
|
4
|
+
export declare function buildNodeCommands(pm: string): {
|
|
5
|
+
install: string;
|
|
6
|
+
lint: string;
|
|
7
|
+
test: string;
|
|
8
|
+
build: string;
|
|
9
|
+
};
|
|
10
|
+
export declare function detectPythonPackageManager(projectPath: string): Promise<string>;
|
|
11
|
+
export declare function detectPythonVersion(projectPath: string): Promise<string>;
|
|
12
|
+
export declare function detectGoVersion(projectPath: string): Promise<string>;
|
|
13
|
+
export declare function detectRustChannel(projectPath: string): Promise<string>;
|
|
14
|
+
export declare function detectJavaVersion(projectPath: string): Promise<string>;
|
|
15
|
+
export declare function detectJavaBuildTool(projectPath: string): Promise<JavaBuildTool>;
|
|
16
|
+
/**
|
|
17
|
+
* Detect the full stack context of a project for CI generation.
|
|
18
|
+
* Reads config files to determine ecosystem, package manager, versions, and commands.
|
|
19
|
+
*/
|
|
20
|
+
export declare function detectCIStack(projectPath: string): Promise<CIStackContext>;
|
|
21
|
+
//# sourceMappingURL=stack-detector.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"stack-detector.d.ts","sourceRoot":"","sources":["../../../src/engine/ci-generator/stack-detector.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAe,cAAc,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AA4EvF,wBAAsB,wBAAwB,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAWnF;AAED,wBAAsB,iBAAiB,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAoB5E;AAED,wBAAgB,iBAAiB,CAAC,EAAE,EAAE,MAAM,GAAG;IAC7C,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;CACf,CAWA;AAID,wBAAsB,0BAA0B,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CASrF;AAED,wBAAsB,mBAAmB,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAe9E;AAID,wBAAsB,eAAe,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAI1E;AAID,wBAAsB,iBAAiB,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAa5E;AAID,wBAAsB,iBAAiB,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAkB5E;AAED,wBAAsB,mBAAmB,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,CAAC,CAKrF;AAcD;;;GAGG;AACH,wBAAsB,aAAa,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,CAAC,CAIhF"}
|
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
// ci-generator/stack-detector.ts — Detect project stack for CI generation (SPEC-066)
|
|
2
|
+
import { readFile, access } from 'node:fs/promises';
|
|
3
|
+
import { join } from 'node:path';
|
|
4
|
+
import { buildContextForEcosystem } from './context-builders.js';
|
|
5
|
+
// -- File existence helper ---------------------------------------------------
|
|
6
|
+
async function fileExists(filePath) {
|
|
7
|
+
try {
|
|
8
|
+
await access(filePath);
|
|
9
|
+
return true;
|
|
10
|
+
}
|
|
11
|
+
catch {
|
|
12
|
+
return false;
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
async function readTextSafe(filePath) {
|
|
16
|
+
try {
|
|
17
|
+
return await readFile(filePath, 'utf-8');
|
|
18
|
+
}
|
|
19
|
+
catch {
|
|
20
|
+
return '';
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
async function readJsonSafe(filePath) {
|
|
24
|
+
try {
|
|
25
|
+
const content = await readFile(filePath, 'utf-8');
|
|
26
|
+
return JSON.parse(content);
|
|
27
|
+
}
|
|
28
|
+
catch {
|
|
29
|
+
return null;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
// -- Ecosystem detection -----------------------------------------------------
|
|
33
|
+
async function detectEcosystem(projectPath) {
|
|
34
|
+
if (await fileExists(join(projectPath, 'go.mod'))) {
|
|
35
|
+
return 'go';
|
|
36
|
+
}
|
|
37
|
+
if (await fileExists(join(projectPath, 'Cargo.toml'))) {
|
|
38
|
+
return 'rust';
|
|
39
|
+
}
|
|
40
|
+
if (await fileExists(join(projectPath, 'pom.xml'))) {
|
|
41
|
+
return 'java';
|
|
42
|
+
}
|
|
43
|
+
if (await fileExists(join(projectPath, 'build.gradle'))) {
|
|
44
|
+
return 'java';
|
|
45
|
+
}
|
|
46
|
+
if (await fileExists(join(projectPath, 'build.gradle.kts'))) {
|
|
47
|
+
return 'kotlin';
|
|
48
|
+
}
|
|
49
|
+
if (await fileExists(join(projectPath, 'Gemfile'))) {
|
|
50
|
+
return 'ruby';
|
|
51
|
+
}
|
|
52
|
+
if (await fileExists(join(projectPath, 'composer.json'))) {
|
|
53
|
+
return 'php';
|
|
54
|
+
}
|
|
55
|
+
if (await fileExists(join(projectPath, 'pubspec.yaml'))) {
|
|
56
|
+
return 'dart';
|
|
57
|
+
}
|
|
58
|
+
if (await fileExists(join(projectPath, 'package.json'))) {
|
|
59
|
+
return 'nodejs';
|
|
60
|
+
}
|
|
61
|
+
if ((await fileExists(join(projectPath, 'pyproject.toml'))) ||
|
|
62
|
+
(await fileExists(join(projectPath, 'requirements.txt'))) ||
|
|
63
|
+
(await fileExists(join(projectPath, 'setup.py')))) {
|
|
64
|
+
return 'python';
|
|
65
|
+
}
|
|
66
|
+
if (await fileExists(join(projectPath, 'global.json'))) {
|
|
67
|
+
return 'dotnet';
|
|
68
|
+
}
|
|
69
|
+
return 'unknown';
|
|
70
|
+
}
|
|
71
|
+
// -- Node.js helpers ---------------------------------------------------------
|
|
72
|
+
export async function detectNodePackageManager(projectPath) {
|
|
73
|
+
if (await fileExists(join(projectPath, 'pnpm-lock.yaml'))) {
|
|
74
|
+
return 'pnpm';
|
|
75
|
+
}
|
|
76
|
+
if (await fileExists(join(projectPath, 'bun.lockb'))) {
|
|
77
|
+
return 'bun';
|
|
78
|
+
}
|
|
79
|
+
if (await fileExists(join(projectPath, 'yarn.lock'))) {
|
|
80
|
+
return 'yarn';
|
|
81
|
+
}
|
|
82
|
+
return 'npm';
|
|
83
|
+
}
|
|
84
|
+
export async function detectNodeVersion(projectPath) {
|
|
85
|
+
const nvmrc = await readTextSafe(join(projectPath, '.nvmrc'));
|
|
86
|
+
if (nvmrc.trim()) {
|
|
87
|
+
return nvmrc.trim();
|
|
88
|
+
}
|
|
89
|
+
const nodeVer = await readTextSafe(join(projectPath, '.node-version'));
|
|
90
|
+
if (nodeVer.trim()) {
|
|
91
|
+
return nodeVer.trim();
|
|
92
|
+
}
|
|
93
|
+
const pkg = await readJsonSafe(join(projectPath, 'package.json'));
|
|
94
|
+
if (pkg) {
|
|
95
|
+
const engines = pkg.engines;
|
|
96
|
+
if (engines?.node) {
|
|
97
|
+
const match = /(\d+)/.exec(engines.node);
|
|
98
|
+
return match?.[1] ?? '20';
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
return '20';
|
|
102
|
+
}
|
|
103
|
+
export function buildNodeCommands(pm) {
|
|
104
|
+
const run = pm === 'npm' ? 'npm run' : pm === 'bun' ? 'bun run' : `${pm} run`;
|
|
105
|
+
const install = pm === 'pnpm'
|
|
106
|
+
? 'pnpm install --frozen-lockfile'
|
|
107
|
+
: pm === 'yarn'
|
|
108
|
+
? 'yarn install --frozen-lockfile'
|
|
109
|
+
: pm === 'bun'
|
|
110
|
+
? 'bun install --frozen-lockfile'
|
|
111
|
+
: 'npm ci';
|
|
112
|
+
return { install, lint: `${run} lint`, test: `${run} test`, build: `${run} build` };
|
|
113
|
+
}
|
|
114
|
+
// -- Python helpers ----------------------------------------------------------
|
|
115
|
+
export async function detectPythonPackageManager(projectPath) {
|
|
116
|
+
const pyproject = await readTextSafe(join(projectPath, 'pyproject.toml'));
|
|
117
|
+
if (pyproject.includes('[tool.poetry]')) {
|
|
118
|
+
return 'poetry';
|
|
119
|
+
}
|
|
120
|
+
if (await fileExists(join(projectPath, 'uv.lock'))) {
|
|
121
|
+
return 'uv';
|
|
122
|
+
}
|
|
123
|
+
return 'pip';
|
|
124
|
+
}
|
|
125
|
+
export async function detectPythonVersion(projectPath) {
|
|
126
|
+
const pyVer = await readTextSafe(join(projectPath, '.python-version'));
|
|
127
|
+
if (pyVer.trim()) {
|
|
128
|
+
return pyVer.trim();
|
|
129
|
+
}
|
|
130
|
+
const pyproject = await readTextSafe(join(projectPath, 'pyproject.toml'));
|
|
131
|
+
if (pyproject) {
|
|
132
|
+
const match = /requires-python\s*=\s*"([^"]+)"/.exec(pyproject);
|
|
133
|
+
if (match?.[1]) {
|
|
134
|
+
const verMatch = /(\d+\.\d+)/.exec(match[1]);
|
|
135
|
+
return verMatch?.[1] ?? '3.11';
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
return '3.11';
|
|
139
|
+
}
|
|
140
|
+
// -- Go helpers --------------------------------------------------------------
|
|
141
|
+
export async function detectGoVersion(projectPath) {
|
|
142
|
+
const goMod = await readTextSafe(join(projectPath, 'go.mod'));
|
|
143
|
+
const match = /^go\s+(\S+)/m.exec(goMod);
|
|
144
|
+
return match?.[1] ?? '1.22';
|
|
145
|
+
}
|
|
146
|
+
// -- Rust helpers ------------------------------------------------------------
|
|
147
|
+
export async function detectRustChannel(projectPath) {
|
|
148
|
+
const toolchain = await readTextSafe(join(projectPath, 'rust-toolchain.toml'));
|
|
149
|
+
if (toolchain) {
|
|
150
|
+
const match = /channel\s*=\s*"([^"]+)"/.exec(toolchain);
|
|
151
|
+
if (match?.[1]) {
|
|
152
|
+
return match[1];
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
const toolchainFile = await readTextSafe(join(projectPath, 'rust-toolchain'));
|
|
156
|
+
if (toolchainFile.trim()) {
|
|
157
|
+
return toolchainFile.trim();
|
|
158
|
+
}
|
|
159
|
+
return 'stable';
|
|
160
|
+
}
|
|
161
|
+
// -- Java helpers ------------------------------------------------------------
|
|
162
|
+
export async function detectJavaVersion(projectPath) {
|
|
163
|
+
const pom = await readTextSafe(join(projectPath, 'pom.xml'));
|
|
164
|
+
if (pom) {
|
|
165
|
+
const match = /<java.version>([^<]+)</.exec(pom) ?? /<maven.compiler.source>([^<]+)</.exec(pom);
|
|
166
|
+
if (match?.[1]) {
|
|
167
|
+
return match[1];
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
for (const gradleFile of ['build.gradle.kts', 'build.gradle']) {
|
|
171
|
+
const gradle = await readTextSafe(join(projectPath, gradleFile));
|
|
172
|
+
if (gradle) {
|
|
173
|
+
const match = /(?:sourceCompatibility|jvmTarget)\s*[=:]\s*['"]?(\S+?)['"]?\s/m.exec(gradle);
|
|
174
|
+
if (match?.[1]) {
|
|
175
|
+
return match[1];
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
return '21';
|
|
180
|
+
}
|
|
181
|
+
export async function detectJavaBuildTool(projectPath) {
|
|
182
|
+
if (await fileExists(join(projectPath, 'pom.xml'))) {
|
|
183
|
+
return 'maven';
|
|
184
|
+
}
|
|
185
|
+
return 'gradle';
|
|
186
|
+
}
|
|
187
|
+
// -- Docker detection --------------------------------------------------------
|
|
188
|
+
async function detectHasDocker(projectPath) {
|
|
189
|
+
return ((await fileExists(join(projectPath, 'Dockerfile'))) ||
|
|
190
|
+
(await fileExists(join(projectPath, 'docker-compose.yml'))) ||
|
|
191
|
+
(await fileExists(join(projectPath, 'docker-compose.yaml'))));
|
|
192
|
+
}
|
|
193
|
+
// -- Main export -------------------------------------------------------------
|
|
194
|
+
/**
|
|
195
|
+
* Detect the full stack context of a project for CI generation.
|
|
196
|
+
* Reads config files to determine ecosystem, package manager, versions, and commands.
|
|
197
|
+
*/
|
|
198
|
+
export async function detectCIStack(projectPath) {
|
|
199
|
+
const ecosystem = await detectEcosystem(projectPath);
|
|
200
|
+
const hasDocker = await detectHasDocker(projectPath);
|
|
201
|
+
return buildContextForEcosystem(ecosystem, projectPath, hasDocker);
|
|
202
|
+
}
|
|
203
|
+
//# sourceMappingURL=stack-detector.js.map
|