pi-harness-runtime 0.9.2 → 0.9.5
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/CHANGELOG.md +36 -0
- package/footer-status.ts +38 -0
- package/index.ts +41 -1
- package/package.json +2 -1
- package/packages/a2a-adapter/README.md +35 -0
- package/packages/a2a-adapter/dist/agent.d.ts +27 -0
- package/packages/a2a-adapter/dist/agent.d.ts.map +1 -0
- package/packages/a2a-adapter/dist/agent.js +120 -0
- package/packages/a2a-adapter/dist/agent.js.map +1 -0
- package/packages/a2a-adapter/dist/client.d.ts +58 -0
- package/packages/a2a-adapter/dist/client.d.ts.map +1 -0
- package/packages/a2a-adapter/dist/client.js +77 -0
- package/packages/a2a-adapter/dist/client.js.map +1 -0
- package/packages/a2a-adapter/dist/index.d.ts +9 -0
- package/packages/a2a-adapter/dist/index.d.ts.map +1 -0
- package/packages/a2a-adapter/dist/index.js +8 -0
- package/packages/a2a-adapter/dist/index.js.map +1 -0
- package/packages/a2a-adapter/dist/protocol.d.ts +34 -0
- package/packages/a2a-adapter/dist/protocol.d.ts.map +1 -0
- package/packages/a2a-adapter/dist/protocol.js +40 -0
- package/packages/a2a-adapter/dist/protocol.js.map +1 -0
- package/packages/a2a-adapter/dist/transport.d.ts +55 -0
- package/packages/a2a-adapter/dist/transport.d.ts.map +1 -0
- package/packages/a2a-adapter/dist/transport.js +109 -0
- package/packages/a2a-adapter/dist/transport.js.map +1 -0
- package/packages/a2a-adapter/dist/types.d.ts +117 -0
- package/packages/a2a-adapter/dist/types.d.ts.map +1 -0
- package/packages/a2a-adapter/dist/types.js +5 -0
- package/packages/a2a-adapter/dist/types.js.map +1 -0
- package/packages/a2a-adapter/package.json +21 -0
- package/packages/a2a-adapter/src/agent.ts +139 -0
- package/packages/a2a-adapter/src/client.ts +107 -0
- package/packages/a2a-adapter/src/index.ts +30 -0
- package/packages/a2a-adapter/src/protocol.ts +46 -0
- package/packages/a2a-adapter/src/transport.ts +142 -0
- package/packages/a2a-adapter/src/types.ts +117 -0
- package/packages/a2a-adapter/test/a2a.test.ts +151 -0
- package/packages/a2a-adapter/tsconfig.json +5 -0
- package/packages/auth/package.json +22 -0
- package/packages/auth/test/auth.test.ts +238 -0
- package/packages/autonomous-refactor/dist/detector.d.ts +11 -0
- package/packages/autonomous-refactor/dist/detector.d.ts.map +1 -0
- package/packages/autonomous-refactor/dist/detector.js +175 -0
- package/packages/autonomous-refactor/dist/detector.js.map +1 -0
- package/packages/autonomous-refactor/dist/index.d.ts +7 -0
- package/packages/autonomous-refactor/dist/index.d.ts.map +1 -0
- package/packages/autonomous-refactor/dist/index.js +6 -0
- package/packages/autonomous-refactor/dist/index.js.map +1 -0
- package/packages/autonomous-refactor/dist/planner.d.ts +9 -0
- package/packages/autonomous-refactor/dist/planner.d.ts.map +1 -0
- package/packages/autonomous-refactor/dist/planner.js +71 -0
- package/packages/autonomous-refactor/dist/planner.js.map +1 -0
- package/packages/autonomous-refactor/dist/types.d.ts +39 -0
- package/packages/autonomous-refactor/dist/types.d.ts.map +1 -0
- package/packages/autonomous-refactor/dist/types.js +11 -0
- package/packages/autonomous-refactor/dist/types.js.map +1 -0
- package/packages/autonomous-refactor/package.json +21 -0
- package/packages/autonomous-refactor/src/detector.ts +219 -0
- package/packages/autonomous-refactor/src/index.ts +16 -0
- package/packages/autonomous-refactor/src/planner.ts +99 -0
- package/packages/autonomous-refactor/src/types.ts +57 -0
- package/packages/autonomous-refactor/test/refactor.test.ts +202 -0
- package/packages/autonomous-refactor/tsconfig.json +5 -0
- package/packages/cache-strategy/dist/cache.d.ts +31 -0
- package/packages/cache-strategy/dist/cache.d.ts.map +1 -0
- package/packages/cache-strategy/dist/cache.js +195 -0
- package/packages/cache-strategy/dist/cache.js.map +1 -0
- package/packages/cache-strategy/dist/index.d.ts +6 -0
- package/packages/cache-strategy/dist/index.d.ts.map +1 -0
- package/packages/cache-strategy/dist/index.js +5 -0
- package/packages/cache-strategy/dist/index.js.map +1 -0
- package/packages/cache-strategy/dist/types.d.ts +35 -0
- package/packages/cache-strategy/dist/types.d.ts.map +1 -0
- package/packages/cache-strategy/dist/types.js +5 -0
- package/packages/cache-strategy/dist/types.js.map +1 -0
- package/packages/cache-strategy/package.json +21 -0
- package/packages/cache-strategy/src/cache.ts +213 -0
- package/packages/cache-strategy/src/index.ts +6 -0
- package/packages/cache-strategy/src/types.ts +40 -0
- package/packages/cache-strategy/test/cache.test.ts +137 -0
- package/packages/cache-strategy/tsconfig.json +5 -0
- package/packages/capability-registry/dist/registry.d.ts.map +1 -1
- package/packages/capability-registry/package.json +1 -1
- package/packages/checkpoint/dist/checkpoint-manager.d.ts.map +1 -1
- package/packages/checkpoint/dist/checkpoint-manager.js.map +1 -1
- package/packages/checkpoint/dist/differ.d.ts.map +1 -1
- package/packages/checkpoint/dist/engine.d.ts.map +1 -1
- package/packages/checkpoint/dist/engine.js.map +1 -1
- package/packages/checkpoint/dist/storage.d.ts.map +1 -1
- package/packages/checkpoint/dist/storage.js.map +1 -1
- package/packages/checkpoint/package.json +2 -2
- package/packages/checkpoint/tsconfig.tsbuildinfo +1 -1
- package/packages/cli-plugin-sdk/README.md +48 -0
- package/packages/cli-plugin-sdk/dist/index.d.ts +30 -0
- package/packages/cli-plugin-sdk/dist/index.d.ts.map +1 -0
- package/packages/cli-plugin-sdk/dist/index.js +128 -0
- package/packages/cli-plugin-sdk/dist/index.js.map +1 -0
- package/packages/cli-plugin-sdk/dist/plugin-fs.d.ts +21 -0
- package/packages/cli-plugin-sdk/dist/plugin-fs.d.ts.map +1 -0
- package/packages/cli-plugin-sdk/dist/plugin-fs.js +80 -0
- package/packages/cli-plugin-sdk/dist/plugin-fs.js.map +1 -0
- package/packages/cli-plugin-sdk/dist/registry.d.ts +16 -0
- package/packages/cli-plugin-sdk/dist/registry.d.ts.map +1 -0
- package/packages/cli-plugin-sdk/dist/registry.js +45 -0
- package/packages/cli-plugin-sdk/dist/registry.js.map +1 -0
- package/packages/cli-plugin-sdk/dist/types.d.ts +28 -0
- package/packages/cli-plugin-sdk/dist/types.d.ts.map +1 -0
- package/packages/cli-plugin-sdk/dist/types.js +5 -0
- package/packages/cli-plugin-sdk/dist/types.js.map +1 -0
- package/packages/cli-plugin-sdk/package.json +24 -0
- package/packages/cli-plugin-sdk/src/index.ts +169 -0
- package/packages/cli-plugin-sdk/src/plugin-fs.ts +91 -0
- package/packages/cli-plugin-sdk/src/registry.ts +55 -0
- package/packages/cli-plugin-sdk/src/types.ts +32 -0
- package/packages/cli-plugin-sdk/test/cli.test.ts +45 -0
- package/packages/cli-plugin-sdk/tsconfig.json +11 -0
- package/packages/code-generation/dist/generator.d.ts.map +1 -1
- package/packages/code-generation/dist/generator.js.map +1 -1
- package/packages/code-generation/dist/templates/ejs-renderer.d.ts.map +1 -1
- package/packages/code-generation/dist/templates/ejs-renderer.js.map +1 -1
- package/packages/code-generation/dist/templates/registry.d.ts.map +1 -1
- package/packages/code-generation/package.json +2 -2
- package/packages/code-generation/tsconfig.tsbuildinfo +1 -1
- package/packages/code-review/dist/engine.d.ts.map +1 -1
- package/packages/code-review/dist/reports/html.d.ts.map +1 -1
- package/packages/code-review/dist/reports/markdown.d.ts.map +1 -1
- package/packages/code-review/dist/reports/text.d.ts.map +1 -1
- package/packages/code-review/package.json +2 -2
- package/packages/code-review/tsconfig.tsbuildinfo +1 -1
- package/packages/codex-adapter/dist/executor.d.ts +14 -0
- package/packages/codex-adapter/dist/executor.d.ts.map +1 -0
- package/packages/codex-adapter/dist/executor.js +69 -0
- package/packages/codex-adapter/dist/executor.js.map +1 -0
- package/packages/codex-adapter/dist/index.d.ts +8 -0
- package/packages/codex-adapter/dist/index.d.ts.map +1 -0
- package/packages/codex-adapter/dist/index.js +7 -0
- package/packages/codex-adapter/dist/index.js.map +1 -0
- package/packages/codex-adapter/dist/provider.d.ts +26 -0
- package/packages/codex-adapter/dist/provider.d.ts.map +1 -0
- package/packages/codex-adapter/dist/provider.js +170 -0
- package/packages/codex-adapter/dist/provider.js.map +1 -0
- package/packages/codex-adapter/dist/types.d.ts +52 -0
- package/packages/codex-adapter/dist/types.d.ts.map +1 -0
- package/packages/codex-adapter/dist/types.js +64 -0
- package/packages/codex-adapter/dist/types.js.map +1 -0
- package/packages/codex-adapter/package.json +24 -0
- package/packages/codex-adapter/src/executor.ts +83 -0
- package/packages/codex-adapter/src/index.ts +16 -0
- package/packages/codex-adapter/src/provider.ts +213 -0
- package/packages/codex-adapter/src/types.ts +118 -0
- package/packages/codex-adapter/test/provider.test.ts +142 -0
- package/packages/codex-adapter/tsconfig.json +5 -0
- package/packages/context-compiler/dist/cache.js.map +1 -1
- package/packages/context-compiler/dist/compiler.d.ts.map +1 -1
- package/packages/context-compiler/dist/compiler.js.map +1 -1
- package/packages/context-compiler/dist/okf-loader.js.map +1 -1
- package/packages/context-compiler/dist/types.d.ts.map +1 -1
- package/packages/context-compiler/package.json +2 -2
- package/packages/context-manager/dist/compaction.d.ts +11 -0
- package/packages/context-manager/dist/compaction.d.ts.map +1 -0
- package/packages/context-manager/dist/compaction.js +110 -0
- package/packages/context-manager/dist/compaction.js.map +1 -0
- package/packages/context-manager/dist/core.d.ts +24 -0
- package/packages/context-manager/dist/core.d.ts.map +1 -0
- package/packages/context-manager/dist/core.js +62 -0
- package/packages/context-manager/dist/core.js.map +1 -0
- package/packages/context-manager/dist/index.d.ts +7 -0
- package/packages/context-manager/dist/index.d.ts.map +1 -0
- package/packages/context-manager/dist/index.js +6 -0
- package/packages/context-manager/dist/index.js.map +1 -0
- package/packages/context-manager/dist/types.d.ts +39 -0
- package/packages/context-manager/dist/types.d.ts.map +1 -0
- package/packages/context-manager/dist/types.js +5 -0
- package/packages/context-manager/dist/types.js.map +1 -0
- package/packages/context-manager/package.json +21 -0
- package/packages/context-manager/src/compaction.ts +139 -0
- package/packages/context-manager/src/core.ts +85 -0
- package/packages/context-manager/src/index.ts +22 -0
- package/packages/context-manager/src/types.ts +44 -0
- package/packages/context-manager/test/context.test.ts +198 -0
- package/packages/context-manager/tsconfig.json +6 -0
- package/packages/cost-optimizer/dist/optimizer.d.ts.map +1 -1
- package/packages/cost-optimizer/dist/selection.js.map +1 -1
- package/packages/cost-optimizer/dist/tracker.js.map +1 -1
- package/packages/cost-optimizer/package.json +1 -1
- package/packages/django-plugin/README.md +1 -0
- package/packages/django-plugin/dist/analyzer.d.ts +8 -0
- package/packages/django-plugin/dist/analyzer.d.ts.map +1 -0
- package/packages/django-plugin/dist/analyzer.js +249 -0
- package/packages/django-plugin/dist/analyzer.js.map +1 -0
- package/packages/django-plugin/dist/index.d.ts +8 -0
- package/packages/django-plugin/dist/index.d.ts.map +1 -0
- package/packages/django-plugin/dist/index.js +30 -0
- package/packages/django-plugin/dist/index.js.map +1 -0
- package/packages/django-plugin/dist/types.d.ts +32 -0
- package/packages/django-plugin/dist/types.d.ts.map +1 -0
- package/packages/django-plugin/dist/types.js +5 -0
- package/packages/django-plugin/dist/types.js.map +1 -0
- package/packages/django-plugin/package.json +20 -0
- package/packages/django-plugin/src/analyzer.ts +284 -0
- package/packages/django-plugin/src/index.ts +39 -0
- package/packages/django-plugin/src/types.ts +35 -0
- package/packages/django-plugin/test/analyzer.test.ts +195 -0
- package/packages/django-plugin/tsconfig.json +12 -0
- package/packages/doc-generator/dist/detector.d.ts +9 -0
- package/packages/doc-generator/dist/detector.d.ts.map +1 -0
- package/packages/doc-generator/dist/detector.js +98 -0
- package/packages/doc-generator/dist/detector.js.map +1 -0
- package/packages/doc-generator/dist/docs.d.ts +9 -0
- package/packages/doc-generator/dist/docs.d.ts.map +1 -0
- package/packages/doc-generator/dist/docs.js +132 -0
- package/packages/doc-generator/dist/docs.js.map +1 -0
- package/packages/doc-generator/dist/index.d.ts +7 -0
- package/packages/doc-generator/dist/index.d.ts.map +1 -0
- package/packages/doc-generator/dist/index.js +6 -0
- package/packages/doc-generator/dist/index.js.map +1 -0
- package/packages/doc-generator/dist/types.d.ts +37 -0
- package/packages/doc-generator/dist/types.d.ts.map +1 -0
- package/packages/doc-generator/dist/types.js +5 -0
- package/packages/doc-generator/dist/types.js.map +1 -0
- package/packages/doc-generator/package.json +21 -0
- package/packages/doc-generator/src/detector.ts +113 -0
- package/packages/doc-generator/src/docs.ts +158 -0
- package/packages/doc-generator/src/index.ts +7 -0
- package/packages/doc-generator/src/types.ts +58 -0
- package/packages/doc-generator/test/docs.test.ts +168 -0
- package/packages/doc-generator/tsconfig.json +6 -0
- package/packages/evaluation-engine/dist/engine.d.ts.map +1 -1
- package/packages/evaluation-engine/package.json +2 -2
- package/packages/evaluation-runner/dist/index.d.ts +6 -0
- package/packages/evaluation-runner/dist/index.d.ts.map +1 -0
- package/packages/evaluation-runner/dist/index.js +5 -0
- package/packages/evaluation-runner/dist/index.js.map +1 -0
- package/packages/evaluation-runner/dist/runner.d.ts +17 -0
- package/packages/evaluation-runner/dist/runner.d.ts.map +1 -0
- package/packages/evaluation-runner/dist/runner.js +153 -0
- package/packages/evaluation-runner/dist/runner.js.map +1 -0
- package/packages/evaluation-runner/dist/types.d.ts +48 -0
- package/packages/evaluation-runner/dist/types.d.ts.map +1 -0
- package/packages/evaluation-runner/dist/types.js +5 -0
- package/packages/evaluation-runner/dist/types.js.map +1 -0
- package/packages/evaluation-runner/package.json +21 -0
- package/packages/evaluation-runner/src/index.ts +6 -0
- package/packages/evaluation-runner/src/runner.ts +182 -0
- package/packages/evaluation-runner/src/types.ts +51 -0
- package/packages/evaluation-runner/test/runner.test.ts +168 -0
- package/packages/evaluation-runner/tsconfig.json +5 -0
- package/packages/experience-replay/dist/replay.d.ts.map +1 -1
- package/packages/experience-replay/package.json +2 -2
- package/packages/feedback-collector/dist/collector.d.ts +20 -0
- package/packages/feedback-collector/dist/collector.d.ts.map +1 -0
- package/packages/feedback-collector/dist/collector.js +145 -0
- package/packages/feedback-collector/dist/collector.js.map +1 -0
- package/packages/feedback-collector/dist/index.d.ts +6 -0
- package/packages/feedback-collector/dist/index.d.ts.map +1 -0
- package/packages/feedback-collector/dist/index.js +5 -0
- package/packages/feedback-collector/dist/index.js.map +1 -0
- package/packages/feedback-collector/dist/types.d.ts +46 -0
- package/packages/feedback-collector/dist/types.d.ts.map +1 -0
- package/packages/feedback-collector/dist/types.js +5 -0
- package/packages/feedback-collector/dist/types.js.map +1 -0
- package/packages/feedback-collector/package.json +21 -0
- package/packages/feedback-collector/src/collector.ts +160 -0
- package/packages/feedback-collector/src/index.ts +6 -0
- package/packages/feedback-collector/src/types.ts +51 -0
- package/packages/feedback-collector/test/collector.test.ts +142 -0
- package/packages/feedback-collector/tsconfig.json +5 -0
- package/packages/framework-detector/dist/detector.d.ts.map +1 -1
- package/packages/framework-detector/dist/detector.js.map +1 -1
- package/packages/framework-detector/dist/signatures/registry.d.ts.map +1 -1
- package/packages/framework-detector/package.json +2 -2
- package/packages/framework-detector/tsconfig.tsbuildinfo +1 -1
- package/packages/framework-plugin-sdk/dist/manager.d.ts.map +1 -1
- package/packages/framework-plugin-sdk/dist/manager.js.map +1 -1
- package/packages/framework-plugin-sdk/dist/types.d.ts.map +1 -1
- package/packages/framework-plugin-sdk/dist/types.js.map +1 -1
- package/packages/framework-plugin-sdk/package.json +2 -2
- package/packages/framework-plugin-sdk/tsconfig.tsbuildinfo +1 -1
- package/packages/frappe-plugin/dist/analyzer.d.ts +15 -0
- package/packages/frappe-plugin/dist/analyzer.d.ts.map +1 -0
- package/packages/frappe-plugin/dist/analyzer.js +368 -0
- package/packages/frappe-plugin/dist/analyzer.js.map +1 -0
- package/packages/frappe-plugin/dist/index.d.ts +27 -0
- package/packages/frappe-plugin/dist/index.d.ts.map +1 -0
- package/packages/frappe-plugin/dist/index.js +52 -0
- package/packages/frappe-plugin/dist/index.js.map +1 -0
- package/packages/frappe-plugin/dist/types.d.ts +91 -0
- package/packages/frappe-plugin/dist/types.d.ts.map +1 -0
- package/packages/frappe-plugin/dist/types.js +13 -0
- package/packages/frappe-plugin/dist/types.js.map +1 -0
- package/packages/frappe-plugin/package.json +20 -0
- package/packages/frappe-plugin/src/analyzer.ts +454 -0
- package/packages/frappe-plugin/src/index.ts +72 -0
- package/packages/frappe-plugin/src/types.ts +135 -0
- package/packages/frappe-plugin/test/analyzer.test.ts +250 -0
- package/packages/frappe-plugin/tsconfig.json +12 -0
- package/packages/generic-web-plugin/dist/analyzer.d.ts +15 -0
- package/packages/generic-web-plugin/dist/analyzer.d.ts.map +1 -0
- package/packages/generic-web-plugin/dist/analyzer.js +310 -0
- package/packages/generic-web-plugin/dist/analyzer.js.map +1 -0
- package/packages/generic-web-plugin/dist/index.d.ts +20 -0
- package/packages/generic-web-plugin/dist/index.d.ts.map +1 -0
- package/packages/generic-web-plugin/dist/index.js +47 -0
- package/packages/generic-web-plugin/dist/index.js.map +1 -0
- package/packages/generic-web-plugin/dist/types.d.ts +21 -0
- package/packages/generic-web-plugin/dist/types.d.ts.map +1 -0
- package/packages/generic-web-plugin/dist/types.js +5 -0
- package/packages/generic-web-plugin/dist/types.js.map +1 -0
- package/packages/generic-web-plugin/package.json +20 -0
- package/packages/generic-web-plugin/src/analyzer.ts +347 -0
- package/packages/generic-web-plugin/src/index.ts +61 -0
- package/packages/generic-web-plugin/src/types.ts +41 -0
- package/packages/generic-web-plugin/test/analyzer.test.ts +134 -0
- package/packages/generic-web-plugin/tsconfig.json +12 -0
- package/packages/health-monitor/dist/index.d.ts +6 -0
- package/packages/health-monitor/dist/index.d.ts.map +1 -0
- package/packages/health-monitor/dist/index.js +5 -0
- package/packages/health-monitor/dist/index.js.map +1 -0
- package/packages/health-monitor/dist/monitor.d.ts +39 -0
- package/packages/health-monitor/dist/monitor.d.ts.map +1 -0
- package/packages/health-monitor/dist/monitor.js +155 -0
- package/packages/health-monitor/dist/monitor.js.map +1 -0
- package/packages/health-monitor/dist/types.d.ts +33 -0
- package/packages/health-monitor/dist/types.d.ts.map +1 -0
- package/packages/health-monitor/dist/types.js +5 -0
- package/packages/health-monitor/dist/types.js.map +1 -0
- package/packages/health-monitor/package.json +21 -0
- package/packages/health-monitor/src/index.ts +16 -0
- package/packages/health-monitor/src/monitor.ts +216 -0
- package/packages/health-monitor/src/types.ts +45 -0
- package/packages/health-monitor/test/health.test.ts +231 -0
- package/packages/health-monitor/tsconfig.json +5 -0
- package/packages/laravel-plugin/README.md +1 -0
- package/packages/laravel-plugin/dist/analyzer.d.ts +8 -0
- package/packages/laravel-plugin/dist/analyzer.d.ts.map +1 -0
- package/packages/laravel-plugin/dist/analyzer.js +297 -0
- package/packages/laravel-plugin/dist/analyzer.js.map +1 -0
- package/packages/laravel-plugin/dist/index.d.ts +8 -0
- package/packages/laravel-plugin/dist/index.d.ts.map +1 -0
- package/packages/laravel-plugin/dist/index.js +31 -0
- package/packages/laravel-plugin/dist/index.js.map +1 -0
- package/packages/laravel-plugin/dist/types.d.ts +23 -0
- package/packages/laravel-plugin/dist/types.d.ts.map +1 -0
- package/packages/laravel-plugin/dist/types.js +5 -0
- package/packages/laravel-plugin/dist/types.js.map +1 -0
- package/packages/laravel-plugin/package.json +20 -0
- package/packages/laravel-plugin/src/analyzer.ts +323 -0
- package/packages/laravel-plugin/src/index.ts +40 -0
- package/packages/laravel-plugin/src/types.ts +24 -0
- package/packages/laravel-plugin/test/analyzer.test.ts +220 -0
- package/packages/laravel-plugin/tsconfig.json +12 -0
- package/packages/learning-engine/dist/engine.d.ts.map +1 -1
- package/packages/learning-engine/package.json +2 -2
- package/packages/mcp-adapter/README.md +47 -0
- package/packages/mcp-adapter/dist/index.d.ts +8 -0
- package/packages/mcp-adapter/dist/index.d.ts.map +1 -0
- package/packages/mcp-adapter/dist/index.js +7 -0
- package/packages/mcp-adapter/dist/index.js.map +1 -0
- package/packages/mcp-adapter/dist/server.d.ts +9 -0
- package/packages/mcp-adapter/dist/server.d.ts.map +1 -0
- package/packages/mcp-adapter/dist/server.js +228 -0
- package/packages/mcp-adapter/dist/server.js.map +1 -0
- package/packages/mcp-adapter/dist/tools.d.ts +12 -0
- package/packages/mcp-adapter/dist/tools.d.ts.map +1 -0
- package/packages/mcp-adapter/dist/tools.js +178 -0
- package/packages/mcp-adapter/dist/tools.js.map +1 -0
- package/packages/mcp-adapter/dist/types.d.ts +80 -0
- package/packages/mcp-adapter/dist/types.d.ts.map +1 -0
- package/packages/mcp-adapter/dist/types.js +5 -0
- package/packages/mcp-adapter/dist/types.js.map +1 -0
- package/packages/mcp-adapter/package.json +21 -0
- package/packages/mcp-adapter/src/index.ts +20 -0
- package/packages/mcp-adapter/src/server.ts +273 -0
- package/packages/mcp-adapter/src/tools.ts +220 -0
- package/packages/mcp-adapter/src/types.ts +79 -0
- package/packages/mcp-adapter/test/server.test.ts +91 -0
- package/packages/mcp-adapter/tsconfig.json +8 -0
- package/packages/memory-engine/dist/engine.d.ts +15 -7
- package/packages/memory-engine/dist/engine.d.ts.map +1 -1
- package/packages/memory-engine/dist/engine.js +148 -25
- package/packages/memory-engine/dist/engine.js.map +1 -1
- package/packages/memory-engine/package.json +2 -2
- package/packages/memory-engine/src/engine.ts +166 -25
- package/packages/memory-engine/test/engine.test.ts +193 -8
- package/packages/model-registry/dist/registry.d.ts.map +1 -1
- package/packages/model-registry/package.json +1 -1
- package/packages/nextjs-plugin/README.md +1 -0
- package/packages/nextjs-plugin/dist/analyzer.d.ts +12 -0
- package/packages/nextjs-plugin/dist/analyzer.d.ts.map +1 -0
- package/packages/nextjs-plugin/dist/analyzer.js +217 -0
- package/packages/nextjs-plugin/dist/analyzer.js.map +1 -0
- package/packages/nextjs-plugin/dist/index.d.ts +8 -0
- package/packages/nextjs-plugin/dist/index.d.ts.map +1 -0
- package/packages/nextjs-plugin/dist/index.js +32 -0
- package/packages/nextjs-plugin/dist/index.js.map +1 -0
- package/packages/nextjs-plugin/dist/types.d.ts +33 -0
- package/packages/nextjs-plugin/dist/types.d.ts.map +1 -0
- package/packages/nextjs-plugin/dist/types.js +5 -0
- package/packages/nextjs-plugin/dist/types.js.map +1 -0
- package/packages/nextjs-plugin/package.json +30 -0
- package/packages/nextjs-plugin/src/analyzer.ts +247 -0
- package/packages/nextjs-plugin/src/index.ts +41 -0
- package/packages/nextjs-plugin/src/types.ts +36 -0
- package/packages/nextjs-plugin/test/analyzer.test.ts +149 -0
- package/packages/nextjs-plugin/tsconfig.json +12 -0
- package/packages/notification/dist/adapters/email-adapter.d.ts +17 -0
- package/packages/notification/dist/adapters/email-adapter.d.ts.map +1 -0
- package/packages/notification/dist/adapters/email-adapter.js +89 -0
- package/packages/notification/dist/adapters/email-adapter.js.map +1 -0
- package/packages/notification/dist/adapters/ntfy-adapter.d.ts +17 -0
- package/packages/notification/dist/adapters/ntfy-adapter.d.ts.map +1 -0
- package/packages/notification/dist/adapters/ntfy-adapter.js +84 -0
- package/packages/notification/dist/adapters/ntfy-adapter.js.map +1 -0
- package/packages/notification/dist/adapters/telegram-adapter.d.ts +17 -0
- package/packages/notification/dist/adapters/telegram-adapter.d.ts.map +1 -0
- package/packages/notification/dist/adapters/telegram-adapter.js +88 -0
- package/packages/notification/dist/adapters/telegram-adapter.js.map +1 -0
- package/packages/notification/dist/adapters/webhook-adapter.d.ts +15 -0
- package/packages/notification/dist/adapters/webhook-adapter.d.ts.map +1 -0
- package/packages/notification/dist/adapters/webhook-adapter.js +64 -0
- package/packages/notification/dist/adapters/webhook-adapter.js.map +1 -0
- package/packages/notification/dist/base-adapter.d.ts +36 -0
- package/packages/notification/dist/base-adapter.d.ts.map +1 -0
- package/packages/notification/dist/base-adapter.js +39 -0
- package/packages/notification/dist/base-adapter.js.map +1 -0
- package/packages/notification/dist/index.d.ts +9 -0
- package/packages/notification/dist/index.d.ts.map +1 -0
- package/packages/notification/dist/index.js +9 -0
- package/packages/notification/dist/index.js.map +1 -0
- package/packages/notification/dist/notification-center.d.ts +46 -0
- package/packages/notification/dist/notification-center.d.ts.map +1 -0
- package/packages/notification/dist/notification-center.js +228 -0
- package/packages/notification/dist/notification-center.js.map +1 -0
- package/packages/notification/dist/types.d.ts +65 -0
- package/packages/notification/dist/types.d.ts.map +1 -0
- package/packages/notification/dist/types.js +7 -0
- package/packages/notification/dist/types.js.map +1 -0
- package/packages/notification/package.json +22 -0
- package/packages/notification/src/adapters/email-adapter.ts +126 -0
- package/packages/notification/src/adapters/ntfy-adapter.ts +100 -0
- package/packages/notification/src/adapters/telegram-adapter.ts +107 -0
- package/packages/notification/src/adapters/webhook-adapter.ts +75 -0
- package/packages/notification/src/base-adapter.ts +75 -0
- package/packages/notification/src/index.ts +9 -0
- package/packages/notification/src/notification-center.ts +286 -0
- package/packages/notification/src/types.ts +89 -0
- package/packages/notification/test/notification.test.ts +372 -0
- package/packages/notification/tsconfig.json +8 -0
- package/packages/observability/dist/alerts.d.ts.map +1 -1
- package/packages/observability/dist/alerts.js.map +1 -1
- package/packages/observability/dist/health.d.ts.map +1 -1
- package/packages/observability/dist/logger.d.ts.map +1 -1
- package/packages/observability/dist/logger.js.map +1 -1
- package/packages/observability/dist/metrics.d.ts.map +1 -1
- package/packages/observability/dist/metrics.js.map +1 -1
- package/packages/observability/dist/tracer.d.ts.map +1 -1
- package/packages/observability/package.json +2 -2
- package/packages/observability/test/observability.test.ts +1331 -26
- package/packages/observability/tsconfig.tsbuildinfo +1 -1
- package/packages/performance-optimizer/dist/optimizer.d.ts.map +1 -1
- package/packages/performance-optimizer/dist/optimizer.js.map +1 -1
- package/packages/performance-optimizer/package.json +2 -2
- package/packages/project-analyzer/dist/analyzer.d.ts.map +1 -1
- package/packages/project-analyzer/dist/analyzer.js.map +1 -1
- package/packages/project-analyzer/dist/cache.d.ts.map +1 -1
- package/packages/project-analyzer/dist/cache.js.map +1 -1
- package/packages/project-analyzer/dist/rule-discovery.js.map +1 -1
- package/packages/project-analyzer/dist/signals.d.ts.map +1 -1
- package/packages/project-analyzer/dist/signals.js.map +1 -1
- package/packages/project-analyzer/dist/walker.d.ts.map +1 -1
- package/packages/project-analyzer/package.json +2 -2
- package/packages/project-analyzer/test/index.test.ts +1614 -124
- package/packages/project-analyzer/tsconfig.tsbuildinfo +1 -1
- package/packages/prompt-compiler/dist/compiler.d.ts.map +1 -1
- package/packages/prompt-compiler/dist/types.d.ts.map +1 -1
- package/packages/prompt-compiler/package.json +2 -2
- package/packages/prompt-versioning/dist/index.d.ts +6 -0
- package/packages/prompt-versioning/dist/index.d.ts.map +1 -0
- package/packages/prompt-versioning/dist/index.js +5 -0
- package/packages/prompt-versioning/dist/index.js.map +1 -0
- package/packages/prompt-versioning/dist/types.d.ts +37 -0
- package/packages/prompt-versioning/dist/types.d.ts.map +1 -0
- package/packages/prompt-versioning/dist/types.js +5 -0
- package/packages/prompt-versioning/dist/types.js.map +1 -0
- package/packages/prompt-versioning/dist/versioning.d.ts +26 -0
- package/packages/prompt-versioning/dist/versioning.d.ts.map +1 -0
- package/packages/prompt-versioning/dist/versioning.js +130 -0
- package/packages/prompt-versioning/dist/versioning.js.map +1 -0
- package/packages/prompt-versioning/package.json +21 -0
- package/packages/prompt-versioning/src/index.ts +6 -0
- package/packages/prompt-versioning/src/types.ts +41 -0
- package/packages/prompt-versioning/src/versioning.ts +149 -0
- package/packages/prompt-versioning/test/versioning.test.ts +112 -0
- package/packages/prompt-versioning/tsconfig.json +5 -0
- package/packages/provider-adapter-sdk/dist/builder.d.ts.map +1 -1
- package/packages/provider-adapter-sdk/dist/errors.d.ts +2 -2
- package/packages/provider-adapter-sdk/dist/errors.d.ts.map +1 -1
- package/packages/provider-adapter-sdk/dist/errors.js.map +1 -1
- package/packages/provider-adapter-sdk/dist/registry.d.ts.map +1 -1
- package/packages/provider-adapter-sdk/dist/registry.js.map +1 -1
- package/packages/provider-adapter-sdk/dist/tester.d.ts.map +1 -1
- package/packages/provider-adapter-sdk/dist/tester.js.map +1 -1
- package/packages/provider-adapter-sdk/package.json +2 -2
- package/packages/provider-adapter-sdk/tsconfig.tsbuildinfo +1 -1
- package/packages/provider-router/package.json +1 -1
- package/packages/provider-selector/dist/index.d.ts +6 -0
- package/packages/provider-selector/dist/index.d.ts.map +1 -0
- package/packages/provider-selector/dist/index.js +5 -0
- package/packages/provider-selector/dist/index.js.map +1 -0
- package/packages/provider-selector/dist/selector.d.ts +17 -0
- package/packages/provider-selector/dist/selector.d.ts.map +1 -0
- package/packages/provider-selector/dist/selector.js +93 -0
- package/packages/provider-selector/dist/selector.js.map +1 -0
- package/packages/provider-selector/dist/types.d.ts +26 -0
- package/packages/provider-selector/dist/types.d.ts.map +1 -0
- package/packages/provider-selector/dist/types.js +5 -0
- package/packages/provider-selector/dist/types.js.map +1 -0
- package/packages/provider-selector/package.json +21 -0
- package/packages/provider-selector/src/index.ts +13 -0
- package/packages/provider-selector/src/selector.ts +120 -0
- package/packages/provider-selector/src/types.ts +33 -0
- package/packages/provider-selector/test/selector.test.ts +192 -0
- package/packages/provider-selector/tsconfig.json +6 -0
- package/packages/providers/dist/adapters.d.ts +133 -0
- package/packages/providers/dist/adapters.d.ts.map +1 -0
- package/packages/providers/dist/adapters.js +236 -0
- package/packages/providers/dist/adapters.js.map +1 -0
- package/packages/providers/dist/deepagents-adapter.d.ts +78 -0
- package/packages/providers/dist/deepagents-adapter.d.ts.map +1 -0
- package/packages/providers/dist/deepagents-adapter.js +323 -0
- package/packages/providers/dist/deepagents-adapter.js.map +1 -0
- package/packages/providers/dist/glm-usage.d.ts +102 -0
- package/packages/providers/dist/glm-usage.d.ts.map +1 -0
- package/packages/providers/dist/glm-usage.js +197 -0
- package/packages/providers/dist/glm-usage.js.map +1 -0
- package/packages/providers/dist/index.d.ts +10 -0
- package/packages/providers/dist/index.d.ts.map +1 -0
- package/packages/providers/dist/index.js +10 -0
- package/packages/providers/dist/index.js.map +1 -0
- package/packages/providers/dist/openai-usage.d.ts +103 -0
- package/packages/providers/dist/openai-usage.d.ts.map +1 -0
- package/packages/providers/dist/openai-usage.js +208 -0
- package/packages/providers/dist/openai-usage.js.map +1 -0
- package/packages/providers/package.json +22 -0
- package/packages/providers/src/adapters.ts +362 -0
- package/packages/providers/src/deepagents-adapter.ts +458 -0
- package/packages/providers/src/glm-usage.ts +248 -0
- package/packages/providers/src/index.ts +10 -0
- package/packages/providers/src/openai-usage.ts +263 -0
- package/packages/providers/test/providers.test.ts +225 -0
- package/packages/providers/tsconfig.json +8 -0
- package/packages/quota-manager/dist/examples/tui-usage-integration.d.ts +35 -0
- package/packages/quota-manager/dist/examples/tui-usage-integration.d.ts.map +1 -0
- package/packages/quota-manager/dist/examples/tui-usage-integration.js +73 -0
- package/packages/quota-manager/dist/examples/tui-usage-integration.js.map +1 -0
- package/packages/quota-manager/dist/index.d.ts +8 -0
- package/packages/quota-manager/dist/index.d.ts.map +1 -0
- package/packages/quota-manager/dist/index.js +8 -0
- package/packages/quota-manager/dist/index.js.map +1 -0
- package/packages/quota-manager/dist/quota-manager.d.ts +70 -0
- package/packages/quota-manager/dist/quota-manager.d.ts.map +1 -0
- package/packages/quota-manager/dist/quota-manager.js +260 -0
- package/packages/quota-manager/dist/quota-manager.js.map +1 -0
- package/packages/quota-manager/dist/tui-usage-monitor.d.ts +96 -0
- package/packages/quota-manager/dist/tui-usage-monitor.d.ts.map +1 -0
- package/packages/quota-manager/dist/tui-usage-monitor.js +269 -0
- package/packages/quota-manager/dist/tui-usage-monitor.js.map +1 -0
- package/packages/quota-manager/package.json +22 -0
- package/packages/quota-manager/src/examples/tui-usage-integration.ts +72 -0
- package/packages/quota-manager/src/index.ts +8 -0
- package/packages/quota-manager/src/quota-manager.ts +339 -0
- package/packages/quota-manager/src/tui-usage-monitor.ts +355 -0
- package/packages/quota-manager/test/quota.test.ts +432 -0
- package/packages/quota-manager/tsconfig.json +8 -0
- package/packages/rate-limiter/dist/index.d.ts +6 -0
- package/packages/rate-limiter/dist/index.d.ts.map +1 -0
- package/packages/rate-limiter/dist/index.js +5 -0
- package/packages/rate-limiter/dist/index.js.map +1 -0
- package/packages/rate-limiter/dist/limiter.d.ts +20 -0
- package/packages/rate-limiter/dist/limiter.d.ts.map +1 -0
- package/packages/rate-limiter/dist/limiter.js +101 -0
- package/packages/rate-limiter/dist/limiter.js.map +1 -0
- package/packages/rate-limiter/dist/types.d.ts +36 -0
- package/packages/rate-limiter/dist/types.d.ts.map +1 -0
- package/packages/rate-limiter/dist/types.js +5 -0
- package/packages/rate-limiter/dist/types.js.map +1 -0
- package/packages/rate-limiter/package.json +21 -0
- package/packages/rate-limiter/src/index.ts +6 -0
- package/packages/rate-limiter/src/limiter.ts +122 -0
- package/packages/rate-limiter/src/types.ts +41 -0
- package/packages/rate-limiter/test/limiter.test.ts +128 -0
- package/packages/rate-limiter/tsconfig.json +5 -0
- package/packages/react-vite-plugin/README.md +1 -0
- package/packages/react-vite-plugin/dist/analyzer.d.ts +8 -0
- package/packages/react-vite-plugin/dist/analyzer.d.ts.map +1 -0
- package/packages/react-vite-plugin/dist/analyzer.js +193 -0
- package/packages/react-vite-plugin/dist/analyzer.js.map +1 -0
- package/packages/react-vite-plugin/dist/index.d.ts +8 -0
- package/packages/react-vite-plugin/dist/index.d.ts.map +1 -0
- package/packages/react-vite-plugin/dist/index.js +30 -0
- package/packages/react-vite-plugin/dist/index.js.map +1 -0
- package/packages/react-vite-plugin/dist/types.d.ts +26 -0
- package/packages/react-vite-plugin/dist/types.d.ts.map +1 -0
- package/packages/react-vite-plugin/dist/types.js +5 -0
- package/packages/react-vite-plugin/dist/types.js.map +1 -0
- package/packages/react-vite-plugin/package.json +20 -0
- package/packages/react-vite-plugin/src/analyzer.ts +226 -0
- package/packages/react-vite-plugin/src/index.ts +39 -0
- package/packages/react-vite-plugin/src/types.ts +28 -0
- package/packages/react-vite-plugin/test/analyzer.test.ts +139 -0
- package/packages/react-vite-plugin/tsconfig.json +12 -0
- package/packages/release-manager/dist/changelog.d.ts +14 -0
- package/packages/release-manager/dist/changelog.d.ts.map +1 -0
- package/packages/release-manager/dist/changelog.js +126 -0
- package/packages/release-manager/dist/changelog.js.map +1 -0
- package/packages/release-manager/dist/index.d.ts +7 -0
- package/packages/release-manager/dist/index.d.ts.map +1 -0
- package/packages/release-manager/dist/index.js +6 -0
- package/packages/release-manager/dist/index.js.map +1 -0
- package/packages/release-manager/dist/types.d.ts +36 -0
- package/packages/release-manager/dist/types.d.ts.map +1 -0
- package/packages/release-manager/dist/types.js +5 -0
- package/packages/release-manager/dist/types.js.map +1 -0
- package/packages/release-manager/dist/version.d.ts +10 -0
- package/packages/release-manager/dist/version.d.ts.map +1 -0
- package/packages/release-manager/dist/version.js +53 -0
- package/packages/release-manager/dist/version.js.map +1 -0
- package/packages/release-manager/package.json +21 -0
- package/packages/release-manager/src/changelog.ts +148 -0
- package/packages/release-manager/src/index.ts +21 -0
- package/packages/release-manager/src/types.ts +50 -0
- package/packages/release-manager/src/version.ts +52 -0
- package/packages/release-manager/test/release.test.ts +215 -0
- package/packages/release-manager/tsconfig.json +5 -0
- package/packages/requirement-compiler/dist/types.d.ts.map +1 -1
- package/packages/requirement-compiler/dist/types.js.map +1 -1
- package/packages/requirement-compiler/package.json +1 -1
- package/packages/runtime/dist/command-executor.d.ts +129 -0
- package/packages/runtime/dist/command-executor.d.ts.map +1 -0
- package/packages/runtime/dist/command-executor.js +383 -0
- package/packages/runtime/dist/command-executor.js.map +1 -0
- package/packages/runtime/dist/index.d.ts +11 -0
- package/packages/runtime/dist/index.d.ts.map +1 -0
- package/packages/runtime/dist/index.js +11 -0
- package/packages/runtime/dist/index.js.map +1 -0
- package/packages/runtime/dist/local-runtime-agent.d.ts +111 -0
- package/packages/runtime/dist/local-runtime-agent.d.ts.map +1 -0
- package/packages/runtime/dist/local-runtime-agent.js +356 -0
- package/packages/runtime/dist/local-runtime-agent.js.map +1 -0
- package/packages/runtime/dist/policy-engine.d.ts +203 -0
- package/packages/runtime/dist/policy-engine.d.ts.map +1 -0
- package/packages/runtime/dist/policy-engine.js +592 -0
- package/packages/runtime/dist/policy-engine.js.map +1 -0
- package/packages/runtime/dist/runtime-api.d.ts +137 -0
- package/packages/runtime/dist/runtime-api.d.ts.map +1 -0
- package/packages/runtime/dist/runtime-api.js +454 -0
- package/packages/runtime/dist/runtime-api.js.map +1 -0
- package/packages/runtime/dist/workspace-manager.d.ts +162 -0
- package/packages/runtime/dist/workspace-manager.d.ts.map +1 -0
- package/packages/runtime/dist/workspace-manager.js +451 -0
- package/packages/runtime/dist/workspace-manager.js.map +1 -0
- package/packages/runtime/package.json +22 -0
- package/packages/runtime/src/command-executor.ts +523 -0
- package/packages/runtime/src/index.ts +11 -0
- package/packages/runtime/src/local-runtime-agent.ts +480 -0
- package/packages/runtime/src/policy-engine.ts +813 -0
- package/packages/runtime/src/runtime-api.ts +665 -0
- package/packages/runtime/src/workspace-manager.ts +591 -0
- package/packages/runtime/test/runtime.test.ts +297 -0
- package/packages/runtime/tsconfig.json +8 -0
- package/packages/scheduler/package.json +22 -0
- package/packages/scheduler/test/scheduler.test.ts +125 -0
- package/packages/session/dist/history.d.ts.map +1 -1
- package/packages/session/dist/history.js.map +1 -1
- package/packages/session/dist/manager.d.ts.map +1 -1
- package/packages/session/dist/manager.js.map +1 -1
- package/packages/session/dist/policy.d.ts.map +1 -1
- package/packages/session/dist/policy.js.map +1 -1
- package/packages/session/dist/store.d.ts.map +1 -1
- package/packages/session/package.json +2 -2
- package/packages/session/tsconfig.tsbuildinfo +1 -1
- package/packages/shared-context/package.json +22 -0
- package/packages/shared-context/src/index.ts +7 -0
- package/packages/shared-context/test/shared-context.test.ts +114 -0
- package/packages/skill-registry/dist/defaults.d.ts.map +1 -1
- package/packages/skill-registry/dist/defaults.js +51 -0
- package/packages/skill-registry/dist/defaults.js.map +1 -1
- package/packages/skill-registry/dist/matching.js.map +1 -1
- package/packages/skill-registry/dist/registry.d.ts +6 -6
- package/packages/skill-registry/dist/registry.d.ts.map +1 -1
- package/packages/skill-registry/dist/registry.js +27 -4
- package/packages/skill-registry/dist/registry.js.map +1 -1
- package/packages/skill-registry/dist/types.d.ts +1 -4
- package/packages/skill-registry/dist/types.d.ts.map +1 -1
- package/packages/skill-registry/package.json +1 -1
- package/packages/skill-registry/src/defaults.ts +54 -0
- package/packages/skill-registry/src/registry.ts +40 -5
- package/packages/skill-registry/src/types.ts +1 -1
- package/packages/skill-registry/test/registry.test.ts +145 -1
- package/packages/sprint-planner/dist/decomposer.d.ts +13 -0
- package/packages/sprint-planner/dist/decomposer.d.ts.map +1 -0
- package/packages/sprint-planner/dist/decomposer.js +38 -0
- package/packages/sprint-planner/dist/decomposer.js.map +1 -0
- package/packages/sprint-planner/dist/index.d.ts +7 -0
- package/packages/sprint-planner/dist/index.d.ts.map +1 -0
- package/packages/sprint-planner/dist/index.js +6 -0
- package/packages/sprint-planner/dist/index.js.map +1 -0
- package/packages/sprint-planner/dist/planner.d.ts +9 -0
- package/packages/sprint-planner/dist/planner.d.ts.map +1 -0
- package/packages/sprint-planner/dist/planner.js +114 -0
- package/packages/sprint-planner/dist/planner.js.map +1 -0
- package/packages/sprint-planner/dist/types.d.ts +51 -0
- package/packages/sprint-planner/dist/types.d.ts.map +1 -0
- package/packages/sprint-planner/dist/types.js +5 -0
- package/packages/sprint-planner/dist/types.js.map +1 -0
- package/packages/sprint-planner/package.json +21 -0
- package/packages/sprint-planner/src/decomposer.ts +57 -0
- package/packages/sprint-planner/src/index.ts +16 -0
- package/packages/sprint-planner/src/planner.ts +150 -0
- package/packages/sprint-planner/src/types.ts +59 -0
- package/packages/sprint-planner/test/planner.test.ts +187 -0
- package/packages/sprint-planner/tsconfig.json +5 -0
- package/packages/task-compiler/dist/command-policy.js.map +1 -1
- package/packages/task-compiler/dist/file-scope.js.map +1 -1
- package/packages/task-compiler/dist/types.d.ts.map +1 -1
- package/packages/task-compiler/dist/verification.js.map +1 -1
- package/packages/task-compiler/package.json +1 -1
- package/packages/test-data-generator/dist/faker-adapter.d.ts.map +1 -1
- package/packages/test-data-generator/dist/faker-adapter.js.map +1 -1
- package/packages/test-data-generator/dist/generator.d.ts.map +1 -1
- package/packages/test-data-generator/dist/generator.js.map +1 -1
- package/packages/test-data-generator/package.json +2 -2
- package/packages/test-data-generator/tsconfig.tsbuildinfo +1 -1
- package/packages/test-generator/dist/generator.d.ts +13 -0
- package/packages/test-generator/dist/generator.d.ts.map +1 -0
- package/packages/test-generator/dist/generator.js +116 -0
- package/packages/test-generator/dist/generator.js.map +1 -0
- package/packages/test-generator/dist/index.d.ts +6 -0
- package/packages/test-generator/dist/index.d.ts.map +1 -0
- package/packages/test-generator/dist/index.js +5 -0
- package/packages/test-generator/dist/index.js.map +1 -0
- package/packages/test-generator/dist/types.d.ts +34 -0
- package/packages/test-generator/dist/types.d.ts.map +1 -0
- package/packages/test-generator/dist/types.js +5 -0
- package/packages/test-generator/dist/types.js.map +1 -0
- package/packages/test-generator/package.json +21 -0
- package/packages/test-generator/src/generator.ts +144 -0
- package/packages/test-generator/src/index.ts +11 -0
- package/packages/test-generator/src/types.ts +39 -0
- package/packages/test-generator/test/generator.test.ts +156 -0
- package/packages/test-generator/tsconfig.json +6 -0
- package/packages/token-estimation/package.json +22 -0
- package/packages/token-estimation/test/token-estimation.test.ts +207 -0
- package/packages/token-optimizer/dist/index.d.ts +6 -0
- package/packages/token-optimizer/dist/index.d.ts.map +1 -0
- package/packages/token-optimizer/dist/index.js +5 -0
- package/packages/token-optimizer/dist/index.js.map +1 -0
- package/packages/token-optimizer/dist/optimizer.d.ts +29 -0
- package/packages/token-optimizer/dist/optimizer.d.ts.map +1 -0
- package/packages/token-optimizer/dist/optimizer.js +106 -0
- package/packages/token-optimizer/dist/optimizer.js.map +1 -0
- package/packages/token-optimizer/dist/types.d.ts +36 -0
- package/packages/token-optimizer/dist/types.d.ts.map +1 -0
- package/packages/token-optimizer/dist/types.js +5 -0
- package/packages/token-optimizer/dist/types.js.map +1 -0
- package/packages/token-optimizer/package.json +21 -0
- package/packages/token-optimizer/src/index.ts +15 -0
- package/packages/token-optimizer/src/optimizer.ts +150 -0
- package/packages/token-optimizer/src/types.ts +47 -0
- package/packages/token-optimizer/test/optimizer.test.ts +141 -0
- package/packages/token-optimizer/tsconfig.json +6 -0
- package/packages/tui/package.json +22 -0
- package/packages/tui/tsconfig.json +8 -0
- package/packages/types/dist/agent-worker-types.d.ts.map +1 -1
- package/packages/types/package.json +1 -1
- package/packages/types/tsconfig.tsbuildinfo +1 -1
- package/packages/worktree/dist/index.d.ts +7 -0
- package/packages/worktree/dist/index.d.ts.map +1 -0
- package/packages/worktree/dist/index.js +7 -0
- package/packages/worktree/dist/index.js.map +1 -0
- package/packages/worktree/dist/worktree.d.ts +88 -0
- package/packages/worktree/dist/worktree.d.ts.map +1 -0
- package/packages/worktree/dist/worktree.js +242 -0
- package/packages/worktree/dist/worktree.js.map +1 -0
- package/packages/worktree/package.json +22 -0
- package/packages/worktree/src/index.ts +7 -0
- package/packages/worktree/src/worktree.ts +293 -0
- package/packages/worktree/test/worktree.test.ts +163 -0
- package/packages/worktree/tsconfig.json +8 -0
- package/proactive-compact.ts +53 -0
- package/status-parsers.ts +84 -0
|
@@ -1,20 +1,62 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Project Analyzer Tests
|
|
2
|
+
* Project Analyzer Tests (comprehensive)
|
|
3
|
+
*
|
|
4
|
+
* Tests for ProjectAnalyzer, detectLanguages, detectPackageManager,
|
|
5
|
+
* command discovery, caching, and filesystem walker.
|
|
3
6
|
*/
|
|
4
7
|
|
|
5
|
-
import { describe, test, expect, beforeEach } from "bun:test";
|
|
8
|
+
import { describe, test, expect, afterEach, beforeEach } from "bun:test";
|
|
9
|
+
import { mkdtemp, writeFile, mkdir, rm } from "node:fs/promises";
|
|
6
10
|
import { join } from "node:path";
|
|
11
|
+
import { tmpdir } from "node:os";
|
|
12
|
+
|
|
7
13
|
import {
|
|
8
14
|
ProjectAnalyzer,
|
|
9
15
|
createProjectAnalyzer,
|
|
10
16
|
detectLanguages,
|
|
11
17
|
} from "../src/index.js";
|
|
18
|
+
import {
|
|
19
|
+
AnalysisCache,
|
|
20
|
+
hashRuleFiles,
|
|
21
|
+
hashManifestFiles,
|
|
22
|
+
} from "../src/cache.js";
|
|
23
|
+
import {
|
|
24
|
+
parsePackageJsonScripts,
|
|
25
|
+
categorizeCommands,
|
|
26
|
+
detectPackageManager,
|
|
27
|
+
parsePythonCommands,
|
|
28
|
+
parseComposerScripts,
|
|
29
|
+
} from "../src/command-discovery.js";
|
|
30
|
+
import { FileSystemWalker } from "../src/walker.js";
|
|
31
|
+
import { GenericFrameworkDetector, scanSignals } from "../src/signals.js";
|
|
32
|
+
import {
|
|
33
|
+
parseRuleFile,
|
|
34
|
+
discoverRuleFiles,
|
|
35
|
+
mergeRules,
|
|
36
|
+
} from "../src/rule-discovery.js";
|
|
12
37
|
|
|
13
|
-
// ───
|
|
38
|
+
// ─── Temp Fixture Helpers ─────────────────────────────────────────────
|
|
14
39
|
|
|
15
|
-
const
|
|
40
|
+
const tempDirs: string[] = [];
|
|
41
|
+
|
|
42
|
+
async function tmpDir(): Promise<string> {
|
|
43
|
+
const d = await mkdtemp(join(tmpdir(), "proj-analyzer-"));
|
|
44
|
+
tempDirs.push(d);
|
|
45
|
+
return d;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
afterEach(async () => {
|
|
49
|
+
for (const d of tempDirs) {
|
|
50
|
+
try {
|
|
51
|
+
await rm(d, { recursive: true, force: true });
|
|
52
|
+
} catch {
|
|
53
|
+
// ignore
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
tempDirs.length = 0;
|
|
57
|
+
});
|
|
16
58
|
|
|
17
|
-
// ───
|
|
59
|
+
// ─── detectLanguages Tests ────────────────────────────────────────────
|
|
18
60
|
|
|
19
61
|
describe("detectLanguages", () => {
|
|
20
62
|
test("detects TypeScript files", () => {
|
|
@@ -23,207 +65,1655 @@ describe("detectLanguages", () => {
|
|
|
23
65
|
{ relativePath: "src/app.ts", size: 500 },
|
|
24
66
|
{ relativePath: "src/types.ts", size: 300 },
|
|
25
67
|
];
|
|
68
|
+
const langs = detectLanguages(files);
|
|
69
|
+
expect(langs.find((l) => l.name === "TypeScript")).toBeDefined();
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
test("detects Python files", () => {
|
|
73
|
+
const files = [
|
|
74
|
+
{ relativePath: "app/main.py", size: 5000 },
|
|
75
|
+
{ relativePath: "app/models.py", size: 2000 },
|
|
76
|
+
];
|
|
77
|
+
const langs = detectLanguages(files);
|
|
78
|
+
expect(langs.find((l) => l.name === "Python")).toBeDefined();
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
test("detects Go files", () => {
|
|
82
|
+
const files = [{ relativePath: "cmd/main.go", size: 3000 }];
|
|
83
|
+
const langs = detectLanguages(files);
|
|
84
|
+
expect(langs.find((l) => l.name === "Go")).toBeDefined();
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
test("detects Java and Kotlin files", () => {
|
|
88
|
+
const files = [
|
|
89
|
+
{ relativePath: "src/Main.java", size: 2000 },
|
|
90
|
+
{ relativePath: "src/Utils.kt", size: 1000 },
|
|
91
|
+
];
|
|
92
|
+
const langs = detectLanguages(files);
|
|
93
|
+
expect(langs.find((l) => l.name === "Java")).toBeDefined();
|
|
94
|
+
expect(langs.find((l) => l.name === "JavaScript")).toBeUndefined();
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
test("detects Rust files", () => {
|
|
98
|
+
const files = [{ relativePath: "src/lib.rs", size: 4000 }];
|
|
99
|
+
const langs = detectLanguages(files);
|
|
100
|
+
expect(langs.find((l) => l.name === "Rust")).toBeDefined();
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
test("detects C# files", () => {
|
|
104
|
+
const files = [{ relativePath: "Program.cs", size: 1500 }];
|
|
105
|
+
const langs = detectLanguages(files);
|
|
106
|
+
expect(langs.find((l) => l.name === "C#")).toBeDefined();
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
test("detects HTML and CSS", () => {
|
|
110
|
+
const files = [
|
|
111
|
+
{ relativePath: "index.html", size: 2000 },
|
|
112
|
+
{ relativePath: "styles.css", size: 500 },
|
|
113
|
+
{ relativePath: "theme.scss", size: 800 },
|
|
114
|
+
];
|
|
115
|
+
const langs = detectLanguages(files);
|
|
116
|
+
expect(langs.find((l) => l.name === "HTML")).toBeDefined();
|
|
117
|
+
expect(langs.find((l) => l.name === "CSS")).toBeDefined();
|
|
118
|
+
});
|
|
26
119
|
|
|
27
|
-
|
|
120
|
+
test("detects multiple languages with correct coverage", () => {
|
|
121
|
+
const files = [
|
|
122
|
+
{ relativePath: "main.ts", size: 500 },
|
|
123
|
+
{ relativePath: "app.py", size: 1000 },
|
|
124
|
+
];
|
|
125
|
+
const langs = detectLanguages(files);
|
|
126
|
+
const py = langs.find((l) => l.name === "Python");
|
|
127
|
+
const ts = langs.find((l) => l.name === "TypeScript");
|
|
128
|
+
expect(py).toBeDefined();
|
|
129
|
+
expect(ts).toBeDefined();
|
|
130
|
+
// Python should have higher coverage (1000 vs 500 bytes)
|
|
131
|
+
expect(py!.coverage).toBeGreaterThan(ts!.coverage);
|
|
132
|
+
});
|
|
28
133
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
134
|
+
test("sorts languages by coverage descending", () => {
|
|
135
|
+
const files = [
|
|
136
|
+
{ relativePath: "main.js", size: 9000 },
|
|
137
|
+
{ relativePath: "main.ts", size: 1000 },
|
|
138
|
+
];
|
|
139
|
+
const langs = detectLanguages(files);
|
|
140
|
+
expect(langs[0].name).toBe("JavaScript");
|
|
141
|
+
expect(langs[1].name).toBe("TypeScript");
|
|
33
142
|
});
|
|
34
143
|
|
|
35
144
|
test("handles empty file list", () => {
|
|
36
|
-
|
|
37
|
-
expect(languages).toEqual([]);
|
|
145
|
+
expect(detectLanguages([])).toEqual([]);
|
|
38
146
|
});
|
|
39
147
|
|
|
40
|
-
test("
|
|
148
|
+
test("handles files with no recognized extensions", () => {
|
|
41
149
|
const files = [
|
|
42
|
-
{ relativePath: "
|
|
43
|
-
{ relativePath: "
|
|
150
|
+
{ relativePath: "README", size: 500 },
|
|
151
|
+
{ relativePath: "Makefile", size: 200 },
|
|
44
152
|
];
|
|
153
|
+
const langs = detectLanguages(files);
|
|
154
|
+
expect(langs).toEqual([]);
|
|
155
|
+
});
|
|
156
|
+
|
|
157
|
+
test("handles mixed TSX and JSX files", () => {
|
|
158
|
+
const files = [
|
|
159
|
+
{ relativePath: "Component.tsx", size: 500 },
|
|
160
|
+
{ relativePath: "App.jsx", size: 300 },
|
|
161
|
+
];
|
|
162
|
+
const langs = detectLanguages(files);
|
|
163
|
+
const ts = langs.find((l) => l.name === "TypeScript");
|
|
164
|
+
expect(ts).toBeDefined();
|
|
165
|
+
});
|
|
45
166
|
|
|
46
|
-
|
|
167
|
+
test("handles Swift files", () => {
|
|
168
|
+
const files = [{ relativePath: "iOS/App.swift", size: 2000 }];
|
|
169
|
+
const langs = detectLanguages(files);
|
|
170
|
+
expect(langs.find((l) => l.name === "Swift")).toBeDefined();
|
|
171
|
+
});
|
|
47
172
|
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
const
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
173
|
+
test("handles SQL files", () => {
|
|
174
|
+
const files = [{ relativePath: "schema.sql", size: 3000 }];
|
|
175
|
+
const langs = detectLanguages(files);
|
|
176
|
+
expect(langs.find((l) => l.name === "SQL")).toBeDefined();
|
|
177
|
+
});
|
|
178
|
+
|
|
179
|
+
test("handles Markdown files", () => {
|
|
180
|
+
const files = [
|
|
181
|
+
{ relativePath: "README.md", size: 1000 },
|
|
182
|
+
{ relativePath: "CHANGELOG.md", size: 500 },
|
|
183
|
+
];
|
|
184
|
+
const langs = detectLanguages(files);
|
|
185
|
+
expect(langs.find((l) => l.name === "Markdown")).toBeDefined();
|
|
186
|
+
});
|
|
187
|
+
|
|
188
|
+
test("coverage sums to 1.0 for single language", () => {
|
|
189
|
+
const files = [
|
|
190
|
+
{ relativePath: "a.py", size: 300 },
|
|
191
|
+
{ relativePath: "b.py", size: 700 },
|
|
192
|
+
];
|
|
193
|
+
const langs = detectLanguages(files);
|
|
194
|
+
const py = langs.find((l) => l.name === "Python");
|
|
195
|
+
expect(py!.coverage).toBeCloseTo(1.0, 2);
|
|
196
|
+
});
|
|
197
|
+
});
|
|
198
|
+
|
|
199
|
+
// ─── detectPackageManager Tests ───────────────────────────────────────
|
|
200
|
+
|
|
201
|
+
describe("detectPackageManager", () => {
|
|
202
|
+
test("detects npm from package.json", () => {
|
|
203
|
+
const result = detectPackageManager(["package.json"]);
|
|
204
|
+
expect(result).toBe("npm");
|
|
205
|
+
});
|
|
206
|
+
|
|
207
|
+
test("detects npm from package-lock.json", () => {
|
|
208
|
+
const result = detectPackageManager(["package-lock.json"]);
|
|
209
|
+
expect(result).toBe("npm");
|
|
210
|
+
});
|
|
211
|
+
|
|
212
|
+
test("detects yarn from yarn.lock", () => {
|
|
213
|
+
const result = detectPackageManager(["yarn.lock"]);
|
|
214
|
+
expect(result).toBe("yarn");
|
|
215
|
+
});
|
|
216
|
+
|
|
217
|
+
test("detects pnpm from pnpm-lock.yaml", () => {
|
|
218
|
+
const result = detectPackageManager(["pnpm-lock.yaml"]);
|
|
219
|
+
expect(result).toBe("pnpm");
|
|
220
|
+
});
|
|
221
|
+
|
|
222
|
+
test("detects bun from bun.lockb", () => {
|
|
223
|
+
const result = detectPackageManager(["bun.lockb"]);
|
|
224
|
+
expect(result).toBe("bun");
|
|
225
|
+
});
|
|
226
|
+
|
|
227
|
+
test("detects pip from requirements.txt", () => {
|
|
228
|
+
const result = detectPackageManager(["requirements.txt"]);
|
|
229
|
+
expect(result).toBe("pip");
|
|
230
|
+
});
|
|
231
|
+
|
|
232
|
+
test("detects poetry from pyproject.toml", () => {
|
|
233
|
+
const result = detectPackageManager(["pyproject.toml"]);
|
|
234
|
+
expect(result).toBe("poetry");
|
|
235
|
+
});
|
|
236
|
+
|
|
237
|
+
test("detects poetry from poetry.lock", () => {
|
|
238
|
+
const result = detectPackageManager(["poetry.lock"]);
|
|
239
|
+
expect(result).toBe("poetry");
|
|
240
|
+
});
|
|
241
|
+
|
|
242
|
+
test("returns null for empty list", () => {
|
|
243
|
+
expect(detectPackageManager([])).toBeNull();
|
|
244
|
+
});
|
|
245
|
+
|
|
246
|
+
test("prefers npm over yarn when both present", () => {
|
|
247
|
+
// npm gets score 1 (package.json), yarn gets score 1 (yarn.lock)
|
|
248
|
+
// npm comes first in tiebreak since it's the first non-zero score
|
|
249
|
+
const result = detectPackageManager(["package.json", "yarn.lock"]);
|
|
250
|
+
// yarn.lock beats package.json signal for yarn
|
|
251
|
+
expect(result === "yarn" || result === "npm").toBe(true);
|
|
252
|
+
});
|
|
253
|
+
|
|
254
|
+
test("handles nested paths", () => {
|
|
255
|
+
const result = detectPackageManager(["apps/frontend/package.json"]);
|
|
256
|
+
expect(result).toBe("npm");
|
|
257
|
+
});
|
|
258
|
+
|
|
259
|
+
test("detects bench from apps.txt", () => {
|
|
260
|
+
const result = detectPackageManager(["apps.txt"]);
|
|
261
|
+
expect(result).toBe("bench");
|
|
262
|
+
});
|
|
263
|
+
|
|
264
|
+
test("detects bench from sites directory", () => {
|
|
265
|
+
const result = detectPackageManager(["sites/", "apps.txt"]);
|
|
266
|
+
expect(result).toBe("bench");
|
|
267
|
+
});
|
|
268
|
+
|
|
269
|
+
test("score beats previous with multiple signals", () => {
|
|
270
|
+
// yarn.lock gives yarn score 1; package-lock.json gives npm score 1; yarn wins on order
|
|
271
|
+
// Use only yarn.lock so only yarn has a signal
|
|
272
|
+
const result = detectPackageManager(["yarn.lock"]);
|
|
273
|
+
expect(result).toBe("yarn");
|
|
274
|
+
});
|
|
275
|
+
});
|
|
276
|
+
|
|
277
|
+
// ─── parsePackageJsonScripts Tests ────────────────────────────────────
|
|
278
|
+
|
|
279
|
+
describe("parsePackageJsonScripts", () => {
|
|
280
|
+
test("extracts all scripts", () => {
|
|
281
|
+
const pkg = {
|
|
282
|
+
scripts: {
|
|
283
|
+
test: "vitest",
|
|
284
|
+
build: "tsc && vite build",
|
|
285
|
+
dev: "vite",
|
|
286
|
+
},
|
|
287
|
+
};
|
|
288
|
+
const cmds = parsePackageJsonScripts(pkg);
|
|
289
|
+
expect(cmds.length).toBe(3);
|
|
290
|
+
});
|
|
291
|
+
|
|
292
|
+
test("marks test as primary", () => {
|
|
293
|
+
const pkg = { scripts: { test: "jest" } };
|
|
294
|
+
const cmds = parsePackageJsonScripts(pkg);
|
|
295
|
+
expect(cmds.find((c) => c.command === "npm run test")?.primary).toBe(true);
|
|
296
|
+
});
|
|
297
|
+
|
|
298
|
+
test("marks build as primary", () => {
|
|
299
|
+
const pkg = { scripts: { build: "webpack" } };
|
|
300
|
+
const cmds = parsePackageJsonScripts(pkg);
|
|
301
|
+
expect(cmds.find((c) => c.command === "npm run build")?.primary).toBe(true);
|
|
302
|
+
});
|
|
303
|
+
|
|
304
|
+
test("marks dev as primary", () => {
|
|
305
|
+
const pkg = { scripts: { dev: "vite" } };
|
|
306
|
+
const cmds = parsePackageJsonScripts(pkg);
|
|
307
|
+
expect(cmds.find((c) => c.command === "npm run dev")?.primary).toBe(true);
|
|
308
|
+
});
|
|
309
|
+
|
|
310
|
+
test("marks start as primary", () => {
|
|
311
|
+
const pkg = { scripts: { start: "node server.js" } };
|
|
312
|
+
const cmds = parsePackageJsonScripts(pkg);
|
|
313
|
+
expect(cmds.find((c) => c.command === "npm run start")?.primary).toBe(true);
|
|
314
|
+
});
|
|
315
|
+
|
|
316
|
+
test("marks lint as primary", () => {
|
|
317
|
+
const pkg = { scripts: { lint: "eslint ." } };
|
|
318
|
+
const cmds = parsePackageJsonScripts(pkg);
|
|
319
|
+
expect(cmds.find((c) => c.command === "npm run lint")?.primary).toBe(true);
|
|
320
|
+
});
|
|
321
|
+
|
|
322
|
+
test("marks non-standard scripts as non-primary", () => {
|
|
323
|
+
const pkg = { scripts: { myscript: "echo hello" } };
|
|
324
|
+
const cmds = parsePackageJsonScripts(pkg);
|
|
325
|
+
expect(cmds.find((c) => c.command === "npm run myscript")?.primary).toBe(
|
|
326
|
+
false,
|
|
327
|
+
);
|
|
328
|
+
});
|
|
329
|
+
|
|
330
|
+
test("handles empty scripts object", () => {
|
|
331
|
+
const pkg = { scripts: {} };
|
|
332
|
+
expect(parsePackageJsonScripts(pkg)).toEqual([]);
|
|
333
|
+
});
|
|
334
|
+
|
|
335
|
+
test("handles undefined scripts", () => {
|
|
336
|
+
const pkg = {};
|
|
337
|
+
expect(parsePackageJsonScripts(pkg)).toEqual([]);
|
|
338
|
+
});
|
|
339
|
+
|
|
340
|
+
test("source is always package.json", () => {
|
|
341
|
+
const pkg = { scripts: { test: "jest" } };
|
|
342
|
+
const cmds = parsePackageJsonScripts(pkg);
|
|
343
|
+
expect(cmds.every((c) => c.source === "package.json")).toBe(true);
|
|
344
|
+
});
|
|
345
|
+
|
|
346
|
+
test("command format is npm run <name>", () => {
|
|
347
|
+
const pkg = { scripts: { foo: "bar" } };
|
|
348
|
+
const cmds = parsePackageJsonScripts(pkg);
|
|
349
|
+
expect(cmds[0].command).toBe("npm run foo");
|
|
350
|
+
});
|
|
351
|
+
});
|
|
352
|
+
|
|
353
|
+
// ─── categorizeCommands Tests ─────────────────────────────────────────
|
|
354
|
+
|
|
355
|
+
describe("categorizeCommands", () => {
|
|
356
|
+
test("categorizes jest test commands", () => {
|
|
357
|
+
const cmds = [
|
|
358
|
+
{ command: "npm run test", source: "package.json", primary: true },
|
|
359
|
+
];
|
|
360
|
+
const categorized = categorizeCommands(cmds);
|
|
361
|
+
expect(categorized.unitTest).toContain("npm run test");
|
|
362
|
+
});
|
|
363
|
+
|
|
364
|
+
test("categorizes vitest commands", () => {
|
|
365
|
+
const cmds = [
|
|
366
|
+
{ command: "vitest run", source: "package.json", primary: true },
|
|
367
|
+
];
|
|
368
|
+
const categorized = categorizeCommands(cmds);
|
|
369
|
+
expect(categorized.unitTest.some((c) => c.includes("vitest"))).toBe(true);
|
|
370
|
+
});
|
|
371
|
+
|
|
372
|
+
test("categorizes pytest commands", () => {
|
|
373
|
+
const cmds = [{ command: "pytest", source: "package.json", primary: true }];
|
|
374
|
+
const categorized = categorizeCommands(cmds);
|
|
375
|
+
expect(categorized.unitTest).toContain("pytest");
|
|
376
|
+
});
|
|
377
|
+
|
|
378
|
+
test("categorizes playwright e2e commands", () => {
|
|
379
|
+
const cmds = [
|
|
380
|
+
{ command: "playwright e2e", source: "package.json", primary: true },
|
|
381
|
+
];
|
|
382
|
+
const categorized = categorizeCommands(cmds);
|
|
383
|
+
expect(categorized.e2eTest).toContain("playwright e2e");
|
|
384
|
+
});
|
|
385
|
+
|
|
386
|
+
test("categorizes cypress e2e commands", () => {
|
|
387
|
+
const cmds = [
|
|
388
|
+
{ command: "cypress run", source: "package.json", primary: true },
|
|
389
|
+
];
|
|
390
|
+
const categorized = categorizeCommands(cmds);
|
|
391
|
+
expect(categorized.e2eTest).toContain("cypress run");
|
|
392
|
+
});
|
|
393
|
+
|
|
394
|
+
test("categorizes eslint lint commands", () => {
|
|
395
|
+
const cmds = [
|
|
396
|
+
{ command: "eslint .", source: "package.json", primary: false },
|
|
397
|
+
];
|
|
398
|
+
const categorized = categorizeCommands(cmds);
|
|
399
|
+
expect(categorized.lint.some((c) => c.includes("eslint"))).toBe(true);
|
|
400
|
+
});
|
|
401
|
+
|
|
402
|
+
test("categorizes prettier lint commands", () => {
|
|
403
|
+
const cmds = [
|
|
404
|
+
{ command: "prettier --check .", source: "package.json", primary: false },
|
|
405
|
+
];
|
|
406
|
+
const categorized = categorizeCommands(cmds);
|
|
407
|
+
expect(categorized.lint.some((c) => c.includes("prettier"))).toBe(true);
|
|
408
|
+
});
|
|
409
|
+
|
|
410
|
+
test("categorizes build commands", () => {
|
|
411
|
+
const cmds = [
|
|
412
|
+
{ command: "npm run build", source: "package.json", primary: true },
|
|
413
|
+
];
|
|
414
|
+
const categorized = categorizeCommands(cmds);
|
|
415
|
+
expect(categorized.build).toContain("npm run build");
|
|
416
|
+
});
|
|
417
|
+
|
|
418
|
+
test("categorizes vite build commands", () => {
|
|
419
|
+
const cmds = [
|
|
420
|
+
{ command: "vite build", source: "package.json", primary: true },
|
|
421
|
+
];
|
|
422
|
+
const categorized = categorizeCommands(cmds);
|
|
423
|
+
expect(categorized.build.some((c) => c.includes("vite"))).toBe(true);
|
|
424
|
+
});
|
|
425
|
+
|
|
426
|
+
test("categorizes next build commands", () => {
|
|
427
|
+
const cmds = [
|
|
428
|
+
{ command: "next build", source: "package.json", primary: true },
|
|
429
|
+
];
|
|
430
|
+
const categorized = categorizeCommands(cmds);
|
|
431
|
+
expect(categorized.build.some((c) => c.includes("next"))).toBe(true);
|
|
432
|
+
});
|
|
433
|
+
|
|
434
|
+
test("categorizes migrate commands", () => {
|
|
435
|
+
const cmds = [
|
|
436
|
+
{ command: "npm run migrate", source: "package.json", primary: false },
|
|
437
|
+
];
|
|
438
|
+
const categorized = categorizeCommands(cmds);
|
|
439
|
+
expect(categorized.migrate).toContain("npm run migrate");
|
|
440
|
+
});
|
|
441
|
+
|
|
442
|
+
test("categorizes bench migrate commands", () => {
|
|
443
|
+
const cmds = [
|
|
444
|
+
{ command: "bench migrate", source: "package.json", primary: false },
|
|
445
|
+
];
|
|
446
|
+
const categorized = categorizeCommands(cmds);
|
|
447
|
+
expect(categorized.migrate.some((c) => c.includes("bench"))).toBe(true);
|
|
448
|
+
});
|
|
449
|
+
|
|
450
|
+
test("avoids duplicate categorization", () => {
|
|
451
|
+
const cmds = [
|
|
452
|
+
{ command: "npm run test", source: "package.json", primary: true },
|
|
453
|
+
{ command: "npm run test", source: "package.json", primary: true },
|
|
454
|
+
];
|
|
455
|
+
const categorized = categorizeCommands(cmds);
|
|
456
|
+
expect(
|
|
457
|
+
categorized.unitTest.filter((c) => c === "npm run test").length,
|
|
458
|
+
).toBe(1);
|
|
459
|
+
});
|
|
460
|
+
|
|
461
|
+
test("handles empty command list", () => {
|
|
462
|
+
const categorized = categorizeCommands([]);
|
|
463
|
+
expect(categorized.unitTest).toEqual([]);
|
|
464
|
+
expect(categorized.build).toEqual([]);
|
|
465
|
+
});
|
|
466
|
+
|
|
467
|
+
test("categorizes integration test commands", () => {
|
|
468
|
+
const cmds = [
|
|
469
|
+
{
|
|
470
|
+
command: "npm run integration-tests",
|
|
471
|
+
source: "package.json",
|
|
472
|
+
primary: false,
|
|
473
|
+
},
|
|
474
|
+
];
|
|
475
|
+
const categorized = categorizeCommands(cmds);
|
|
476
|
+
expect(categorized.integrationTest).toContain("npm run integration-tests");
|
|
477
|
+
});
|
|
478
|
+
|
|
479
|
+
test("categorizes typecheck commands", () => {
|
|
480
|
+
const cmds = [
|
|
481
|
+
{ command: "tsc --noEmit", source: "package.json", primary: false },
|
|
482
|
+
];
|
|
483
|
+
const categorized = categorizeCommands(cmds);
|
|
484
|
+
expect(categorized.typecheck.some((c) => c.includes("tsc"))).toBe(true);
|
|
485
|
+
});
|
|
486
|
+
});
|
|
487
|
+
|
|
488
|
+
// ─── parsePythonCommands Tests ────────────────────────────────────────
|
|
489
|
+
|
|
490
|
+
describe("parsePythonCommands", () => {
|
|
491
|
+
test("detects pytest from pyproject.toml", () => {
|
|
492
|
+
const content = '[tool.pytest]\ntestpaths = ["tests"]';
|
|
493
|
+
const cmds = parsePythonCommands(content);
|
|
494
|
+
expect(cmds.find((c) => c.command === "pytest")).toBeDefined();
|
|
495
|
+
});
|
|
496
|
+
|
|
497
|
+
test("detects pytest from [pytest] section", () => {
|
|
498
|
+
const cmds = parsePythonCommands("[pytest]\ntestpaths = tests");
|
|
499
|
+
expect(cmds.find((c) => c.command === "pytest")).toBeDefined();
|
|
500
|
+
});
|
|
501
|
+
|
|
502
|
+
test("detects coverage commands", () => {
|
|
503
|
+
const cmds = parsePythonCommands("coverage = run: pytest");
|
|
504
|
+
expect(cmds.some((c) => c.command.includes("coverage run"))).toBe(true);
|
|
505
|
+
});
|
|
506
|
+
|
|
507
|
+
test("handles empty content", () => {
|
|
508
|
+
const cmds = parsePythonCommands("");
|
|
509
|
+
expect(cmds).toEqual([]);
|
|
510
|
+
});
|
|
511
|
+
});
|
|
512
|
+
|
|
513
|
+
// ─── parseComposerScripts Tests ───────────────────────────────────────
|
|
514
|
+
|
|
515
|
+
describe("parseComposerScripts", () => {
|
|
516
|
+
test("extracts composer scripts", () => {
|
|
517
|
+
const composer = { scripts: { test: "phpunit", lint: "phpcs" } };
|
|
518
|
+
const cmds = parseComposerScripts(composer);
|
|
519
|
+
expect(cmds.length).toBe(2);
|
|
520
|
+
});
|
|
521
|
+
|
|
522
|
+
test("command format is composer <name>", () => {
|
|
523
|
+
const composer = { scripts: { test: "phpunit" } };
|
|
524
|
+
const cmds = parseComposerScripts(composer);
|
|
525
|
+
expect(cmds[0].command).toBe("composer test");
|
|
526
|
+
});
|
|
527
|
+
|
|
528
|
+
test("marks test as primary", () => {
|
|
529
|
+
const composer = { scripts: { test: "phpunit" } };
|
|
530
|
+
const cmds = parseComposerScripts(composer);
|
|
531
|
+
expect(cmds.find((c) => c.command === "composer test")?.primary).toBe(true);
|
|
532
|
+
});
|
|
533
|
+
|
|
534
|
+
test("marks lint as primary", () => {
|
|
535
|
+
const composer = { scripts: { lint: "phpcs" } };
|
|
536
|
+
const cmds = parseComposerScripts(composer);
|
|
537
|
+
expect(cmds.find((c) => c.command === "composer lint")?.primary).toBe(true);
|
|
538
|
+
});
|
|
539
|
+
|
|
540
|
+
test("handles empty scripts", () => {
|
|
541
|
+
const composer = { scripts: {} };
|
|
542
|
+
expect(parseComposerScripts(composer)).toEqual([]);
|
|
543
|
+
});
|
|
544
|
+
|
|
545
|
+
test("handles undefined scripts", () => {
|
|
546
|
+
const composer = {};
|
|
547
|
+
expect(parseComposerScripts(composer)).toEqual([]);
|
|
548
|
+
});
|
|
549
|
+
});
|
|
550
|
+
|
|
551
|
+
// ─── AnalysisCache Tests ──────────────────────────────────────────────
|
|
552
|
+
|
|
553
|
+
describe("AnalysisCache", () => {
|
|
554
|
+
test("generates consistent cache keys", () => {
|
|
555
|
+
const cache = new AnalysisCache({ enabled: false });
|
|
556
|
+
const key1 = cache.generateKey("/repo", "abc123", "def456");
|
|
557
|
+
const key2 = cache.generateKey("/repo", "abc123", "def456");
|
|
558
|
+
expect(key1.repositoryRoot).toBe(key2.repositoryRoot);
|
|
559
|
+
expect(key1.revision).toBe(key2.revision);
|
|
560
|
+
expect(key1.configHash).toBe(key2.configHash);
|
|
561
|
+
});
|
|
562
|
+
|
|
563
|
+
test("generates different keys for different roots", () => {
|
|
564
|
+
const cache = new AnalysisCache({ enabled: false });
|
|
565
|
+
const key1 = cache.generateKey("/repo1", "abc123", "def456");
|
|
566
|
+
const key2 = cache.generateKey("/repo2", "abc123", "def456");
|
|
567
|
+
expect(key1.repositoryRoot).not.toBe(key2.repositoryRoot);
|
|
568
|
+
});
|
|
569
|
+
|
|
570
|
+
test("generates different keys for different revisions", () => {
|
|
571
|
+
const cache = new AnalysisCache({ enabled: false });
|
|
572
|
+
const key1 = cache.generateKey("/repo", "abc123", "def456");
|
|
573
|
+
const key2 = cache.generateKey("/repo", "xyz789", "def456");
|
|
574
|
+
expect(key1.revision).not.toBe(key2.revision);
|
|
575
|
+
});
|
|
576
|
+
|
|
577
|
+
test("calculates hash consistently", () => {
|
|
578
|
+
const cache = new AnalysisCache({ enabled: false });
|
|
579
|
+
const h1 = cache.calculateHash("hello");
|
|
580
|
+
const h2 = cache.calculateHash("hello");
|
|
581
|
+
expect(h1).toBe(h2);
|
|
582
|
+
});
|
|
583
|
+
|
|
584
|
+
test("calculates different hashes for different content", () => {
|
|
585
|
+
const cache = new AnalysisCache({ enabled: false });
|
|
586
|
+
const h1 = cache.calculateHash("hello");
|
|
587
|
+
const h2 = cache.calculateHash("world");
|
|
588
|
+
expect(h1).not.toBe(h2);
|
|
589
|
+
});
|
|
590
|
+
|
|
591
|
+
test("calculates config hash", async () => {
|
|
592
|
+
const cache = new AnalysisCache({ enabled: false });
|
|
593
|
+
const hash = await cache.calculateConfigHash([
|
|
594
|
+
{ path: "a.json", content: '{"test":1}' },
|
|
595
|
+
]);
|
|
596
|
+
expect(typeof hash).toBe("string");
|
|
597
|
+
expect(hash.length).toBe(64); // sha256 hex
|
|
598
|
+
});
|
|
599
|
+
|
|
600
|
+
test("get returns null when disabled", async () => {
|
|
601
|
+
const cache = new AnalysisCache({ enabled: false });
|
|
602
|
+
const key = cache.generateKey("/repo", "abc", "def");
|
|
603
|
+
const result = await cache.get(key);
|
|
604
|
+
expect(result).toBeNull();
|
|
605
|
+
});
|
|
606
|
+
|
|
607
|
+
test("set does not throw when disabled", async () => {
|
|
608
|
+
const cache = new AnalysisCache({ enabled: false });
|
|
609
|
+
const key = cache.generateKey("/repo", "abc", "def");
|
|
610
|
+
await expect(
|
|
611
|
+
cache.set(
|
|
612
|
+
key,
|
|
613
|
+
{
|
|
614
|
+
repositoryRoot: "/repo",
|
|
615
|
+
repositoryName: "repo",
|
|
616
|
+
revision: "abc",
|
|
617
|
+
frameworks: [],
|
|
618
|
+
languages: [],
|
|
619
|
+
packageManagers: [],
|
|
620
|
+
applications: [],
|
|
621
|
+
commands: {
|
|
622
|
+
unitTest: [],
|
|
623
|
+
integrationTest: [],
|
|
624
|
+
e2eTest: [],
|
|
625
|
+
lint: [],
|
|
626
|
+
typecheck: [],
|
|
627
|
+
build: [],
|
|
628
|
+
migrate: [],
|
|
629
|
+
},
|
|
630
|
+
rules: [],
|
|
631
|
+
sensitivePaths: [],
|
|
632
|
+
generatedPaths: [],
|
|
633
|
+
testCapabilities: [],
|
|
634
|
+
confidence: 0,
|
|
635
|
+
warnings: [],
|
|
636
|
+
analyzedAt: new Date().toISOString(),
|
|
637
|
+
},
|
|
638
|
+
{ ruleHash: "r", manifestHash: "m", configHash: "c" },
|
|
639
|
+
),
|
|
640
|
+
).resolves.toBeUndefined();
|
|
641
|
+
});
|
|
642
|
+
|
|
643
|
+
test("clear does not throw when disabled", async () => {
|
|
644
|
+
const cache = new AnalysisCache({ enabled: false });
|
|
645
|
+
await expect(cache.clear()).resolves.toBeUndefined();
|
|
646
|
+
});
|
|
647
|
+
|
|
648
|
+
test("invalidate does not throw when disabled", async () => {
|
|
649
|
+
const cache = new AnalysisCache({ enabled: false });
|
|
650
|
+
await expect(cache.invalidate("/repo")).resolves.toBeUndefined();
|
|
651
|
+
});
|
|
652
|
+
|
|
653
|
+
test("getStats returns zeros when disabled", async () => {
|
|
654
|
+
const cache = new AnalysisCache({ enabled: false });
|
|
655
|
+
const stats = await cache.getStats();
|
|
656
|
+
expect(stats.entryCount).toBe(0);
|
|
657
|
+
expect(stats.totalSize).toBe(0);
|
|
658
|
+
});
|
|
659
|
+
});
|
|
660
|
+
|
|
661
|
+
// ─── hashRuleFiles Tests ──────────────────────────────────────────────
|
|
662
|
+
|
|
663
|
+
describe("hashRuleFiles", () => {
|
|
664
|
+
test("generates consistent hash for same files", async () => {
|
|
665
|
+
const files = [{ path: "AGENTS.md", content: "# Rules\n\nTest content" }];
|
|
666
|
+
const h1 = await hashRuleFiles(files);
|
|
667
|
+
const h2 = await hashRuleFiles(files);
|
|
668
|
+
expect(h1).toBe(h2);
|
|
669
|
+
});
|
|
670
|
+
|
|
671
|
+
test("different content produces different hash", async () => {
|
|
672
|
+
const h1 = await hashRuleFiles([{ path: "a.md", content: "v1" }]);
|
|
673
|
+
const h2 = await hashRuleFiles([{ path: "a.md", content: "v2" }]);
|
|
674
|
+
expect(h1).not.toBe(h2);
|
|
675
|
+
});
|
|
676
|
+
|
|
677
|
+
test("different paths produce different hash", async () => {
|
|
678
|
+
const h1 = await hashRuleFiles([{ path: "a.md", content: "same" }]);
|
|
679
|
+
const h2 = await hashRuleFiles([{ path: "b.md", content: "same" }]);
|
|
680
|
+
expect(h1).not.toBe(h2);
|
|
681
|
+
});
|
|
682
|
+
|
|
683
|
+
test("empty list produces valid hash", async () => {
|
|
684
|
+
const hash = await hashRuleFiles([]);
|
|
685
|
+
expect(typeof hash).toBe("string");
|
|
686
|
+
expect(hash.length).toBe(64);
|
|
687
|
+
});
|
|
688
|
+
});
|
|
689
|
+
|
|
690
|
+
// ─── hashManifestFiles Tests ───────────────────────────────────────────
|
|
691
|
+
|
|
692
|
+
describe("hashManifestFiles", () => {
|
|
693
|
+
test("generates consistent hash", async () => {
|
|
694
|
+
const files = [
|
|
695
|
+
{ path: "package.json", content: '{"scripts":{"test":"jest"}}' },
|
|
696
|
+
];
|
|
697
|
+
const h1 = await hashManifestFiles(files);
|
|
698
|
+
const h2 = await hashManifestFiles(files);
|
|
699
|
+
expect(h1).toBe(h2);
|
|
700
|
+
});
|
|
701
|
+
|
|
702
|
+
test("only scripts and deps are hashed", async () => {
|
|
703
|
+
const files = [
|
|
704
|
+
{
|
|
705
|
+
path: "package.json",
|
|
706
|
+
content: '{"scripts":{"test":"jest"},"extra":"ignored"}',
|
|
707
|
+
},
|
|
708
|
+
];
|
|
709
|
+
const hash = await hashManifestFiles(files);
|
|
710
|
+
expect(typeof hash).toBe("string");
|
|
711
|
+
expect(hash.length).toBe(64);
|
|
712
|
+
});
|
|
713
|
+
});
|
|
714
|
+
|
|
715
|
+
// ─── FileSystemWalker Tests ────────────────────────────────────────────
|
|
716
|
+
|
|
717
|
+
describe("FileSystemWalker", () => {
|
|
718
|
+
test("rejects non-absolute root path", () => {
|
|
719
|
+
expect(() => new FileSystemWalker("relative/path")).toThrow();
|
|
720
|
+
});
|
|
721
|
+
|
|
722
|
+
test("scans empty directory", async () => {
|
|
723
|
+
const dir = await tmpDir();
|
|
724
|
+
const walker = new FileSystemWalker(dir);
|
|
725
|
+
const result = await walker.scan();
|
|
726
|
+
expect(result.files).toEqual([]);
|
|
727
|
+
expect(result.truncated).toBe(false);
|
|
728
|
+
expect(result.errors).toEqual([]);
|
|
729
|
+
});
|
|
730
|
+
|
|
731
|
+
test("scans files in directory", async () => {
|
|
732
|
+
const dir = await tmpDir();
|
|
733
|
+
await writeFile(join(dir, "index.ts"), "const x = 1;", "utf-8");
|
|
734
|
+
await writeFile(join(dir, "main.py"), "print('hello')", "utf-8");
|
|
735
|
+
|
|
736
|
+
const walker = new FileSystemWalker(dir);
|
|
737
|
+
const result = await walker.scan();
|
|
738
|
+
|
|
739
|
+
expect(result.files.length).toBeGreaterThanOrEqual(2);
|
|
740
|
+
const paths = result.files.map((f) => f.relativePath);
|
|
741
|
+
expect(paths).toContain("index.ts");
|
|
742
|
+
expect(paths).toContain("main.py");
|
|
743
|
+
});
|
|
744
|
+
|
|
745
|
+
test("detects sensitive files by pattern", async () => {
|
|
746
|
+
const dir = await tmpDir();
|
|
747
|
+
await writeFile(join(dir, ".env"), "SECRET=value", "utf-8");
|
|
748
|
+
await writeFile(join(dir, ".env.local"), "SECRET=local", "utf-8");
|
|
749
|
+
|
|
750
|
+
const walker = new FileSystemWalker(dir);
|
|
751
|
+
const result = await walker.scan();
|
|
752
|
+
|
|
753
|
+
const envFiles = result.files.filter((f) => f.sensitive);
|
|
754
|
+
expect(envFiles.length).toBeGreaterThan(0);
|
|
755
|
+
});
|
|
756
|
+
|
|
757
|
+
test("detects generated files by pattern", async () => {
|
|
758
|
+
const dir = await tmpDir();
|
|
759
|
+
await mkdir(join(dir, "dist"), { recursive: true });
|
|
760
|
+
await writeFile(join(dir, "dist/bundle.js"), "module.exports={};", "utf-8");
|
|
761
|
+
|
|
762
|
+
const walker = new FileSystemWalker(dir);
|
|
763
|
+
const result = await walker.scan();
|
|
764
|
+
|
|
765
|
+
const generatedFiles = result.files.filter((f) => f.generated);
|
|
766
|
+
expect(generatedFiles.length).toBeGreaterThan(0);
|
|
767
|
+
});
|
|
768
|
+
|
|
769
|
+
test("respects maxScanFiles limit", async () => {
|
|
770
|
+
const dir = await tmpDir();
|
|
771
|
+
// Create many files
|
|
772
|
+
for (let i = 0; i < 50; i++) {
|
|
773
|
+
await writeFile(join(dir, `file${i}.txt`), `content ${i}`, "utf-8");
|
|
56
774
|
}
|
|
775
|
+
|
|
776
|
+
const walker = new FileSystemWalker(dir, { maxScanFiles: 10 });
|
|
777
|
+
const result = await walker.scan();
|
|
778
|
+
|
|
779
|
+
expect(result.files.length).toBeLessThanOrEqual(10);
|
|
780
|
+
expect(result.truncated).toBe(true);
|
|
781
|
+
});
|
|
782
|
+
|
|
783
|
+
test("skips hidden directories except .git", async () => {
|
|
784
|
+
const dir = await tmpDir();
|
|
785
|
+
await mkdir(join(dir, ".hidden"), { recursive: true });
|
|
786
|
+
await writeFile(join(dir, ".hidden/file.txt"), "secret", "utf-8");
|
|
787
|
+
await mkdir(join(dir, ".git"), { recursive: true });
|
|
788
|
+
await writeFile(join(dir, ".git/config"), "[core]", "utf-8");
|
|
789
|
+
|
|
790
|
+
const walker = new FileSystemWalker(dir);
|
|
791
|
+
const result = await walker.scan();
|
|
792
|
+
|
|
793
|
+
const hiddenFiles = result.files.filter((f) =>
|
|
794
|
+
f.relativePath.includes(".hidden"),
|
|
795
|
+
);
|
|
796
|
+
expect(hiddenFiles).toEqual([]);
|
|
797
|
+
// .git should be included (not skipped)
|
|
798
|
+
});
|
|
799
|
+
|
|
800
|
+
test("resolves relative path correctly", async () => {
|
|
801
|
+
const dir = await tmpDir();
|
|
802
|
+
await mkdir(join(dir, "src"), { recursive: true });
|
|
803
|
+
await writeFile(join(dir, "src/index.ts"), "", "utf-8");
|
|
804
|
+
|
|
805
|
+
const walker = new FileSystemWalker(dir);
|
|
806
|
+
const result = await walker.scan();
|
|
807
|
+
|
|
808
|
+
const tsFile = result.files.find((f) => f.relativePath.endsWith(".ts"));
|
|
809
|
+
expect(tsFile?.relativePath).toBe("src/index.ts");
|
|
810
|
+
});
|
|
811
|
+
|
|
812
|
+
test("getStats returns scan statistics", async () => {
|
|
813
|
+
const dir = await tmpDir();
|
|
814
|
+
await writeFile(join(dir, "a.txt"), "a", "utf-8");
|
|
815
|
+
await writeFile(join(dir, "b.txt"), "b", "utf-8");
|
|
816
|
+
|
|
817
|
+
const walker = new FileSystemWalker(dir);
|
|
818
|
+
await walker.scan();
|
|
819
|
+
const stats = walker.getStats();
|
|
820
|
+
|
|
821
|
+
expect(stats.filesScanned).toBeGreaterThanOrEqual(2);
|
|
822
|
+
expect(stats.directoriesScanned).toBeGreaterThanOrEqual(1);
|
|
823
|
+
});
|
|
824
|
+
|
|
825
|
+
test("readFileSafe returns null for oversized files", async () => {
|
|
826
|
+
const dir = await tmpDir();
|
|
827
|
+
await writeFile(join(dir, "big.txt"), "x".repeat(1000), "utf-8");
|
|
828
|
+
|
|
829
|
+
const walker = new FileSystemWalker(dir, { maxFileSize: 100 });
|
|
830
|
+
const content = await walker.readFileSafe(join(dir, "big.txt"));
|
|
831
|
+
expect(content).toBeNull();
|
|
832
|
+
});
|
|
833
|
+
|
|
834
|
+
test("readFileSafe returns content for small files", async () => {
|
|
835
|
+
const dir = await tmpDir();
|
|
836
|
+
const content = "hello world";
|
|
837
|
+
await writeFile(join(dir, "small.txt"), content, "utf-8");
|
|
838
|
+
|
|
839
|
+
const walker = new FileSystemWalker(dir);
|
|
840
|
+
const result = await walker.readFileSafe(join(dir, "small.txt"));
|
|
841
|
+
expect(result).toBe(content);
|
|
842
|
+
});
|
|
843
|
+
|
|
844
|
+
test("exists returns true for existing path", async () => {
|
|
845
|
+
const dir = await tmpDir();
|
|
846
|
+
await writeFile(join(dir, "exists.txt"), "x", "utf-8");
|
|
847
|
+
|
|
848
|
+
const walker = new FileSystemWalker(dir);
|
|
849
|
+
expect(await walker.exists(join(dir, "exists.txt"))).toBe(true);
|
|
850
|
+
});
|
|
851
|
+
|
|
852
|
+
test("exists returns false for non-existent path", async () => {
|
|
853
|
+
const dir = await tmpDir();
|
|
854
|
+
const walker = new FileSystemWalker(dir);
|
|
855
|
+
expect(await walker.exists(join(dir, "nonexistent.txt"))).toBe(false);
|
|
856
|
+
});
|
|
857
|
+
|
|
858
|
+
test("findFiles matches regex patterns", async () => {
|
|
859
|
+
const dir = await tmpDir();
|
|
860
|
+
await writeFile(join(dir, "test.spec.ts"), "", "utf-8");
|
|
861
|
+
await writeFile(join(dir, "test.test.ts"), "", "utf-8");
|
|
862
|
+
await writeFile(join(dir, "app.ts"), "", "utf-8");
|
|
863
|
+
|
|
864
|
+
const walker = new FileSystemWalker(dir);
|
|
865
|
+
const results = await walker.findFiles(/\.test\.ts$/);
|
|
866
|
+
expect(results.length).toBe(1);
|
|
57
867
|
});
|
|
58
868
|
});
|
|
59
869
|
|
|
60
|
-
// ───
|
|
870
|
+
// ─── Rule Discovery Tests ─────────────────────────────────────────────
|
|
871
|
+
|
|
872
|
+
describe("rule-discovery", () => {
|
|
873
|
+
test("parseRuleFile extracts sections from markdown", async () => {
|
|
874
|
+
const ruleFile = {
|
|
875
|
+
path: "/repo/AGENTS.md",
|
|
876
|
+
name: "AGENTS.md",
|
|
877
|
+
content: "# Section 1\n\nContent here.\n\n## Section 2\n\nMore content.",
|
|
878
|
+
userDefined: true,
|
|
879
|
+
};
|
|
880
|
+
const rule = await parseRuleFile(ruleFile);
|
|
881
|
+
expect(rule.sections.length).toBeGreaterThan(0);
|
|
882
|
+
expect(rule.priority).toBe("mandatory");
|
|
883
|
+
expect(rule.userDefined).toBe(true);
|
|
884
|
+
});
|
|
885
|
+
|
|
886
|
+
test("AGENTS.md has mandatory priority", async () => {
|
|
887
|
+
const rule = await parseRuleFile({
|
|
888
|
+
path: "/repo/AGENTS.md",
|
|
889
|
+
name: "AGENTS.md",
|
|
890
|
+
content: "# Rules",
|
|
891
|
+
userDefined: true,
|
|
892
|
+
});
|
|
893
|
+
expect(rule.priority).toBe("mandatory");
|
|
894
|
+
});
|
|
895
|
+
|
|
896
|
+
test("CONTRIBUTING.md has advisory priority", async () => {
|
|
897
|
+
const rule = await parseRuleFile({
|
|
898
|
+
path: "/repo/CONTRIBUTING.md",
|
|
899
|
+
name: "CONTRIBUTING.md",
|
|
900
|
+
content: "# Contributing",
|
|
901
|
+
userDefined: false,
|
|
902
|
+
});
|
|
903
|
+
expect(rule.priority).toBe("advisory");
|
|
904
|
+
});
|
|
905
|
+
|
|
906
|
+
test("discoverRuleFiles finds files in temp repo", async () => {
|
|
907
|
+
const dir = await tmpDir();
|
|
908
|
+
await writeFile(
|
|
909
|
+
join(dir, "AGENTS.md"),
|
|
910
|
+
"# Agent Rules\n\nUse TypeScript.",
|
|
911
|
+
"utf-8",
|
|
912
|
+
);
|
|
913
|
+
|
|
914
|
+
const fs = {
|
|
915
|
+
exists: async (p: string) => {
|
|
916
|
+
try {
|
|
917
|
+
const { access } = await import("node:fs/promises");
|
|
918
|
+
await access(p);
|
|
919
|
+
return true;
|
|
920
|
+
} catch {
|
|
921
|
+
return false;
|
|
922
|
+
}
|
|
923
|
+
},
|
|
924
|
+
readFile: async (p: string) => {
|
|
925
|
+
const { readFile } = await import("node:fs/promises");
|
|
926
|
+
return readFile(p, "utf-8");
|
|
927
|
+
},
|
|
928
|
+
readDir: async (p: string) => {
|
|
929
|
+
const { readdir } = await import("node:fs/promises");
|
|
930
|
+
return readdir(p);
|
|
931
|
+
},
|
|
932
|
+
isDirectory: async (p: string) => {
|
|
933
|
+
const { stat } = await import("node:fs/promises");
|
|
934
|
+
const s = await stat(p);
|
|
935
|
+
return s.isDirectory();
|
|
936
|
+
},
|
|
937
|
+
};
|
|
938
|
+
|
|
939
|
+
const rules = await discoverRuleFiles(dir, fs);
|
|
940
|
+
expect(rules.length).toBeGreaterThan(0);
|
|
941
|
+
expect(rules.find((r) => r.name === "AGENTS.md")).toBeDefined();
|
|
942
|
+
});
|
|
943
|
+
|
|
944
|
+
test("mergeRules sorts by priority", async () => {
|
|
945
|
+
const files = [
|
|
946
|
+
{
|
|
947
|
+
path: "/repo/CONTRIBUTING.md",
|
|
948
|
+
name: "CONTRIBUTING.md",
|
|
949
|
+
content: "# Contributing",
|
|
950
|
+
userDefined: false,
|
|
951
|
+
},
|
|
952
|
+
{
|
|
953
|
+
path: "/repo/AGENTS.md",
|
|
954
|
+
name: "AGENTS.md",
|
|
955
|
+
content: "# Agents",
|
|
956
|
+
userDefined: true,
|
|
957
|
+
},
|
|
958
|
+
];
|
|
959
|
+
const merged = mergeRules(files);
|
|
960
|
+
expect(merged[0].id).toBe("rule-AGENTS");
|
|
961
|
+
});
|
|
962
|
+
});
|
|
963
|
+
|
|
964
|
+
// ─── Signal Detection Tests ───────────────────────────────────────────
|
|
965
|
+
|
|
966
|
+
describe("scanSignals", () => {
|
|
967
|
+
test("returns empty array when no signals match", async () => {
|
|
968
|
+
const fs = {
|
|
969
|
+
exists: async () => false,
|
|
970
|
+
glob: async () => [],
|
|
971
|
+
readFile: async () => "",
|
|
972
|
+
readDir: async () => [],
|
|
973
|
+
isDirectory: async () => false,
|
|
974
|
+
};
|
|
975
|
+
const signals = await scanSignals(fs);
|
|
976
|
+
expect(signals).toEqual([]);
|
|
977
|
+
});
|
|
978
|
+
|
|
979
|
+
test("detects file existence signals", async () => {
|
|
980
|
+
// Use a non-glob signal: frappe uses "apps.txt"
|
|
981
|
+
const fs = {
|
|
982
|
+
exists: async (path: string) => path === "apps.txt",
|
|
983
|
+
glob: async () => [],
|
|
984
|
+
readFile: async () => "",
|
|
985
|
+
readDir: async () => [],
|
|
986
|
+
isDirectory: async () => false,
|
|
987
|
+
};
|
|
988
|
+
const signals = await scanSignals(fs);
|
|
989
|
+
const frappeSignal = signals.find((s) => s.type === "frappe_hooks");
|
|
990
|
+
expect(frappeSignal).toBeDefined();
|
|
991
|
+
expect(frappeSignal?.path).toBe("apps.txt");
|
|
992
|
+
});
|
|
993
|
+
});
|
|
994
|
+
|
|
995
|
+
describe("GenericFrameworkDetector", () => {
|
|
996
|
+
test("detects Next.js from next.config.js", async () => {
|
|
997
|
+
const dir = await tmpDir();
|
|
998
|
+
await writeFile(
|
|
999
|
+
join(dir, "next.config.js"),
|
|
1000
|
+
"module.exports = {}",
|
|
1001
|
+
"utf-8",
|
|
1002
|
+
);
|
|
1003
|
+
await writeFile(
|
|
1004
|
+
join(dir, "package.json"),
|
|
1005
|
+
'{"dependencies":{"next":"14"}}',
|
|
1006
|
+
"utf-8",
|
|
1007
|
+
);
|
|
1008
|
+
|
|
1009
|
+
const walker = new FileSystemWalker(dir);
|
|
1010
|
+
const roFs = {
|
|
1011
|
+
exists: async (path: string) => walker.exists(path),
|
|
1012
|
+
readFile: async (path: string) => {
|
|
1013
|
+
const c = await walker.readFileSafe(path);
|
|
1014
|
+
if (c === null) throw new Error("not found");
|
|
1015
|
+
return c;
|
|
1016
|
+
},
|
|
1017
|
+
readDir: async (path: string) => {
|
|
1018
|
+
try {
|
|
1019
|
+
const { readdir } = await import("node:fs/promises");
|
|
1020
|
+
return readdir(walker.resolvePath(path));
|
|
1021
|
+
} catch {
|
|
1022
|
+
return [];
|
|
1023
|
+
}
|
|
1024
|
+
},
|
|
1025
|
+
isDirectory: async (path: string) => {
|
|
1026
|
+
try {
|
|
1027
|
+
const { stat } = await import("node:fs/promises");
|
|
1028
|
+
const s = await stat(walker.resolvePath(path));
|
|
1029
|
+
return s.isDirectory();
|
|
1030
|
+
} catch {
|
|
1031
|
+
return false;
|
|
1032
|
+
}
|
|
1033
|
+
},
|
|
1034
|
+
// glob is used for wildcard patterns like "next.config.*"
|
|
1035
|
+
glob: async (pattern: string) => {
|
|
1036
|
+
if (pattern === "next.config.*") {
|
|
1037
|
+
return ["next.config.js"];
|
|
1038
|
+
}
|
|
1039
|
+
return [];
|
|
1040
|
+
},
|
|
1041
|
+
};
|
|
1042
|
+
|
|
1043
|
+
const detector = new GenericFrameworkDetector();
|
|
1044
|
+
const results = await detector.detect(roFs);
|
|
1045
|
+
|
|
1046
|
+
expect(results.length).toBeGreaterThan(0);
|
|
1047
|
+
const nextjs = results.find((r) => r.category === "nextjs");
|
|
1048
|
+
expect(nextjs).toBeDefined();
|
|
1049
|
+
expect(nextjs!.confidence).toBeGreaterThan(0);
|
|
1050
|
+
});
|
|
1051
|
+
|
|
1052
|
+
test("detects Django from manage.py", async () => {
|
|
1053
|
+
const dir = await tmpDir();
|
|
1054
|
+
await writeFile(join(dir, "manage.py"), "#!/usr/bin/env python", "utf-8");
|
|
1055
|
+
await writeFile(join(dir, "settings.py"), "SECRET_KEY = 'x'", "utf-8");
|
|
1056
|
+
|
|
1057
|
+
const walker = new FileSystemWalker(dir);
|
|
1058
|
+
const roFs = {
|
|
1059
|
+
exists: async (path: string) => walker.exists(path),
|
|
1060
|
+
readFile: async () => "",
|
|
1061
|
+
readDir: async () => [],
|
|
1062
|
+
isDirectory: async () => false,
|
|
1063
|
+
glob: async () => [],
|
|
1064
|
+
};
|
|
1065
|
+
|
|
1066
|
+
const detector = new GenericFrameworkDetector();
|
|
1067
|
+
const results = await detector.detect(roFs);
|
|
1068
|
+
|
|
1069
|
+
const django = results.find((r) => r.category === "django");
|
|
1070
|
+
expect(django).toBeDefined();
|
|
1071
|
+
expect(django!.confidence).toBeGreaterThan(0);
|
|
1072
|
+
});
|
|
1073
|
+
|
|
1074
|
+
test("returns empty results for unknown directory", async () => {
|
|
1075
|
+
await tmpDir(); // Creates empty temp dir
|
|
1076
|
+
const roFs = {
|
|
1077
|
+
exists: async () => false,
|
|
1078
|
+
readFile: async () => {
|
|
1079
|
+
throw new Error("not found");
|
|
1080
|
+
},
|
|
1081
|
+
readDir: async () => [],
|
|
1082
|
+
isDirectory: async () => false,
|
|
1083
|
+
glob: async () => [],
|
|
1084
|
+
};
|
|
1085
|
+
|
|
1086
|
+
const detector = new GenericFrameworkDetector();
|
|
1087
|
+
const results = await detector.detect(roFs);
|
|
1088
|
+
// Unknown framework is possible if signal matching doesn't find anything
|
|
1089
|
+
expect(Array.isArray(results)).toBe(true);
|
|
1090
|
+
});
|
|
1091
|
+
});
|
|
1092
|
+
|
|
1093
|
+
// ─── ProjectAnalyzer Integration Tests ────────────────────────────────
|
|
61
1094
|
|
|
62
1095
|
describe("ProjectAnalyzer", () => {
|
|
63
1096
|
let analyzer: ProjectAnalyzer;
|
|
64
1097
|
|
|
65
1098
|
beforeEach(() => {
|
|
66
|
-
analyzer = createProjectAnalyzer(
|
|
1099
|
+
analyzer = createProjectAnalyzer({
|
|
1100
|
+
cache: new AnalysisCache({ enabled: false }),
|
|
1101
|
+
});
|
|
67
1102
|
});
|
|
68
1103
|
|
|
69
|
-
test("
|
|
70
|
-
expect(analyzer).toBeDefined();
|
|
1104
|
+
test("analyzer is instance of ProjectAnalyzer", () => {
|
|
71
1105
|
expect(analyzer).toBeInstanceOf(ProjectAnalyzer);
|
|
72
1106
|
});
|
|
73
1107
|
|
|
74
|
-
test("analyzes
|
|
75
|
-
const
|
|
76
|
-
|
|
77
|
-
|
|
1108
|
+
test("analyzes Next.js workspace", async () => {
|
|
1109
|
+
const dir = await tmpDir();
|
|
1110
|
+
await writeFile(
|
|
1111
|
+
join(dir, "package.json"),
|
|
1112
|
+
JSON.stringify({ dependencies: { next: "14.0.0" } }),
|
|
1113
|
+
"utf-8",
|
|
1114
|
+
);
|
|
1115
|
+
await writeFile(
|
|
1116
|
+
join(dir, "next.config.js"),
|
|
1117
|
+
"module.exports = {}",
|
|
1118
|
+
"utf-8",
|
|
1119
|
+
);
|
|
1120
|
+
await mkdir(join(dir, "app"), { recursive: true });
|
|
1121
|
+
await writeFile(
|
|
1122
|
+
join(dir, "app/page.tsx"),
|
|
1123
|
+
"export default function(){}",
|
|
1124
|
+
"utf-8",
|
|
1125
|
+
);
|
|
1126
|
+
|
|
1127
|
+
const result = await analyzer.analyze({ repositoryRoot: dir });
|
|
78
1128
|
|
|
79
1129
|
expect(result.success).toBe(true);
|
|
80
1130
|
expect(result.profile).toBeDefined();
|
|
1131
|
+
expect(result.profile!.repositoryRoot).toBe(dir);
|
|
1132
|
+
expect(result.profile!.repositoryName).toBeDefined();
|
|
1133
|
+
expect(result.profile!.analyzedAt).toBeDefined();
|
|
1134
|
+
});
|
|
81
1135
|
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
1136
|
+
test("analyzes React/Vite workspace", async () => {
|
|
1137
|
+
const dir = await tmpDir();
|
|
1138
|
+
await writeFile(
|
|
1139
|
+
join(dir, "package.json"),
|
|
1140
|
+
JSON.stringify({
|
|
1141
|
+
dependencies: { react: "^18" },
|
|
1142
|
+
devDependencies: { vite: "^5" },
|
|
1143
|
+
}),
|
|
1144
|
+
"utf-8",
|
|
1145
|
+
);
|
|
1146
|
+
await writeFile(
|
|
1147
|
+
join(dir, "vite.config.ts"),
|
|
1148
|
+
"import { defineConfig } from 'vite'",
|
|
1149
|
+
"utf-8",
|
|
1150
|
+
);
|
|
1151
|
+
await mkdir(join(dir, "src"), { recursive: true });
|
|
1152
|
+
await writeFile(
|
|
1153
|
+
join(dir, "src/main.tsx"),
|
|
1154
|
+
"import React from 'react'",
|
|
1155
|
+
"utf-8",
|
|
1156
|
+
);
|
|
1157
|
+
|
|
1158
|
+
const result = await analyzer.analyze({ repositoryRoot: dir });
|
|
1159
|
+
|
|
1160
|
+
expect(result.success).toBe(true);
|
|
1161
|
+
expect(result.profile).toBeDefined();
|
|
87
1162
|
});
|
|
88
1163
|
|
|
89
|
-
test("
|
|
90
|
-
const
|
|
91
|
-
|
|
92
|
-
|
|
1164
|
+
test("analyzes Django workspace", async () => {
|
|
1165
|
+
const dir = await tmpDir();
|
|
1166
|
+
await writeFile(join(dir, "manage.py"), "#!/usr/bin/env python", "utf-8");
|
|
1167
|
+
await writeFile(join(dir, "settings.py"), "SECRET_KEY = 'dev'", "utf-8");
|
|
1168
|
+
await writeFile(join(dir, "requirements.txt"), "django==4.0", "utf-8");
|
|
1169
|
+
|
|
1170
|
+
const result = await analyzer.analyze({ repositoryRoot: dir });
|
|
93
1171
|
|
|
94
1172
|
expect(result.success).toBe(true);
|
|
1173
|
+
expect(result.profile).toBeDefined();
|
|
1174
|
+
});
|
|
95
1175
|
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
1176
|
+
test("analyzes Laravel workspace", async () => {
|
|
1177
|
+
const dir = await tmpDir();
|
|
1178
|
+
await writeFile(join(dir, "artisan"), "#!/usr/bin/env php", "utf-8");
|
|
1179
|
+
await writeFile(
|
|
1180
|
+
join(dir, "composer.json"),
|
|
1181
|
+
JSON.stringify({ require: { laravel: "^10" } }),
|
|
1182
|
+
"utf-8",
|
|
1183
|
+
);
|
|
1184
|
+
await mkdir(join(dir, "app", "Http", "Controllers"), { recursive: true });
|
|
1185
|
+
|
|
1186
|
+
const result = await analyzer.analyze({ repositoryRoot: dir });
|
|
1187
|
+
|
|
1188
|
+
expect(result.success).toBe(true);
|
|
1189
|
+
expect(result.profile).toBeDefined();
|
|
100
1190
|
});
|
|
101
1191
|
|
|
102
|
-
test("detects
|
|
103
|
-
const
|
|
104
|
-
|
|
105
|
-
|
|
1192
|
+
test("detects language from scanned files", async () => {
|
|
1193
|
+
const dir = await tmpDir();
|
|
1194
|
+
await writeFile(join(dir, "package.json"), "{}", "utf-8");
|
|
1195
|
+
await writeFile(join(dir, "main.ts"), "const x: number = 1;", "utf-8");
|
|
1196
|
+
await writeFile(join(dir, "utils.py"), "def foo(): pass", "utf-8");
|
|
1197
|
+
|
|
1198
|
+
const result = await analyzer.analyze({ repositoryRoot: dir });
|
|
106
1199
|
|
|
107
1200
|
expect(result.success).toBe(true);
|
|
1201
|
+
expect(result.profile!.languages.length).toBeGreaterThan(0);
|
|
1202
|
+
});
|
|
108
1203
|
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
1204
|
+
test("detects package manager from lock files", async () => {
|
|
1205
|
+
const dir = await tmpDir();
|
|
1206
|
+
await writeFile(join(dir, "package.json"), "{}", "utf-8");
|
|
1207
|
+
await writeFile(join(dir, "bun.lockb"), "", "utf-8");
|
|
1208
|
+
|
|
1209
|
+
const result = await analyzer.analyze({ repositoryRoot: dir });
|
|
1210
|
+
|
|
1211
|
+
expect(result.success).toBe(true);
|
|
1212
|
+
expect(result.profile!.packageManagers.length).toBeGreaterThan(0);
|
|
113
1213
|
});
|
|
114
1214
|
|
|
115
|
-
test("discovers
|
|
1215
|
+
test("discovers commands from package.json", async () => {
|
|
1216
|
+
const dir = await tmpDir();
|
|
1217
|
+
await writeFile(
|
|
1218
|
+
join(dir, "package.json"),
|
|
1219
|
+
JSON.stringify({
|
|
1220
|
+
scripts: {
|
|
1221
|
+
test: "vitest",
|
|
1222
|
+
build: "tsc",
|
|
1223
|
+
lint: "eslint .",
|
|
1224
|
+
},
|
|
1225
|
+
}),
|
|
1226
|
+
"utf-8",
|
|
1227
|
+
);
|
|
1228
|
+
|
|
1229
|
+
const result = await analyzer.analyze({ repositoryRoot: dir });
|
|
1230
|
+
|
|
1231
|
+
expect(result.success).toBe(true);
|
|
1232
|
+
expect(result.profile!.commands.unitTest.length).toBeGreaterThan(0);
|
|
1233
|
+
});
|
|
1234
|
+
|
|
1235
|
+
test("discovers AGENTS.md rules", async () => {
|
|
1236
|
+
const dir = await tmpDir();
|
|
1237
|
+
await writeFile(join(dir, "package.json"), "{}", "utf-8");
|
|
1238
|
+
await writeFile(
|
|
1239
|
+
join(dir, "AGENTS.md"),
|
|
1240
|
+
"# Agent Rules\n\n## Code Style\n\nUse TypeScript.",
|
|
1241
|
+
"utf-8",
|
|
1242
|
+
);
|
|
1243
|
+
|
|
1244
|
+
const result = await analyzer.analyze({ repositoryRoot: dir });
|
|
1245
|
+
|
|
1246
|
+
expect(result.success).toBe(true);
|
|
1247
|
+
expect(result.profile!.rules.length).toBeGreaterThan(0);
|
|
1248
|
+
});
|
|
1249
|
+
|
|
1250
|
+
test("detects test capabilities", async () => {
|
|
1251
|
+
const dir = await tmpDir();
|
|
1252
|
+
await writeFile(join(dir, "package.json"), "{}", "utf-8");
|
|
1253
|
+
await writeFile(
|
|
1254
|
+
join(dir, "vitest.config.ts"),
|
|
1255
|
+
"import { defineConfig } from 'vitest/config'",
|
|
1256
|
+
"utf-8",
|
|
1257
|
+
);
|
|
1258
|
+
|
|
1259
|
+
const result = await analyzer.analyze({ repositoryRoot: dir });
|
|
1260
|
+
|
|
1261
|
+
expect(result.success).toBe(true);
|
|
1262
|
+
expect(result.profile!.testCapabilities.length).toBeGreaterThan(0);
|
|
1263
|
+
const vitest = result.profile!.testCapabilities.find(
|
|
1264
|
+
(t) => t.runner === "vitest",
|
|
1265
|
+
);
|
|
1266
|
+
expect(vitest).toBeDefined();
|
|
1267
|
+
expect(vitest!.available).toBe(true);
|
|
1268
|
+
});
|
|
1269
|
+
|
|
1270
|
+
test("detects pytest from pyproject.toml", async () => {
|
|
1271
|
+
const dir = await tmpDir();
|
|
1272
|
+
await writeFile(
|
|
1273
|
+
join(dir, "pyproject.toml"),
|
|
1274
|
+
"[tool.pytest]\ntestpaths = ['tests']",
|
|
1275
|
+
"utf-8",
|
|
1276
|
+
);
|
|
1277
|
+
|
|
1278
|
+
const result = await analyzer.analyze({ repositoryRoot: dir });
|
|
1279
|
+
|
|
1280
|
+
expect(result.success).toBe(true);
|
|
1281
|
+
const pytest = result.profile!.testCapabilities.find(
|
|
1282
|
+
(t) => t.runner === "pytest",
|
|
1283
|
+
);
|
|
1284
|
+
expect(pytest).toBeDefined();
|
|
1285
|
+
});
|
|
1286
|
+
|
|
1287
|
+
test("returns error for non-existent directory", async () => {
|
|
116
1288
|
const result = await analyzer.analyze({
|
|
117
|
-
repositoryRoot:
|
|
1289
|
+
repositoryRoot: "/nonexistent/path/to/repo",
|
|
118
1290
|
});
|
|
1291
|
+
// The analyzer catches errors and returns success:false for non-existent paths
|
|
1292
|
+
if (!result.success) {
|
|
1293
|
+
expect(result.error).toBeDefined();
|
|
1294
|
+
expect(result.errorCode).toBeDefined();
|
|
1295
|
+
}
|
|
1296
|
+
});
|
|
1297
|
+
|
|
1298
|
+
test("reports duration", async () => {
|
|
1299
|
+
const dir = await tmpDir();
|
|
1300
|
+
await writeFile(join(dir, "package.json"), "{}", "utf-8");
|
|
1301
|
+
|
|
1302
|
+
const result = await analyzer.analyze({ repositoryRoot: dir });
|
|
1303
|
+
expect(result.durationMs).toBeGreaterThanOrEqual(0);
|
|
1304
|
+
});
|
|
119
1305
|
|
|
1306
|
+
test("analyzer with custom cache works", async () => {
|
|
1307
|
+
const cache = new AnalysisCache({ enabled: false });
|
|
1308
|
+
const customAnalyzer = createProjectAnalyzer({ cache });
|
|
1309
|
+
|
|
1310
|
+
const dir = await tmpDir();
|
|
1311
|
+
await writeFile(join(dir, "package.json"), "{}", "utf-8");
|
|
1312
|
+
|
|
1313
|
+
const result = await customAnalyzer.analyze({ repositoryRoot: dir });
|
|
120
1314
|
expect(result.success).toBe(true);
|
|
1315
|
+
});
|
|
1316
|
+
|
|
1317
|
+
test("analyzer config respects maxScanFiles", async () => {
|
|
1318
|
+
const dir = await tmpDir();
|
|
1319
|
+
await writeFile(join(dir, "package.json"), "{}", "utf-8");
|
|
121
1320
|
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
1321
|
+
// Create many files
|
|
1322
|
+
for (let i = 0; i < 30; i++) {
|
|
1323
|
+
await writeFile(join(dir, `file${i}.txt`), `content ${i}`, "utf-8");
|
|
125
1324
|
}
|
|
1325
|
+
|
|
1326
|
+
const limitedAnalyzer = createProjectAnalyzer({
|
|
1327
|
+
cache: new AnalysisCache({ enabled: false }),
|
|
1328
|
+
});
|
|
1329
|
+
|
|
1330
|
+
const result = await limitedAnalyzer.analyze({
|
|
1331
|
+
repositoryRoot: dir,
|
|
1332
|
+
config: { maxScanFiles: 10 },
|
|
1333
|
+
});
|
|
1334
|
+
|
|
1335
|
+
expect(result.success).toBe(true);
|
|
1336
|
+
expect(result.profile).toBeDefined();
|
|
126
1337
|
});
|
|
127
1338
|
|
|
128
|
-
test("
|
|
129
|
-
|
|
130
|
-
|
|
1339
|
+
test("analyzer with no monorepo detection", async () => {
|
|
1340
|
+
const dir = await tmpDir();
|
|
1341
|
+
await writeFile(
|
|
1342
|
+
join(dir, "package.json"),
|
|
1343
|
+
JSON.stringify({ name: "root" }),
|
|
1344
|
+
"utf-8",
|
|
1345
|
+
);
|
|
1346
|
+
await mkdir(join(dir, "packages", "app"), { recursive: true });
|
|
1347
|
+
await writeFile(
|
|
1348
|
+
join(dir, "packages", "app", "package.json"),
|
|
1349
|
+
JSON.stringify({ name: "app" }),
|
|
1350
|
+
"utf-8",
|
|
1351
|
+
);
|
|
131
1352
|
|
|
132
1353
|
const result = await analyzer.analyze({
|
|
133
|
-
repositoryRoot:
|
|
1354
|
+
repositoryRoot: dir,
|
|
1355
|
+
config: { detectMonorepo: false },
|
|
134
1356
|
});
|
|
135
1357
|
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
1358
|
+
expect(result.success).toBe(true);
|
|
1359
|
+
});
|
|
1360
|
+
|
|
1361
|
+
test("generates warnings for conflicting frameworks", async () => {
|
|
1362
|
+
const dir = await tmpDir();
|
|
1363
|
+
await writeFile(join(dir, "package.json"), "{}", "utf-8");
|
|
1364
|
+
await writeFile(
|
|
1365
|
+
join(dir, "next.config.js"),
|
|
1366
|
+
"module.exports = {}",
|
|
1367
|
+
"utf-8",
|
|
1368
|
+
);
|
|
1369
|
+
await writeFile(
|
|
1370
|
+
join(dir, "vite.config.ts"),
|
|
1371
|
+
"import { defineConfig } from 'vite'",
|
|
1372
|
+
"utf-8",
|
|
1373
|
+
);
|
|
1374
|
+
|
|
1375
|
+
const result = await analyzer.analyze({ repositoryRoot: dir });
|
|
1376
|
+
|
|
1377
|
+
expect(result.success).toBe(true);
|
|
1378
|
+
// Both Next.js and Vite should be detected, may produce framework warnings
|
|
1379
|
+
expect(result.profile).toBeDefined();
|
|
140
1380
|
});
|
|
141
1381
|
});
|
|
142
1382
|
|
|
143
|
-
// ───
|
|
1383
|
+
// ─── Complexity Estimation ────────────────────────────────────────────
|
|
144
1384
|
|
|
145
|
-
describe("
|
|
146
|
-
test("
|
|
147
|
-
const
|
|
1385
|
+
describe("complexity signals from FileSystemWalker", () => {
|
|
1386
|
+
test("file count reflects all scanned files", async () => {
|
|
1387
|
+
const dir = await tmpDir();
|
|
1388
|
+
await writeFile(join(dir, "package.json"), "{}", "utf-8");
|
|
1389
|
+
await writeFile(join(dir, "a.ts"), "", "utf-8");
|
|
1390
|
+
await writeFile(join(dir, "b.ts"), "", "utf-8");
|
|
1391
|
+
await writeFile(join(dir, "c.ts"), "", "utf-8");
|
|
148
1392
|
|
|
149
|
-
const
|
|
150
|
-
const
|
|
1393
|
+
const walker = new FileSystemWalker(dir);
|
|
1394
|
+
const result = await walker.scan();
|
|
151
1395
|
|
|
152
|
-
expect(
|
|
153
|
-
expect(key1.revision).toBe(key2.revision);
|
|
154
|
-
expect(key1.configHash).toBe(key2.configHash);
|
|
1396
|
+
expect(result.files.length).toBeGreaterThanOrEqual(4);
|
|
155
1397
|
});
|
|
156
1398
|
|
|
157
|
-
test("
|
|
158
|
-
const
|
|
1399
|
+
test("total size accumulates file sizes", async () => {
|
|
1400
|
+
const dir = await tmpDir();
|
|
1401
|
+
await writeFile(join(dir, "package.json"), '{"name":"test"}', "utf-8");
|
|
1402
|
+
await writeFile(join(dir, "main.ts"), "const x = 1;".repeat(100), "utf-8");
|
|
159
1403
|
|
|
160
|
-
const
|
|
161
|
-
const
|
|
1404
|
+
const walker = new FileSystemWalker(dir);
|
|
1405
|
+
const result = await walker.scan();
|
|
162
1406
|
|
|
163
|
-
|
|
1407
|
+
const tsFile = result.files.find((f) => f.relativePath === "main.ts");
|
|
1408
|
+
expect(tsFile!.size).toBeGreaterThan(500);
|
|
1409
|
+
});
|
|
1410
|
+
|
|
1411
|
+
test("scans nested directories", async () => {
|
|
1412
|
+
const dir = await tmpDir();
|
|
1413
|
+
await mkdir(join(dir, "src", "components", "ui"), { recursive: true });
|
|
1414
|
+
await writeFile(join(dir, "src/index.ts"), "", "utf-8");
|
|
1415
|
+
await writeFile(join(dir, "src/components/Button.tsx"), "", "utf-8");
|
|
1416
|
+
await writeFile(join(dir, "src/components/ui/Card.tsx"), "", "utf-8");
|
|
1417
|
+
|
|
1418
|
+
const walker = new FileSystemWalker(dir);
|
|
1419
|
+
const result = await walker.scan();
|
|
1420
|
+
|
|
1421
|
+
expect(result.files.length).toBeGreaterThanOrEqual(3);
|
|
1422
|
+
expect(result.directoriesScanned).toBeGreaterThan(3);
|
|
1423
|
+
});
|
|
1424
|
+
|
|
1425
|
+
test("node_modules files are marked as generated", async () => {
|
|
1426
|
+
const dir = await tmpDir();
|
|
1427
|
+
await mkdir(join(dir, "node_modules"), { recursive: true });
|
|
1428
|
+
await mkdir(join(dir, "node_modules/lodash"), { recursive: true });
|
|
1429
|
+
await writeFile(
|
|
1430
|
+
join(dir, "node_modules/lodash/index.js"),
|
|
1431
|
+
"module.exports={};",
|
|
1432
|
+
"utf-8",
|
|
1433
|
+
);
|
|
1434
|
+
await mkdir(join(dir, "src"), { recursive: true });
|
|
1435
|
+
await writeFile(join(dir, "src/main.ts"), "", "utf-8");
|
|
1436
|
+
|
|
1437
|
+
const walker = new FileSystemWalker(dir);
|
|
1438
|
+
const result = await walker.scan();
|
|
1439
|
+
|
|
1440
|
+
// node_modules files are scanned but marked as generated
|
|
1441
|
+
const generatedFiles = result.files.filter((f) => f.generated);
|
|
1442
|
+
expect(generatedFiles.length).toBeGreaterThan(0);
|
|
1443
|
+
});
|
|
1444
|
+
|
|
1445
|
+
test("depth limit prevents deep scanning", async () => {
|
|
1446
|
+
const dir = await tmpDir();
|
|
1447
|
+
// Create deeply nested structure
|
|
1448
|
+
let current = dir;
|
|
1449
|
+
for (let i = 0; i < 30; i++) {
|
|
1450
|
+
current = join(current, `level${i}`);
|
|
1451
|
+
}
|
|
1452
|
+
await mkdir(current, { recursive: true });
|
|
1453
|
+
await writeFile(join(current, "deep.ts"), "", "utf-8");
|
|
1454
|
+
|
|
1455
|
+
const walker = new FileSystemWalker(dir, { maxDepth: 5 });
|
|
1456
|
+
const result = await walker.scan();
|
|
1457
|
+
|
|
1458
|
+
const deepFile = result.files.find((f) =>
|
|
1459
|
+
f.relativePath.includes("deep.ts"),
|
|
1460
|
+
);
|
|
1461
|
+
expect(deepFile).toBeUndefined();
|
|
164
1462
|
});
|
|
165
1463
|
});
|
|
166
1464
|
|
|
167
|
-
// ───
|
|
1465
|
+
// ─── Error Cases ──────────────────────────────────────────────────────
|
|
168
1466
|
|
|
169
|
-
describe("
|
|
170
|
-
test("
|
|
171
|
-
const
|
|
1467
|
+
describe("error handling", () => {
|
|
1468
|
+
test("analyzer handles corrupted JSON gracefully", async () => {
|
|
1469
|
+
const dir = await tmpDir();
|
|
1470
|
+
await writeFile(join(dir, "package.json"), "{ invalid json }", "utf-8");
|
|
172
1471
|
|
|
173
|
-
const
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
dev: "vite",
|
|
178
|
-
lint: "eslint .",
|
|
179
|
-
},
|
|
180
|
-
};
|
|
1472
|
+
const analyzer = createProjectAnalyzer({
|
|
1473
|
+
cache: new AnalysisCache({ enabled: false }),
|
|
1474
|
+
});
|
|
1475
|
+
const result = await analyzer.analyze({ repositoryRoot: dir });
|
|
181
1476
|
|
|
182
|
-
|
|
1477
|
+
// Should still succeed with partial results
|
|
1478
|
+
expect(result.success).toBe(true);
|
|
1479
|
+
});
|
|
183
1480
|
|
|
184
|
-
|
|
185
|
-
|
|
1481
|
+
test("walker handles unreadable directories", async () => {
|
|
1482
|
+
const dir = await tmpDir();
|
|
1483
|
+
// The walker should not crash on edge cases
|
|
1484
|
+
const walker = new FileSystemWalker(dir);
|
|
1485
|
+
const result = await walker.scan();
|
|
1486
|
+
expect(result.errors).toEqual([]);
|
|
186
1487
|
});
|
|
187
1488
|
|
|
188
|
-
test("handles
|
|
189
|
-
const
|
|
1489
|
+
test("analyzer handles missing package.json scripts", async () => {
|
|
1490
|
+
const dir = await tmpDir();
|
|
1491
|
+
await writeFile(
|
|
1492
|
+
join(dir, "package.json"),
|
|
1493
|
+
JSON.stringify({ name: "no-scripts" }),
|
|
1494
|
+
"utf-8",
|
|
1495
|
+
);
|
|
190
1496
|
|
|
191
|
-
const
|
|
192
|
-
|
|
1497
|
+
const analyzer = createProjectAnalyzer({
|
|
1498
|
+
cache: new AnalysisCache({ enabled: false }),
|
|
1499
|
+
});
|
|
1500
|
+
const result = await analyzer.analyze({ repositoryRoot: dir });
|
|
193
1501
|
|
|
194
|
-
expect(
|
|
1502
|
+
expect(result.success).toBe(true);
|
|
1503
|
+
expect(result.profile!.commands).toBeDefined();
|
|
195
1504
|
});
|
|
1505
|
+
});
|
|
196
1506
|
|
|
197
|
-
|
|
198
|
-
const { parsePackageJsonScripts } = require("../src/command-discovery.js");
|
|
1507
|
+
// ─── Additional Cache TTL Tests ────────────────────────────────────────
|
|
199
1508
|
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
1509
|
+
describe("AnalysisCache TTL behavior", () => {
|
|
1510
|
+
test("cache returns null for expired entries", async () => {
|
|
1511
|
+
const tmp = await mkdtemp(join(tmpdir(), "cache-ttl-"));
|
|
1512
|
+
tempDirs.push(tmp);
|
|
1513
|
+
|
|
1514
|
+
const cache = new AnalysisCache({
|
|
1515
|
+
enabled: true,
|
|
1516
|
+
cacheDir: tmp,
|
|
1517
|
+
maxAgeMs: 1, // 1 millisecond TTL
|
|
1518
|
+
});
|
|
1519
|
+
|
|
1520
|
+
const key = cache.generateKey("/repo", "abc", "def");
|
|
1521
|
+
await cache.set(
|
|
1522
|
+
key,
|
|
1523
|
+
{
|
|
1524
|
+
repositoryRoot: "/repo",
|
|
1525
|
+
repositoryName: "repo",
|
|
1526
|
+
revision: "abc",
|
|
1527
|
+
frameworks: [],
|
|
1528
|
+
languages: [],
|
|
1529
|
+
packageManagers: [],
|
|
1530
|
+
applications: [],
|
|
1531
|
+
commands: {
|
|
1532
|
+
unitTest: [],
|
|
1533
|
+
integrationTest: [],
|
|
1534
|
+
e2eTest: [],
|
|
1535
|
+
lint: [],
|
|
1536
|
+
typecheck: [],
|
|
1537
|
+
build: [],
|
|
1538
|
+
migrate: [],
|
|
1539
|
+
},
|
|
1540
|
+
rules: [],
|
|
1541
|
+
sensitivePaths: [],
|
|
1542
|
+
generatedPaths: [],
|
|
1543
|
+
testCapabilities: [],
|
|
1544
|
+
confidence: 0,
|
|
1545
|
+
warnings: [],
|
|
1546
|
+
analyzedAt: new Date().toISOString(),
|
|
206
1547
|
},
|
|
1548
|
+
{ ruleHash: "r", manifestHash: "m", configHash: "c" },
|
|
1549
|
+
);
|
|
1550
|
+
|
|
1551
|
+
// Wait for entry to expire
|
|
1552
|
+
await new Promise((r) => setTimeout(r, 10));
|
|
1553
|
+
|
|
1554
|
+
const result = await cache.get(key);
|
|
1555
|
+
expect(result).toBeNull();
|
|
1556
|
+
|
|
1557
|
+
await rm(tmp, { recursive: true, force: true });
|
|
1558
|
+
tempDirs.pop();
|
|
1559
|
+
});
|
|
1560
|
+
|
|
1561
|
+
test("cache stores and retrieves profiles", async () => {
|
|
1562
|
+
const tmp = await mkdtemp(join(tmpdir(), "cache-store-"));
|
|
1563
|
+
tempDirs.push(tmp);
|
|
1564
|
+
|
|
1565
|
+
const cache = new AnalysisCache({
|
|
1566
|
+
enabled: true,
|
|
1567
|
+
cacheDir: tmp,
|
|
1568
|
+
maxAgeMs: 60000,
|
|
1569
|
+
});
|
|
1570
|
+
|
|
1571
|
+
const profile = {
|
|
1572
|
+
repositoryRoot: "/test-repo",
|
|
1573
|
+
repositoryName: "test-repo",
|
|
1574
|
+
revision: "abc123",
|
|
1575
|
+
frameworks: [
|
|
1576
|
+
{
|
|
1577
|
+
category: "react" as const,
|
|
1578
|
+
name: "React",
|
|
1579
|
+
confidence: 0.9,
|
|
1580
|
+
signals: [],
|
|
1581
|
+
primary: true,
|
|
1582
|
+
},
|
|
1583
|
+
],
|
|
1584
|
+
languages: [{ name: "TypeScript", coverage: 1.0 }],
|
|
1585
|
+
packageManagers: [
|
|
1586
|
+
{ type: "npm" as const, configPath: "package.json", primary: true },
|
|
1587
|
+
],
|
|
1588
|
+
applications: [],
|
|
1589
|
+
commands: {
|
|
1590
|
+
unitTest: ["npm run test"],
|
|
1591
|
+
integrationTest: [],
|
|
1592
|
+
e2eTest: [],
|
|
1593
|
+
lint: [],
|
|
1594
|
+
typecheck: [],
|
|
1595
|
+
build: [],
|
|
1596
|
+
migrate: [],
|
|
1597
|
+
},
|
|
1598
|
+
rules: [],
|
|
1599
|
+
sensitivePaths: [],
|
|
1600
|
+
generatedPaths: [],
|
|
1601
|
+
testCapabilities: [],
|
|
1602
|
+
confidence: 0.9,
|
|
1603
|
+
warnings: [],
|
|
1604
|
+
analyzedAt: new Date().toISOString(),
|
|
207
1605
|
};
|
|
208
1606
|
|
|
209
|
-
const
|
|
1607
|
+
const key = cache.generateKey("/test-repo", "abc123", "xyz");
|
|
1608
|
+
await cache.set(key, profile, {
|
|
1609
|
+
ruleHash: "r",
|
|
1610
|
+
manifestHash: "m",
|
|
1611
|
+
configHash: "xyz",
|
|
1612
|
+
});
|
|
210
1613
|
|
|
211
|
-
const
|
|
212
|
-
|
|
213
|
-
);
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
);
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
1614
|
+
const retrieved = await cache.get(key);
|
|
1615
|
+
expect(retrieved).not.toBeNull();
|
|
1616
|
+
expect(retrieved!.repositoryName).toBe("test-repo");
|
|
1617
|
+
expect(retrieved!.languages[0].name).toBe("TypeScript");
|
|
1618
|
+
|
|
1619
|
+
await rm(tmp, { recursive: true, force: true });
|
|
1620
|
+
tempDirs.pop();
|
|
1621
|
+
});
|
|
1622
|
+
|
|
1623
|
+
test("invalidate removes all entries for a repository", async () => {
|
|
1624
|
+
const tmp = await mkdtemp(join(tmpdir(), "cache-inval-"));
|
|
1625
|
+
tempDirs.push(tmp);
|
|
1626
|
+
|
|
1627
|
+
const cache = new AnalysisCache({
|
|
1628
|
+
enabled: true,
|
|
1629
|
+
cacheDir: tmp,
|
|
1630
|
+
});
|
|
1631
|
+
|
|
1632
|
+
const key1 = cache.generateKey("/repo", "v1", "h1");
|
|
1633
|
+
await cache.set(
|
|
1634
|
+
key1,
|
|
1635
|
+
{
|
|
1636
|
+
repositoryRoot: "/repo",
|
|
1637
|
+
repositoryName: "repo",
|
|
1638
|
+
revision: "v1",
|
|
1639
|
+
frameworks: [],
|
|
1640
|
+
languages: [],
|
|
1641
|
+
packageManagers: [],
|
|
1642
|
+
applications: [],
|
|
1643
|
+
commands: {
|
|
1644
|
+
unitTest: [],
|
|
1645
|
+
integrationTest: [],
|
|
1646
|
+
e2eTest: [],
|
|
1647
|
+
lint: [],
|
|
1648
|
+
typecheck: [],
|
|
1649
|
+
build: [],
|
|
1650
|
+
migrate: [],
|
|
1651
|
+
},
|
|
1652
|
+
rules: [],
|
|
1653
|
+
sensitivePaths: [],
|
|
1654
|
+
generatedPaths: [],
|
|
1655
|
+
testCapabilities: [],
|
|
1656
|
+
confidence: 0,
|
|
1657
|
+
warnings: [],
|
|
1658
|
+
analyzedAt: new Date().toISOString(),
|
|
1659
|
+
},
|
|
1660
|
+
{ ruleHash: "r", manifestHash: "m", configHash: "h1" },
|
|
222
1661
|
);
|
|
223
1662
|
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
expect(
|
|
1663
|
+
await cache.invalidate("/repo");
|
|
1664
|
+
|
|
1665
|
+
const stats = await cache.getStats();
|
|
1666
|
+
expect(stats.entryCount).toBe(0);
|
|
1667
|
+
|
|
1668
|
+
await rm(tmp, { recursive: true, force: true });
|
|
1669
|
+
tempDirs.pop();
|
|
1670
|
+
});
|
|
1671
|
+
|
|
1672
|
+
test("getStats counts entries correctly", async () => {
|
|
1673
|
+
const tmp = await mkdtemp(join(tmpdir(), "cache-stats-"));
|
|
1674
|
+
tempDirs.push(tmp);
|
|
1675
|
+
|
|
1676
|
+
const cache = new AnalysisCache({ enabled: true, cacheDir: tmp });
|
|
1677
|
+
|
|
1678
|
+
// Store two entries
|
|
1679
|
+
for (const rev of ["v1", "v2"]) {
|
|
1680
|
+
const key = cache.generateKey("/repo", rev, "h");
|
|
1681
|
+
await cache.set(
|
|
1682
|
+
key,
|
|
1683
|
+
{
|
|
1684
|
+
repositoryRoot: "/repo",
|
|
1685
|
+
repositoryName: "repo",
|
|
1686
|
+
revision: rev,
|
|
1687
|
+
frameworks: [],
|
|
1688
|
+
languages: [],
|
|
1689
|
+
packageManagers: [],
|
|
1690
|
+
applications: [],
|
|
1691
|
+
commands: {
|
|
1692
|
+
unitTest: [],
|
|
1693
|
+
integrationTest: [],
|
|
1694
|
+
e2eTest: [],
|
|
1695
|
+
lint: [],
|
|
1696
|
+
typecheck: [],
|
|
1697
|
+
build: [],
|
|
1698
|
+
migrate: [],
|
|
1699
|
+
},
|
|
1700
|
+
rules: [],
|
|
1701
|
+
sensitivePaths: [],
|
|
1702
|
+
generatedPaths: [],
|
|
1703
|
+
testCapabilities: [],
|
|
1704
|
+
confidence: 0,
|
|
1705
|
+
warnings: [],
|
|
1706
|
+
analyzedAt: new Date().toISOString(),
|
|
1707
|
+
},
|
|
1708
|
+
{ ruleHash: "r", manifestHash: "m", configHash: "h" },
|
|
1709
|
+
);
|
|
1710
|
+
}
|
|
1711
|
+
|
|
1712
|
+
const stats = await cache.getStats();
|
|
1713
|
+
expect(stats.entryCount).toBe(2);
|
|
1714
|
+
expect(stats.totalSize).toBeGreaterThan(0);
|
|
1715
|
+
|
|
1716
|
+
await rm(tmp, { recursive: true, force: true });
|
|
1717
|
+
tempDirs.pop();
|
|
228
1718
|
});
|
|
229
1719
|
});
|