prjct-cli 1.22.0 → 1.23.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +147 -0
- package/bin/prjct +30 -13
- package/dist/bin/prjct.mjs +917 -35845
- package/dist/bin/prjct.mjs.map +7 -0
- package/dist/cli/linear.mjs +16 -0
- package/dist/cli/linear.mjs.map +7 -0
- package/dist/templates.json +1 -0
- package/package.json +4 -5
- package/bin/prjct.ts +0 -342
- package/core/__tests__/agentic/analysis-injection.test.ts +0 -377
- package/core/__tests__/agentic/cache-eviction.test.ts +0 -294
- package/core/__tests__/agentic/command-context.test.ts +0 -281
- package/core/__tests__/agentic/command-executor.test.ts +0 -659
- package/core/__tests__/agentic/domain-classifier.test.ts +0 -330
- package/core/__tests__/agentic/injection-validator.test.ts +0 -255
- package/core/__tests__/agentic/memory-system.test.ts +0 -281
- package/core/__tests__/agentic/plan-mode.test.ts +0 -386
- package/core/__tests__/agentic/prompt-assembly.test.ts +0 -298
- package/core/__tests__/agentic/prompt-builder.test.ts +0 -243
- package/core/__tests__/agentic/response-validator.test.ts +0 -263
- package/core/__tests__/agentic/semantic-matching.test.ts +0 -131
- package/core/__tests__/agentic/smart-context.test.ts +0 -372
- package/core/__tests__/agentic/tech-normalizer.test.ts +0 -136
- package/core/__tests__/agentic/token-budget.test.ts +0 -294
- package/core/__tests__/ai-tools/formatters.test.ts +0 -476
- package/core/__tests__/domain/bm25.test.ts +0 -225
- package/core/__tests__/domain/change-propagator.test.ts +0 -100
- package/core/__tests__/domain/fibonacci.test.ts +0 -113
- package/core/__tests__/domain/file-hasher.test.ts +0 -146
- package/core/__tests__/domain/file-ranker.test.ts +0 -169
- package/core/__tests__/domain/git-cochange.test.ts +0 -121
- package/core/__tests__/domain/import-graph.test.ts +0 -156
- package/core/__tests__/domain/velocity.test.ts +0 -623
- package/core/__tests__/infrastructure/performance-tracker.test.ts +0 -328
- package/core/__tests__/schemas/model.test.ts +0 -272
- package/core/__tests__/services/dependency-validator.test.ts +0 -175
- package/core/__tests__/services/hierarchical-agent-resolver.test.ts +0 -359
- package/core/__tests__/services/nested-context-resolver.test.ts +0 -443
- package/core/__tests__/services/project-index.test.ts +0 -355
- package/core/__tests__/services/staleness-checker.test.ts +0 -204
- package/core/__tests__/storage/analysis-storage.test.ts +0 -641
- package/core/__tests__/storage/archive-storage.test.ts +0 -455
- package/core/__tests__/storage/safe-reader.test.ts +0 -262
- package/core/__tests__/storage/sqlite-migration.test.ts +0 -1016
- package/core/__tests__/storage/state-storage-feedback.test.ts +0 -463
- package/core/__tests__/storage/state-storage-history.test.ts +0 -469
- package/core/__tests__/storage/storage-manager.test.ts +0 -383
- package/core/__tests__/storage/subtask-handoff.test.ts +0 -237
- package/core/__tests__/types/fs.test.ts +0 -125
- package/core/__tests__/utils/date-helper.test.ts +0 -449
- package/core/__tests__/utils/output.test.ts +0 -278
- package/core/__tests__/utils/preserve-sections.test.ts +0 -216
- package/core/__tests__/utils/project-commands.test.ts +0 -71
- package/core/__tests__/utils/retry.test.ts +0 -381
- package/core/__tests__/workflow/state-machine.test.ts +0 -216
- package/core/agentic/agent-router.ts +0 -150
- package/core/agentic/anti-hallucination.ts +0 -141
- package/core/agentic/chain-of-thought.ts +0 -234
- package/core/agentic/command-classifier.ts +0 -141
- package/core/agentic/command-context.ts +0 -168
- package/core/agentic/command-executor.ts +0 -471
- package/core/agentic/context-builder.ts +0 -285
- package/core/agentic/domain-classifier.ts +0 -525
- package/core/agentic/environment-block.ts +0 -102
- package/core/agentic/ground-truth.ts +0 -706
- package/core/agentic/index.ts +0 -193
- package/core/agentic/injection-validator.ts +0 -208
- package/core/agentic/loop-detector.ts +0 -451
- package/core/agentic/memory-system.ts +0 -1547
- package/core/agentic/orchestrator-executor.ts +0 -579
- package/core/agentic/plan-mode.ts +0 -525
- package/core/agentic/prompt-builder.ts +0 -1069
- package/core/agentic/response-validator.ts +0 -98
- package/core/agentic/services.ts +0 -167
- package/core/agentic/skill-loader.ts +0 -106
- package/core/agentic/smart-context.ts +0 -393
- package/core/agentic/tech-normalizer.ts +0 -167
- package/core/agentic/template-executor.ts +0 -272
- package/core/agentic/template-loader.ts +0 -109
- package/core/agentic/token-budget.ts +0 -226
- package/core/agentic/tool-registry.ts +0 -146
- package/core/agents/index.ts +0 -28
- package/core/agents/performance.ts +0 -429
- package/core/ai-tools/formatters.ts +0 -341
- package/core/ai-tools/generator.ts +0 -144
- package/core/ai-tools/index.ts +0 -15
- package/core/ai-tools/registry.ts +0 -201
- package/core/bus/bus.ts +0 -314
- package/core/bus/index.ts +0 -8
- package/core/cli/linear.ts +0 -500
- package/core/cli/lint-meta-commentary.ts +0 -177
- package/core/cli/start.ts +0 -386
- package/core/commands/analysis.ts +0 -1274
- package/core/commands/analytics.ts +0 -342
- package/core/commands/base.ts +0 -118
- package/core/commands/cleanup.ts +0 -157
- package/core/commands/command-data.ts +0 -463
- package/core/commands/commands.ts +0 -306
- package/core/commands/context.ts +0 -238
- package/core/commands/design.ts +0 -77
- package/core/commands/index.ts +0 -19
- package/core/commands/maintenance.ts +0 -77
- package/core/commands/performance.ts +0 -114
- package/core/commands/planning.ts +0 -662
- package/core/commands/register.ts +0 -127
- package/core/commands/registry.ts +0 -444
- package/core/commands/setup.ts +0 -280
- package/core/commands/shipping.ts +0 -267
- package/core/commands/snapshots.ts +0 -297
- package/core/commands/uninstall.ts +0 -542
- package/core/commands/velocity.ts +0 -149
- package/core/commands/workflow.ts +0 -505
- package/core/config/command-context.config.json +0 -66
- package/core/constants/index.ts +0 -379
- package/core/context/generator.ts +0 -368
- package/core/context-tools/files-tool.ts +0 -577
- package/core/context-tools/imports-tool.ts +0 -400
- package/core/context-tools/index.ts +0 -434
- package/core/context-tools/recent-tool.ts +0 -301
- package/core/context-tools/signatures-tool.ts +0 -495
- package/core/context-tools/summary-tool.ts +0 -301
- package/core/context-tools/token-counter.ts +0 -273
- package/core/context-tools/types.ts +0 -253
- package/core/domain/agent-generator.ts +0 -186
- package/core/domain/agent-loader.ts +0 -419
- package/core/domain/analyzer.ts +0 -387
- package/core/domain/architecture-generator.ts +0 -108
- package/core/domain/bm25.ts +0 -525
- package/core/domain/change-propagator.ts +0 -162
- package/core/domain/context-estimator.ts +0 -175
- package/core/domain/fibonacci.ts +0 -128
- package/core/domain/file-hasher.ts +0 -296
- package/core/domain/file-ranker.ts +0 -151
- package/core/domain/git-cochange.ts +0 -250
- package/core/domain/import-graph.ts +0 -315
- package/core/domain/snapshot-manager.ts +0 -415
- package/core/domain/task-stack.ts +0 -578
- package/core/domain/velocity.ts +0 -470
- package/core/errors.ts +0 -335
- package/core/events/events.ts +0 -85
- package/core/events/index.ts +0 -8
- package/core/index.ts +0 -481
- package/core/infrastructure/agent-detector.ts +0 -135
- package/core/infrastructure/ai-provider.ts +0 -578
- package/core/infrastructure/author-detector.ts +0 -133
- package/core/infrastructure/capability-installer.ts +0 -76
- package/core/infrastructure/claude-agent.ts +0 -297
- package/core/infrastructure/command-installer.ts +0 -752
- package/core/infrastructure/config-manager.ts +0 -364
- package/core/infrastructure/editors-config.ts +0 -172
- package/core/infrastructure/path-manager.ts +0 -571
- package/core/infrastructure/performance-tracker.ts +0 -326
- package/core/infrastructure/permission-manager.ts +0 -289
- package/core/infrastructure/setup.ts +0 -1061
- package/core/infrastructure/update-checker.ts +0 -246
- package/core/integrations/issue-tracker/enricher.ts +0 -271
- package/core/integrations/issue-tracker/index.ts +0 -8
- package/core/integrations/issue-tracker/manager.ts +0 -286
- package/core/integrations/issue-tracker/types.ts +0 -310
- package/core/integrations/jira/cache.ts +0 -57
- package/core/integrations/jira/client.ts +0 -688
- package/core/integrations/jira/index.ts +0 -23
- package/core/integrations/jira/service.ts +0 -244
- package/core/integrations/linear/cache.ts +0 -68
- package/core/integrations/linear/client.ts +0 -436
- package/core/integrations/linear/index.ts +0 -20
- package/core/integrations/linear/service.ts +0 -260
- package/core/integrations/linear/sync.ts +0 -314
- package/core/outcomes/analyzer.ts +0 -286
- package/core/outcomes/index.ts +0 -34
- package/core/outcomes/recorder.ts +0 -195
- package/core/plugin/builtin/webhook.ts +0 -148
- package/core/plugin/hooks.ts +0 -315
- package/core/plugin/index.ts +0 -50
- package/core/plugin/loader.ts +0 -354
- package/core/plugin/registry.ts +0 -326
- package/core/schemas/agents.ts +0 -27
- package/core/schemas/analysis.ts +0 -530
- package/core/schemas/classification.ts +0 -91
- package/core/schemas/command-context.ts +0 -29
- package/core/schemas/enriched-task.ts +0 -291
- package/core/schemas/ideas.ts +0 -114
- package/core/schemas/index.ts +0 -53
- package/core/schemas/issues.ts +0 -159
- package/core/schemas/llm-output.ts +0 -170
- package/core/schemas/metrics.ts +0 -143
- package/core/schemas/model.ts +0 -153
- package/core/schemas/outcomes.ts +0 -487
- package/core/schemas/performance.ts +0 -128
- package/core/schemas/permissions.ts +0 -180
- package/core/schemas/prd.ts +0 -450
- package/core/schemas/project.ts +0 -57
- package/core/schemas/roadmap.ts +0 -322
- package/core/schemas/schemas.ts +0 -38
- package/core/schemas/shipped.ts +0 -109
- package/core/schemas/state.ts +0 -284
- package/core/schemas/velocity.ts +0 -103
- package/core/server/index.ts +0 -21
- package/core/server/routes-extended.ts +0 -566
- package/core/server/routes.ts +0 -176
- package/core/server/server.ts +0 -149
- package/core/server/sse.ts +0 -192
- package/core/services/agent-generator.ts +0 -385
- package/core/services/agent-service.ts +0 -168
- package/core/services/breakdown-service.ts +0 -124
- package/core/services/context-generator.ts +0 -445
- package/core/services/context-selector.ts +0 -429
- package/core/services/dependency-validator.ts +0 -318
- package/core/services/diff-generator.ts +0 -313
- package/core/services/doctor-service.ts +0 -423
- package/core/services/file-categorizer.ts +0 -448
- package/core/services/file-scorer.ts +0 -270
- package/core/services/git-analyzer.ts +0 -293
- package/core/services/hierarchical-agent-resolver.ts +0 -236
- package/core/services/hooks-service.ts +0 -685
- package/core/services/index.ts +0 -46
- package/core/services/local-state-generator.ts +0 -158
- package/core/services/memory-service.ts +0 -181
- package/core/services/nested-context-resolver.ts +0 -842
- package/core/services/project-index.ts +0 -911
- package/core/services/project-service.ts +0 -155
- package/core/services/session-tracker.ts +0 -287
- package/core/services/skill-installer.ts +0 -447
- package/core/services/skill-lock.ts +0 -132
- package/core/services/skill-service.ts +0 -306
- package/core/services/stack-detector.ts +0 -229
- package/core/services/staleness-checker.ts +0 -327
- package/core/services/sync-service.ts +0 -1515
- package/core/services/sync-verifier.ts +0 -253
- package/core/services/watch-service.ts +0 -312
- package/core/session/compaction.ts +0 -248
- package/core/session/index.ts +0 -35
- package/core/session/log-migration.ts +0 -88
- package/core/session/metrics.ts +0 -323
- package/core/session/session-log-manager.ts +0 -307
- package/core/session/task-session-manager.ts +0 -404
- package/core/session/utils.ts +0 -51
- package/core/storage/analysis-storage.ts +0 -373
- package/core/storage/archive-storage.ts +0 -205
- package/core/storage/database.ts +0 -575
- package/core/storage/ideas-storage.ts +0 -298
- package/core/storage/index-storage.ts +0 -523
- package/core/storage/index.ts +0 -79
- package/core/storage/metrics-storage.ts +0 -321
- package/core/storage/migrate-json.ts +0 -720
- package/core/storage/queue-storage.ts +0 -336
- package/core/storage/safe-reader.ts +0 -105
- package/core/storage/shipped-storage.ts +0 -253
- package/core/storage/state-storage.ts +0 -1035
- package/core/storage/storage-manager.ts +0 -205
- package/core/storage/storage.ts +0 -177
- package/core/storage/velocity-storage.ts +0 -149
- package/core/sync/auth-config.ts +0 -138
- package/core/sync/index.ts +0 -31
- package/core/sync/oauth-handler.ts +0 -143
- package/core/sync/sync-client.ts +0 -251
- package/core/sync/sync-manager.ts +0 -327
- package/core/tsconfig.json +0 -22
- package/core/types/agentic.ts +0 -760
- package/core/types/agents.ts +0 -150
- package/core/types/bus.ts +0 -193
- package/core/types/citations.ts +0 -22
- package/core/types/commands.ts +0 -399
- package/core/types/config.ts +0 -92
- package/core/types/core.ts +0 -96
- package/core/types/diff.ts +0 -41
- package/core/types/domain.ts +0 -71
- package/core/types/errors.ts +0 -111
- package/core/types/events.ts +0 -42
- package/core/types/fs.ts +0 -72
- package/core/types/index.ts +0 -510
- package/core/types/infrastructure.ts +0 -210
- package/core/types/integrations.ts +0 -31
- package/core/types/jira.ts +0 -51
- package/core/types/logger.ts +0 -17
- package/core/types/memory.ts +0 -313
- package/core/types/outcomes.ts +0 -190
- package/core/types/output.ts +0 -47
- package/core/types/plugin.ts +0 -25
- package/core/types/project-sync.ts +0 -129
- package/core/types/provider.ts +0 -163
- package/core/types/server.ts +0 -71
- package/core/types/services.ts +0 -84
- package/core/types/session.ts +0 -135
- package/core/types/stack.ts +0 -19
- package/core/types/storage.ts +0 -318
- package/core/types/sync-verifier.ts +0 -33
- package/core/types/sync.ts +0 -121
- package/core/types/task.ts +0 -72
- package/core/types/template.ts +0 -24
- package/core/types/utils.ts +0 -92
- package/core/types/workflow.ts +0 -23
- package/core/utils/agent-stream.ts +0 -140
- package/core/utils/animations.ts +0 -251
- package/core/utils/branding.ts +0 -88
- package/core/utils/cache.ts +0 -187
- package/core/utils/citations.ts +0 -39
- package/core/utils/collection-filters.ts +0 -209
- package/core/utils/date-helper.ts +0 -176
- package/core/utils/error-messages.ts +0 -38
- package/core/utils/file-helper.ts +0 -277
- package/core/utils/fs-helpers.ts +0 -14
- package/core/utils/help.ts +0 -314
- package/core/utils/jsonl-helper.ts +0 -290
- package/core/utils/keychain.ts +0 -127
- package/core/utils/logger.ts +0 -77
- package/core/utils/markdown-builder.ts +0 -280
- package/core/utils/next-steps.ts +0 -95
- package/core/utils/output.ts +0 -403
- package/core/utils/preserve-sections.ts +0 -218
- package/core/utils/project-commands.ts +0 -126
- package/core/utils/project-credentials.ts +0 -143
- package/core/utils/provider-cache.ts +0 -49
- package/core/utils/retry.ts +0 -318
- package/core/utils/runtime.ts +0 -108
- package/core/utils/session-helper.ts +0 -278
- package/core/utils/subtask-table.ts +0 -227
- package/core/utils/version.ts +0 -128
- package/core/wizard/index.ts +0 -13
- package/core/wizard/onboarding.ts +0 -633
- package/core/workflow/index.ts +0 -7
- package/core/workflow/state-machine.ts +0 -198
- package/core/workflow/workflow-preferences.ts +0 -294
- package/dist/core/infrastructure/command-installer.js +0 -1141
- package/dist/core/infrastructure/editors-config.js +0 -177
- package/dist/core/infrastructure/setup.js +0 -2244
- package/dist/core/utils/version.js +0 -141
- package/templates/agentic/agent-routing.md +0 -45
- package/templates/agentic/agents/uxui.md +0 -63
- package/templates/agentic/checklist-routing.md +0 -98
- package/templates/agentic/orchestrator.md +0 -68
- package/templates/agentic/task-fragmentation.md +0 -89
- package/templates/agents/AGENTS.md +0 -68
- package/templates/analysis/analyze.md +0 -84
- package/templates/analysis/patterns.md +0 -60
- package/templates/antigravity/SKILL.md +0 -39
- package/templates/architect/discovery.md +0 -67
- package/templates/architect/phases.md +0 -59
- package/templates/checklists/architecture.md +0 -28
- package/templates/checklists/code-quality.md +0 -28
- package/templates/checklists/data.md +0 -33
- package/templates/checklists/documentation.md +0 -33
- package/templates/checklists/infrastructure.md +0 -33
- package/templates/checklists/performance.md +0 -33
- package/templates/checklists/security.md +0 -33
- package/templates/checklists/testing.md +0 -33
- package/templates/checklists/ux-ui.md +0 -37
- package/templates/commands/analyze.md +0 -56
- package/templates/commands/auth.md +0 -234
- package/templates/commands/bug.md +0 -163
- package/templates/commands/cleanup.md +0 -19
- package/templates/commands/dash.md +0 -99
- package/templates/commands/design.md +0 -15
- package/templates/commands/done.md +0 -291
- package/templates/commands/enrich.md +0 -174
- package/templates/commands/git.md +0 -295
- package/templates/commands/history.md +0 -389
- package/templates/commands/idea.md +0 -88
- package/templates/commands/impact.md +0 -864
- package/templates/commands/init.md +0 -54
- package/templates/commands/jira.md +0 -278
- package/templates/commands/linear.md +0 -288
- package/templates/commands/merge.md +0 -206
- package/templates/commands/next.md +0 -80
- package/templates/commands/p.md +0 -67
- package/templates/commands/p.toml +0 -37
- package/templates/commands/pause.md +0 -136
- package/templates/commands/plan.md +0 -696
- package/templates/commands/prd.md +0 -356
- package/templates/commands/resume.md +0 -171
- package/templates/commands/review.md +0 -276
- package/templates/commands/serve.md +0 -118
- package/templates/commands/setup.md +0 -91
- package/templates/commands/ship.md +0 -475
- package/templates/commands/skill.md +0 -259
- package/templates/commands/spec.md +0 -218
- package/templates/commands/status.md +0 -207
- package/templates/commands/sync.md +0 -104
- package/templates/commands/task.md +0 -312
- package/templates/commands/test.md +0 -93
- package/templates/commands/update.md +0 -63
- package/templates/commands/verify.md +0 -204
- package/templates/commands/workflow.md +0 -150
- package/templates/config/skill-mappings.json +0 -82
- package/templates/context/dashboard.md +0 -256
- package/templates/context/roadmap.md +0 -221
- package/templates/cursor/commands/bug.md +0 -8
- package/templates/cursor/commands/done.md +0 -4
- package/templates/cursor/commands/pause.md +0 -6
- package/templates/cursor/commands/resume.md +0 -4
- package/templates/cursor/commands/ship.md +0 -8
- package/templates/cursor/commands/sync.md +0 -4
- package/templates/cursor/commands/task.md +0 -8
- package/templates/cursor/p.md +0 -29
- package/templates/cursor/router.mdc +0 -28
- package/templates/design/api.md +0 -95
- package/templates/design/architecture.md +0 -77
- package/templates/design/component.md +0 -89
- package/templates/design/database.md +0 -78
- package/templates/design/flow.md +0 -94
- package/templates/global/ANTIGRAVITY.md +0 -254
- package/templates/global/CLAUDE.md +0 -497
- package/templates/global/CURSOR.mdc +0 -266
- package/templates/global/GEMINI.md +0 -293
- package/templates/global/STORAGE-SPEC.md +0 -391
- package/templates/global/WINDSURF.md +0 -266
- package/templates/global/modules/CLAUDE-commands.md +0 -70
- package/templates/global/modules/CLAUDE-core.md +0 -105
- package/templates/global/modules/CLAUDE-git.md +0 -50
- package/templates/global/modules/CLAUDE-intelligence.md +0 -92
- package/templates/global/modules/CLAUDE-storage.md +0 -50
- package/templates/global/modules/module-config.json +0 -36
- package/templates/mcp-config.json +0 -19
- package/templates/permissions/default.jsonc +0 -60
- package/templates/permissions/permissive.jsonc +0 -49
- package/templates/permissions/strict.jsonc +0 -58
- package/templates/planning-methodology.md +0 -195
- package/templates/skills/code-review.md +0 -47
- package/templates/skills/debug.md +0 -61
- package/templates/skills/refactor.md +0 -47
- package/templates/subagents/agent-base.md +0 -20
- package/templates/subagents/domain/backend.md +0 -109
- package/templates/subagents/domain/database.md +0 -121
- package/templates/subagents/domain/devops.md +0 -152
- package/templates/subagents/domain/frontend.md +0 -103
- package/templates/subagents/domain/testing.md +0 -169
- package/templates/subagents/pm-expert.md +0 -366
- package/templates/subagents/workflow/chief-architect.md +0 -657
- package/templates/subagents/workflow/prjct-planner.md +0 -159
- package/templates/subagents/workflow/prjct-shipper.md +0 -188
- package/templates/subagents/workflow/prjct-workflow.md +0 -98
- package/templates/tools/bash.txt +0 -22
- package/templates/tools/edit.txt +0 -18
- package/templates/tools/glob.txt +0 -19
- package/templates/tools/grep.txt +0 -21
- package/templates/tools/read.txt +0 -14
- package/templates/tools/task.txt +0 -20
- package/templates/tools/webfetch.txt +0 -16
- package/templates/tools/websearch.txt +0 -18
- package/templates/tools/write.txt +0 -17
- package/templates/windsurf/router.md +0 -28
- package/templates/windsurf/workflows/bug.md +0 -8
- package/templates/windsurf/workflows/done.md +0 -4
- package/templates/windsurf/workflows/pause.md +0 -4
- package/templates/windsurf/workflows/resume.md +0 -4
- package/templates/windsurf/workflows/ship.md +0 -8
- package/templates/windsurf/workflows/sync.md +0 -4
- package/templates/windsurf/workflows/task.md +0 -8
|
@@ -1,301 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Summary Tool - Intelligent file summarization
|
|
3
|
-
*
|
|
4
|
-
* Combines:
|
|
5
|
-
* - Code signatures (public API)
|
|
6
|
-
* - JSDoc/docstring extraction
|
|
7
|
-
* - Key dependencies
|
|
8
|
-
*
|
|
9
|
-
* Achieves high compression by returning only public-facing elements.
|
|
10
|
-
*
|
|
11
|
-
* @module context-tools/summary-tool
|
|
12
|
-
* @version 1.0.0
|
|
13
|
-
*/
|
|
14
|
-
|
|
15
|
-
import fs from 'node:fs/promises'
|
|
16
|
-
import path from 'node:path'
|
|
17
|
-
import { isNotFoundError } from '../types/fs'
|
|
18
|
-
import { analyzeImports } from './imports-tool'
|
|
19
|
-
import { extractSignatures } from './signatures-tool'
|
|
20
|
-
import { measureCompression, noCompression } from './token-counter'
|
|
21
|
-
import type { PublicAPIEntry, SummaryToolOutput } from './types'
|
|
22
|
-
|
|
23
|
-
// =============================================================================
|
|
24
|
-
// Docstring Patterns
|
|
25
|
-
// =============================================================================
|
|
26
|
-
|
|
27
|
-
interface DocstringPattern {
|
|
28
|
-
start: RegExp
|
|
29
|
-
end: RegExp | null
|
|
30
|
-
singleLine?: boolean
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
/**
|
|
34
|
-
* Docstring patterns by language
|
|
35
|
-
*/
|
|
36
|
-
const DOCSTRING_PATTERNS: Record<string, DocstringPattern[]> = {
|
|
37
|
-
typescript: [
|
|
38
|
-
{ start: /\/\*\*/, end: /\*\// }, // JSDoc
|
|
39
|
-
{ start: /\/\/\//, end: null, singleLine: true }, // Triple-slash
|
|
40
|
-
],
|
|
41
|
-
javascript: [
|
|
42
|
-
{ start: /\/\*\*/, end: /\*\// }, // JSDoc
|
|
43
|
-
],
|
|
44
|
-
python: [
|
|
45
|
-
{ start: /"""/, end: /"""/ }, // Triple quotes
|
|
46
|
-
{ start: /'''/, end: /'''/ }, // Single quotes
|
|
47
|
-
],
|
|
48
|
-
go: [
|
|
49
|
-
{ start: /\/\//, end: null, singleLine: true }, // Line comment (Go uses these as docs)
|
|
50
|
-
],
|
|
51
|
-
rust: [
|
|
52
|
-
{ start: /\/\/\//, end: null, singleLine: true }, // Doc comment
|
|
53
|
-
{ start: /\/\/!/, end: null, singleLine: true }, // Inner doc comment
|
|
54
|
-
],
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
/**
|
|
58
|
-
* Extension to language mapping
|
|
59
|
-
*/
|
|
60
|
-
const EXT_TO_LANG: Record<string, string> = {
|
|
61
|
-
'.ts': 'typescript',
|
|
62
|
-
'.tsx': 'typescript',
|
|
63
|
-
'.js': 'javascript',
|
|
64
|
-
'.jsx': 'javascript',
|
|
65
|
-
'.mjs': 'javascript',
|
|
66
|
-
'.py': 'python',
|
|
67
|
-
'.go': 'go',
|
|
68
|
-
'.rs': 'rust',
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
// =============================================================================
|
|
72
|
-
// Main Functions
|
|
73
|
-
// =============================================================================
|
|
74
|
-
|
|
75
|
-
/**
|
|
76
|
-
* Generate an intelligent summary of a file
|
|
77
|
-
*
|
|
78
|
-
* @param filePath - Path to the file
|
|
79
|
-
* @param projectPath - Project root path
|
|
80
|
-
* @returns Summary with public API and metrics
|
|
81
|
-
*/
|
|
82
|
-
export async function summarizeFile(
|
|
83
|
-
filePath: string,
|
|
84
|
-
projectPath: string = process.cwd()
|
|
85
|
-
): Promise<SummaryToolOutput> {
|
|
86
|
-
const absolutePath = path.isAbsolute(filePath) ? filePath : path.join(projectPath, filePath)
|
|
87
|
-
|
|
88
|
-
// Read file content
|
|
89
|
-
let content: string
|
|
90
|
-
try {
|
|
91
|
-
content = await fs.readFile(absolutePath, 'utf-8')
|
|
92
|
-
} catch (error) {
|
|
93
|
-
if (isNotFoundError(error)) {
|
|
94
|
-
return {
|
|
95
|
-
file: filePath,
|
|
96
|
-
purpose: 'File not found',
|
|
97
|
-
publicAPI: [],
|
|
98
|
-
dependencies: [],
|
|
99
|
-
metrics: noCompression(''),
|
|
100
|
-
}
|
|
101
|
-
}
|
|
102
|
-
throw error
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
// Get language
|
|
106
|
-
const ext = path.extname(filePath).toLowerCase()
|
|
107
|
-
const language = EXT_TO_LANG[ext] || 'unknown'
|
|
108
|
-
|
|
109
|
-
// Extract signatures
|
|
110
|
-
const signaturesResult = await extractSignatures(filePath, projectPath)
|
|
111
|
-
|
|
112
|
-
// Extract imports for dependencies
|
|
113
|
-
const importsResult = await analyzeImports(filePath, projectPath)
|
|
114
|
-
|
|
115
|
-
// Extract file-level docstring (purpose)
|
|
116
|
-
const purpose = extractFilePurpose(content, language)
|
|
117
|
-
|
|
118
|
-
// Build public API from exported signatures
|
|
119
|
-
const publicAPI: PublicAPIEntry[] = signaturesResult.signatures
|
|
120
|
-
.filter((sig) => sig.exported)
|
|
121
|
-
.map((sig) => ({
|
|
122
|
-
name: sig.name,
|
|
123
|
-
type: sig.type,
|
|
124
|
-
signature: sig.signature,
|
|
125
|
-
description: sig.docstring ? extractDescriptionFromDocstring(sig.docstring) : undefined,
|
|
126
|
-
}))
|
|
127
|
-
|
|
128
|
-
// Get key dependencies (internal only, external are obvious from package.json)
|
|
129
|
-
const dependencies = importsResult.imports
|
|
130
|
-
.filter((imp) => !imp.isExternal && imp.resolved)
|
|
131
|
-
.map((imp) => imp.resolved!)
|
|
132
|
-
.slice(0, 10) // Limit to 10
|
|
133
|
-
|
|
134
|
-
// Build summary content for metrics
|
|
135
|
-
const summaryContent = buildSummaryText(purpose, publicAPI, dependencies)
|
|
136
|
-
|
|
137
|
-
return {
|
|
138
|
-
file: filePath,
|
|
139
|
-
purpose,
|
|
140
|
-
publicAPI,
|
|
141
|
-
dependencies,
|
|
142
|
-
metrics: measureCompression(content, summaryContent),
|
|
143
|
-
}
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
/**
|
|
147
|
-
* Summarize all files in a directory
|
|
148
|
-
*/
|
|
149
|
-
export async function summarizeDirectory(
|
|
150
|
-
dirPath: string,
|
|
151
|
-
projectPath: string = process.cwd(),
|
|
152
|
-
options: { recursive?: boolean } = {}
|
|
153
|
-
): Promise<SummaryToolOutput[]> {
|
|
154
|
-
const absolutePath = path.isAbsolute(dirPath) ? dirPath : path.join(projectPath, dirPath)
|
|
155
|
-
|
|
156
|
-
const results: SummaryToolOutput[] = []
|
|
157
|
-
|
|
158
|
-
async function processDir(dir: string): Promise<void> {
|
|
159
|
-
const entries = await fs.readdir(dir, { withFileTypes: true })
|
|
160
|
-
|
|
161
|
-
for (const entry of entries) {
|
|
162
|
-
const fullPath = path.join(dir, entry.name)
|
|
163
|
-
const relativePath = path.relative(projectPath, fullPath)
|
|
164
|
-
|
|
165
|
-
if (entry.isDirectory()) {
|
|
166
|
-
// Skip common ignore patterns
|
|
167
|
-
if (entry.name === 'node_modules' || entry.name === '.git' || entry.name.startsWith('.')) {
|
|
168
|
-
continue
|
|
169
|
-
}
|
|
170
|
-
if (options.recursive) {
|
|
171
|
-
await processDir(fullPath)
|
|
172
|
-
}
|
|
173
|
-
} else if (entry.isFile()) {
|
|
174
|
-
const ext = path.extname(entry.name).toLowerCase()
|
|
175
|
-
if (EXT_TO_LANG[ext]) {
|
|
176
|
-
const result = await summarizeFile(relativePath, projectPath)
|
|
177
|
-
results.push(result)
|
|
178
|
-
}
|
|
179
|
-
}
|
|
180
|
-
}
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
await processDir(absolutePath)
|
|
184
|
-
return results
|
|
185
|
-
}
|
|
186
|
-
|
|
187
|
-
// =============================================================================
|
|
188
|
-
// Helper Functions
|
|
189
|
-
// =============================================================================
|
|
190
|
-
|
|
191
|
-
/**
|
|
192
|
-
* Extract file-level purpose from first docstring
|
|
193
|
-
*/
|
|
194
|
-
function extractFilePurpose(content: string, language: string): string {
|
|
195
|
-
const patterns = DOCSTRING_PATTERNS[language] || []
|
|
196
|
-
const lines = content.split('\n')
|
|
197
|
-
|
|
198
|
-
// Look for a file-level docstring in first 30 lines
|
|
199
|
-
for (let i = 0; i < Math.min(30, lines.length); i++) {
|
|
200
|
-
const line = lines[i].trim()
|
|
201
|
-
|
|
202
|
-
for (const pattern of patterns) {
|
|
203
|
-
if (pattern.start.test(line)) {
|
|
204
|
-
if (pattern.singleLine) {
|
|
205
|
-
// Single-line comment - grab consecutive lines
|
|
206
|
-
const commentLines: string[] = []
|
|
207
|
-
let j = i
|
|
208
|
-
while (j < lines.length && pattern.start.test(lines[j].trim())) {
|
|
209
|
-
commentLines.push(lines[j].trim().replace(pattern.start, '').trim())
|
|
210
|
-
j++
|
|
211
|
-
}
|
|
212
|
-
if (commentLines.length > 0) {
|
|
213
|
-
return commentLines.slice(0, 3).join(' ').trim()
|
|
214
|
-
}
|
|
215
|
-
} else if (pattern.end) {
|
|
216
|
-
// Multi-line comment - extract until end
|
|
217
|
-
let comment = ''
|
|
218
|
-
let j = i
|
|
219
|
-
while (j < lines.length) {
|
|
220
|
-
comment += `${lines[j]}\n`
|
|
221
|
-
if (pattern.end.test(lines[j])) break
|
|
222
|
-
j++
|
|
223
|
-
}
|
|
224
|
-
// Extract first meaningful line
|
|
225
|
-
const meaningfulLines = comment
|
|
226
|
-
.replace(pattern.start, '')
|
|
227
|
-
.replace(pattern.end!, '')
|
|
228
|
-
.split('\n')
|
|
229
|
-
.map((l) => l.replace(/^\s*\*\s?/, '').trim())
|
|
230
|
-
.filter((l) => l.length > 0 && !l.startsWith('@'))
|
|
231
|
-
if (meaningfulLines.length > 0) {
|
|
232
|
-
return meaningfulLines.slice(0, 2).join(' ').trim()
|
|
233
|
-
}
|
|
234
|
-
}
|
|
235
|
-
}
|
|
236
|
-
}
|
|
237
|
-
|
|
238
|
-
// Stop if we hit code (not comments or empty lines)
|
|
239
|
-
if (
|
|
240
|
-
line.length > 0 &&
|
|
241
|
-
!line.startsWith('//') &&
|
|
242
|
-
!line.startsWith('#') &&
|
|
243
|
-
!line.startsWith('/*') &&
|
|
244
|
-
!line.startsWith('*') &&
|
|
245
|
-
!line.startsWith("'") &&
|
|
246
|
-
!line.startsWith('"')
|
|
247
|
-
) {
|
|
248
|
-
break
|
|
249
|
-
}
|
|
250
|
-
}
|
|
251
|
-
|
|
252
|
-
// Fallback: derive from filename
|
|
253
|
-
const fileName = content.split('\n')[0] || ''
|
|
254
|
-
return `Module: ${path.basename(fileName, path.extname(fileName))}`
|
|
255
|
-
}
|
|
256
|
-
|
|
257
|
-
/**
|
|
258
|
-
* Extract description from a docstring line
|
|
259
|
-
*/
|
|
260
|
-
function extractDescriptionFromDocstring(docstring: string): string {
|
|
261
|
-
// Remove comment markers and clean up
|
|
262
|
-
return docstring
|
|
263
|
-
.replace(/^\/\*\*\s*/, '')
|
|
264
|
-
.replace(/\*\/$/, '')
|
|
265
|
-
.replace(/^\/\/\/?\s*/, '')
|
|
266
|
-
.replace(/^#\s*/, '')
|
|
267
|
-
.replace(/^"""\s*/, '')
|
|
268
|
-
.replace(/"""\s*$/, '')
|
|
269
|
-
.trim()
|
|
270
|
-
.split('\n')[0] // First line only
|
|
271
|
-
.trim()
|
|
272
|
-
}
|
|
273
|
-
|
|
274
|
-
/**
|
|
275
|
-
* Build summary text for metrics calculation
|
|
276
|
-
*/
|
|
277
|
-
function buildSummaryText(
|
|
278
|
-
purpose: string,
|
|
279
|
-
publicAPI: PublicAPIEntry[],
|
|
280
|
-
dependencies: string[]
|
|
281
|
-
): string {
|
|
282
|
-
const parts: string[] = []
|
|
283
|
-
|
|
284
|
-
parts.push(`Purpose: ${purpose}`)
|
|
285
|
-
parts.push('')
|
|
286
|
-
|
|
287
|
-
if (publicAPI.length > 0) {
|
|
288
|
-
parts.push('Public API:')
|
|
289
|
-
for (const entry of publicAPI) {
|
|
290
|
-
const desc = entry.description ? ` - ${entry.description}` : ''
|
|
291
|
-
parts.push(` ${entry.type} ${entry.name}: ${entry.signature}${desc}`)
|
|
292
|
-
}
|
|
293
|
-
parts.push('')
|
|
294
|
-
}
|
|
295
|
-
|
|
296
|
-
if (dependencies.length > 0) {
|
|
297
|
-
parts.push(`Dependencies: ${dependencies.join(', ')}`)
|
|
298
|
-
}
|
|
299
|
-
|
|
300
|
-
return parts.join('\n')
|
|
301
|
-
}
|
|
@@ -1,273 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Token Counter - REAL token measurement for context tools
|
|
3
|
-
*
|
|
4
|
-
* Provides accurate token estimation for measuring compression rates.
|
|
5
|
-
* Uses industry-standard approximation: ~4 characters per token.
|
|
6
|
-
*
|
|
7
|
-
* This is critical for the Value Dashboard to show REAL savings,
|
|
8
|
-
* not estimated ones.
|
|
9
|
-
*
|
|
10
|
-
* @module context-tools/token-counter
|
|
11
|
-
* @version 1.0.0
|
|
12
|
-
*/
|
|
13
|
-
|
|
14
|
-
import type { TokenMetrics } from './types'
|
|
15
|
-
|
|
16
|
-
// =============================================================================
|
|
17
|
-
// Constants
|
|
18
|
-
// =============================================================================
|
|
19
|
-
|
|
20
|
-
/**
|
|
21
|
-
* Average characters per token
|
|
22
|
-
*
|
|
23
|
-
* Based on empirical analysis of Claude/GPT tokenizers:
|
|
24
|
-
* - Code averages ~3.5-4.5 chars/token
|
|
25
|
-
* - English text averages ~4-5 chars/token
|
|
26
|
-
* - We use 4 as a conservative middle ground
|
|
27
|
-
*/
|
|
28
|
-
const CHARS_PER_TOKEN = 4
|
|
29
|
-
|
|
30
|
-
/**
|
|
31
|
-
* Model pricing per 1000 tokens (January 2026)
|
|
32
|
-
* Sources:
|
|
33
|
-
* - Anthropic: https://docs.anthropic.com/en/docs/about-claude/models
|
|
34
|
-
* - OpenAI: https://openai.com/pricing
|
|
35
|
-
* - Google: https://ai.google.dev/pricing
|
|
36
|
-
*/
|
|
37
|
-
const MODEL_PRICING = {
|
|
38
|
-
// Anthropic Claude (2026)
|
|
39
|
-
'claude-opus-4.5': { input: 0.005, output: 0.025 }, // $5/$25 per M
|
|
40
|
-
'claude-sonnet-4.5': { input: 0.003, output: 0.015 }, // $3/$15 per M
|
|
41
|
-
'claude-haiku-4.5': { input: 0.001, output: 0.005 }, // $1/$5 per M
|
|
42
|
-
'claude-opus-4': { input: 0.015, output: 0.075 }, // $15/$75 per M (legacy)
|
|
43
|
-
'claude-opus-4-6': { input: 0.015, output: 0.075 }, // $15/$75 per M
|
|
44
|
-
// OpenAI
|
|
45
|
-
'gpt-4o': { input: 0.0025, output: 0.01 }, // $2.50/$10 per M
|
|
46
|
-
'gpt-4-turbo': { input: 0.01, output: 0.03 }, // $10/$30 per M
|
|
47
|
-
'gpt-4o-mini': { input: 0.00015, output: 0.0006 }, // $0.15/$0.60 per M
|
|
48
|
-
// Google
|
|
49
|
-
'gemini-1.5-pro': { input: 0.00125, output: 0.005 }, // $1.25/$5 per M
|
|
50
|
-
'gemini-1.5-flash': { input: 0.000075, output: 0.0003 }, // $0.075/$0.30 per M
|
|
51
|
-
} as const
|
|
52
|
-
|
|
53
|
-
type ModelName = keyof typeof MODEL_PRICING
|
|
54
|
-
|
|
55
|
-
// Default model for cost calculations
|
|
56
|
-
const DEFAULT_MODEL: ModelName = 'claude-sonnet-4.5'
|
|
57
|
-
|
|
58
|
-
// =============================================================================
|
|
59
|
-
// Core Functions
|
|
60
|
-
// =============================================================================
|
|
61
|
-
|
|
62
|
-
/**
|
|
63
|
-
* Count tokens in a text string
|
|
64
|
-
*
|
|
65
|
-
* Uses character-based estimation that's accurate enough for
|
|
66
|
-
* measuring compression rates without requiring actual tokenizer.
|
|
67
|
-
*
|
|
68
|
-
* @param text - The text to count tokens for
|
|
69
|
-
* @returns Estimated token count
|
|
70
|
-
*/
|
|
71
|
-
export function countTokens(text: string): number {
|
|
72
|
-
if (!text || text.length === 0) return 0
|
|
73
|
-
return Math.ceil(text.length / CHARS_PER_TOKEN)
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
/**
|
|
77
|
-
* Models to show in cost breakdown (most popular)
|
|
78
|
-
*/
|
|
79
|
-
const BREAKDOWN_MODELS: ModelName[] = [
|
|
80
|
-
'claude-sonnet-4.5',
|
|
81
|
-
'claude-opus-4.5',
|
|
82
|
-
'claude-opus-4-6',
|
|
83
|
-
'gpt-4o',
|
|
84
|
-
'gemini-1.5-pro',
|
|
85
|
-
]
|
|
86
|
-
|
|
87
|
-
/**
|
|
88
|
-
* Calculate cost breakdown for a model
|
|
89
|
-
* Output potential = estimated savings if response is proportionally shorter
|
|
90
|
-
*/
|
|
91
|
-
function calculateModelCost(
|
|
92
|
-
tokensSaved: number,
|
|
93
|
-
model: ModelName
|
|
94
|
-
): {
|
|
95
|
-
inputSaved: number
|
|
96
|
-
outputPotential: number
|
|
97
|
-
total: number
|
|
98
|
-
} {
|
|
99
|
-
const pricing = MODEL_PRICING[model]
|
|
100
|
-
const inputSaved = (tokensSaved / 1000) * pricing.input
|
|
101
|
-
// Conservative estimate: output savings ~30% of compression benefit
|
|
102
|
-
// (less context = more focused response, but not 1:1)
|
|
103
|
-
const outputPotential = (tokensSaved / 1000) * pricing.output * 0.3
|
|
104
|
-
return {
|
|
105
|
-
inputSaved,
|
|
106
|
-
outputPotential,
|
|
107
|
-
total: inputSaved + outputPotential,
|
|
108
|
-
}
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
/**
|
|
112
|
-
* Format cost as currency string
|
|
113
|
-
*/
|
|
114
|
-
function formatCostSaved(cost: number): string {
|
|
115
|
-
if (cost < 0.001) {
|
|
116
|
-
return '<$0.01'
|
|
117
|
-
}
|
|
118
|
-
if (cost < 0.01) {
|
|
119
|
-
return `$${cost.toFixed(3)}`
|
|
120
|
-
}
|
|
121
|
-
return `$${cost.toFixed(2)}`
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
/**
|
|
125
|
-
* Measure compression between original and filtered content
|
|
126
|
-
*
|
|
127
|
-
* @param original - Original content before filtering
|
|
128
|
-
* @param filtered - Filtered content after compression
|
|
129
|
-
* @returns Token metrics with compression rate and multi-model cost savings
|
|
130
|
-
*/
|
|
131
|
-
export function measureCompression(original: string, filtered: string): TokenMetrics {
|
|
132
|
-
const originalTokens = countTokens(original)
|
|
133
|
-
const filteredTokens = countTokens(filtered)
|
|
134
|
-
const tokensSaved = Math.max(0, originalTokens - filteredTokens)
|
|
135
|
-
|
|
136
|
-
const compression = originalTokens > 0 ? (originalTokens - filteredTokens) / originalTokens : 0
|
|
137
|
-
|
|
138
|
-
// Calculate cost for default model
|
|
139
|
-
const defaultCost = calculateModelCost(tokensSaved, DEFAULT_MODEL)
|
|
140
|
-
|
|
141
|
-
// Calculate breakdown for popular models
|
|
142
|
-
const byModel = BREAKDOWN_MODELS.map((model) => ({
|
|
143
|
-
model,
|
|
144
|
-
...calculateModelCost(tokensSaved, model),
|
|
145
|
-
}))
|
|
146
|
-
|
|
147
|
-
return {
|
|
148
|
-
tokens: {
|
|
149
|
-
original: originalTokens,
|
|
150
|
-
filtered: filteredTokens,
|
|
151
|
-
saved: tokensSaved,
|
|
152
|
-
},
|
|
153
|
-
compression: Math.max(0, Math.min(1, compression)),
|
|
154
|
-
cost: {
|
|
155
|
-
saved: defaultCost.total,
|
|
156
|
-
formatted: formatCostSaved(defaultCost.total),
|
|
157
|
-
byModel,
|
|
158
|
-
},
|
|
159
|
-
}
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
/**
|
|
163
|
-
* Create metrics for a fallback (no compression) case
|
|
164
|
-
*
|
|
165
|
-
* @param content - The full content that couldn't be compressed
|
|
166
|
-
* @returns Token metrics with 0% compression
|
|
167
|
-
*/
|
|
168
|
-
export function noCompression(content: string): TokenMetrics {
|
|
169
|
-
const tokens = countTokens(content)
|
|
170
|
-
|
|
171
|
-
return {
|
|
172
|
-
tokens: { original: tokens, filtered: tokens, saved: 0 },
|
|
173
|
-
compression: 0,
|
|
174
|
-
cost: {
|
|
175
|
-
saved: 0,
|
|
176
|
-
formatted: '$0.00',
|
|
177
|
-
byModel: BREAKDOWN_MODELS.map((model) => ({
|
|
178
|
-
model,
|
|
179
|
-
inputSaved: 0,
|
|
180
|
-
outputPotential: 0,
|
|
181
|
-
total: 0,
|
|
182
|
-
})),
|
|
183
|
-
},
|
|
184
|
-
}
|
|
185
|
-
}
|
|
186
|
-
|
|
187
|
-
/**
|
|
188
|
-
* Combine multiple token metrics into one
|
|
189
|
-
*
|
|
190
|
-
* Useful when processing multiple files and aggregating results.
|
|
191
|
-
*
|
|
192
|
-
* @param metrics - Array of token metrics to combine
|
|
193
|
-
* @returns Combined metrics
|
|
194
|
-
*/
|
|
195
|
-
export function combineMetrics(metrics: TokenMetrics[]): TokenMetrics {
|
|
196
|
-
if (metrics.length === 0) {
|
|
197
|
-
return noCompression('')
|
|
198
|
-
}
|
|
199
|
-
|
|
200
|
-
// Sum tokens
|
|
201
|
-
const totalOriginal = metrics.reduce((sum, m) => sum + m.tokens.original, 0)
|
|
202
|
-
const totalFiltered = metrics.reduce((sum, m) => sum + m.tokens.filtered, 0)
|
|
203
|
-
const totalSaved = metrics.reduce((sum, m) => sum + m.tokens.saved, 0)
|
|
204
|
-
|
|
205
|
-
// Calculate overall compression
|
|
206
|
-
const compression = totalOriginal > 0 ? (totalOriginal - totalFiltered) / totalOriginal : 0
|
|
207
|
-
|
|
208
|
-
// Sum costs by model
|
|
209
|
-
const byModel = BREAKDOWN_MODELS.map((model) => {
|
|
210
|
-
const modelMetrics = metrics.map(
|
|
211
|
-
(m) =>
|
|
212
|
-
m.cost.byModel.find((b) => b.model === model) || {
|
|
213
|
-
inputSaved: 0,
|
|
214
|
-
outputPotential: 0,
|
|
215
|
-
total: 0,
|
|
216
|
-
}
|
|
217
|
-
)
|
|
218
|
-
return {
|
|
219
|
-
model,
|
|
220
|
-
inputSaved: modelMetrics.reduce((sum, m) => sum + m.inputSaved, 0),
|
|
221
|
-
outputPotential: modelMetrics.reduce((sum, m) => sum + m.outputPotential, 0),
|
|
222
|
-
total: modelMetrics.reduce((sum, m) => sum + m.total, 0),
|
|
223
|
-
}
|
|
224
|
-
})
|
|
225
|
-
|
|
226
|
-
const totalCost = metrics.reduce((sum, m) => sum + m.cost.saved, 0)
|
|
227
|
-
|
|
228
|
-
return {
|
|
229
|
-
tokens: {
|
|
230
|
-
original: totalOriginal,
|
|
231
|
-
filtered: totalFiltered,
|
|
232
|
-
saved: totalSaved,
|
|
233
|
-
},
|
|
234
|
-
compression,
|
|
235
|
-
cost: {
|
|
236
|
-
saved: totalCost,
|
|
237
|
-
formatted: formatCostSaved(totalCost),
|
|
238
|
-
byModel,
|
|
239
|
-
},
|
|
240
|
-
}
|
|
241
|
-
}
|
|
242
|
-
|
|
243
|
-
/**
|
|
244
|
-
* Format token count for display
|
|
245
|
-
*
|
|
246
|
-
* @param tokens - Number of tokens
|
|
247
|
-
* @returns Human-readable string (e.g., "1.5K", "2.3M")
|
|
248
|
-
*/
|
|
249
|
-
export function formatTokenCount(tokens: number): string {
|
|
250
|
-
if (tokens >= 1_000_000) {
|
|
251
|
-
return `${(tokens / 1_000_000).toFixed(1)}M`
|
|
252
|
-
}
|
|
253
|
-
if (tokens >= 1_000) {
|
|
254
|
-
return `${(tokens / 1_000).toFixed(1)}K`
|
|
255
|
-
}
|
|
256
|
-
return tokens.toLocaleString()
|
|
257
|
-
}
|
|
258
|
-
|
|
259
|
-
/**
|
|
260
|
-
* Format compression rate for display
|
|
261
|
-
*
|
|
262
|
-
* @param rate - Compression rate (0-1)
|
|
263
|
-
* @returns Human-readable string (e.g., "89%")
|
|
264
|
-
*/
|
|
265
|
-
export function formatCompressionRate(rate: number): string {
|
|
266
|
-
return `${Math.round(rate * 100)}%`
|
|
267
|
-
}
|
|
268
|
-
|
|
269
|
-
// =============================================================================
|
|
270
|
-
// Exports
|
|
271
|
-
// =============================================================================
|
|
272
|
-
|
|
273
|
-
export { formatCostSaved }
|