prjct-cli 0.11.4 → 0.12.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 +72 -0
- package/README.md +81 -25
- package/bin/dev.js +1 -1
- package/bin/generate-views.js +209 -0
- package/bin/migrate-to-json.js +742 -0
- package/bin/prjct +5 -5
- package/bin/serve.js +246 -54
- package/core/__tests__/agentic/{memory-system.test.js → memory-system.test.ts} +12 -23
- package/core/__tests__/agentic/{plan-mode.test.js → plan-mode.test.ts} +26 -24
- package/core/__tests__/agentic/{prompt-builder.test.js → prompt-builder.test.ts} +3 -8
- package/core/__tests__/utils/date-helper.test.ts +405 -0
- package/core/__tests__/utils/{output.test.js → output.test.ts} +12 -24
- package/core/agentic/agent-router.ts +137 -0
- package/core/agentic/chain-of-thought.ts +228 -0
- package/core/agentic/command-executor/command-executor.ts +384 -0
- package/core/agentic/command-executor/index.ts +16 -0
- package/core/agentic/command-executor/status-signal.ts +38 -0
- package/core/agentic/command-executor/types.ts +79 -0
- package/core/agentic/command-executor.ts +8 -0
- package/core/agentic/{context-builder.js → context-builder.ts} +99 -89
- package/core/agentic/context-filter.ts +365 -0
- package/core/agentic/ground-truth/index.ts +76 -0
- package/core/agentic/ground-truth/types.ts +33 -0
- package/core/agentic/ground-truth/utils.ts +48 -0
- package/core/agentic/ground-truth/verifiers/analyze.ts +54 -0
- package/core/agentic/ground-truth/verifiers/done.ts +75 -0
- package/core/agentic/ground-truth/verifiers/feature.ts +70 -0
- package/core/agentic/ground-truth/verifiers/index.ts +37 -0
- package/core/agentic/ground-truth/verifiers/init.ts +52 -0
- package/core/agentic/ground-truth/verifiers/now.ts +57 -0
- package/core/agentic/ground-truth/verifiers/ship.ts +85 -0
- package/core/agentic/ground-truth/verifiers/spec.ts +45 -0
- package/core/agentic/ground-truth/verifiers/sync.ts +47 -0
- package/core/agentic/ground-truth/verifiers.ts +6 -0
- package/core/agentic/ground-truth.ts +8 -0
- package/core/agentic/loop-detector/error-analysis.ts +97 -0
- package/core/agentic/loop-detector/hallucination.ts +71 -0
- package/core/agentic/loop-detector/index.ts +41 -0
- package/core/agentic/loop-detector/loop-detector.ts +222 -0
- package/core/agentic/loop-detector/types.ts +66 -0
- package/core/agentic/loop-detector.ts +8 -0
- package/core/agentic/memory-system/history.ts +53 -0
- package/core/agentic/memory-system/index.ts +192 -0
- package/core/agentic/memory-system/patterns.ts +156 -0
- package/core/agentic/memory-system/semantic-memories.ts +277 -0
- package/core/agentic/memory-system/session.ts +21 -0
- package/core/agentic/memory-system/types.ts +159 -0
- package/core/agentic/memory-system.ts +8 -0
- package/core/agentic/parallel-tools.ts +165 -0
- package/core/agentic/plan-mode/approval.ts +57 -0
- package/core/agentic/plan-mode/constants.ts +44 -0
- package/core/agentic/plan-mode/index.ts +28 -0
- package/core/agentic/plan-mode/plan-mode.ts +406 -0
- package/core/agentic/plan-mode/types.ts +193 -0
- package/core/agentic/plan-mode.ts +8 -0
- package/core/agentic/prompt-builder.ts +566 -0
- package/core/agentic/response-templates.ts +164 -0
- package/core/agentic/semantic-compression.ts +273 -0
- package/core/agentic/services.ts +206 -0
- package/core/agentic/smart-context.ts +476 -0
- package/core/agentic/{template-loader.js → template-loader.ts} +35 -18
- package/core/agentic/think-blocks.ts +202 -0
- package/core/agentic/tool-registry.ts +119 -0
- package/core/agentic/validation-rules.ts +313 -0
- package/core/agents/index.ts +28 -0
- package/core/agents/performance.ts +444 -0
- package/core/agents/types.ts +126 -0
- package/core/bus/{index.js → index.ts} +57 -61
- package/core/command-registry/categories.ts +23 -0
- package/core/command-registry/commands.ts +15 -0
- package/core/command-registry/core-commands.ts +319 -0
- package/core/command-registry/index.ts +158 -0
- package/core/command-registry/optional-commands.ts +119 -0
- package/core/command-registry/setup-commands.ts +53 -0
- package/core/command-registry/types.ts +59 -0
- package/core/command-registry.ts +9 -0
- package/core/commands/analysis.ts +298 -0
- package/core/commands/analytics.ts +288 -0
- package/core/commands/base.ts +273 -0
- package/core/commands/index.ts +211 -0
- package/core/commands/maintenance.ts +226 -0
- package/core/commands/planning.ts +311 -0
- package/core/commands/setup.ts +309 -0
- package/core/commands/shipping.ts +188 -0
- package/core/commands/types.ts +183 -0
- package/core/commands/workflow.ts +226 -0
- package/core/commands.ts +11 -0
- package/core/constants/formats.ts +187 -0
- package/core/constants/index.ts +7 -0
- package/core/{context-sync.js → context-sync.ts} +59 -26
- package/core/data/agents-manager.ts +76 -0
- package/core/data/analysis-manager.ts +83 -0
- package/core/data/base-manager.ts +156 -0
- package/core/data/ideas-manager.ts +81 -0
- package/core/data/index.ts +32 -0
- package/core/data/outcomes-manager.ts +96 -0
- package/core/data/project-manager.ts +75 -0
- package/core/data/roadmap-manager.ts +118 -0
- package/core/data/shipped-manager.ts +65 -0
- package/core/data/state-manager.ts +214 -0
- package/core/domain/{agent-generator.js → agent-generator.ts} +77 -57
- package/core/domain/{agent-loader.js → agent-loader.ts} +65 -56
- package/core/domain/{agent-matcher.js → agent-matcher.ts} +51 -24
- package/core/domain/{agent-validator.js → agent-validator.ts} +70 -37
- package/core/domain/{analyzer.js → analyzer.ts} +91 -85
- package/core/domain/{architect-session.js → architect-session.ts} +49 -34
- package/core/domain/{architecture-generator.js → architecture-generator.ts} +25 -13
- package/core/domain/{context-estimator.js → context-estimator.ts} +57 -36
- package/core/domain/{product-standards.js → product-standards.ts} +40 -26
- package/core/domain/{smart-cache.js → smart-cache.ts} +39 -30
- package/core/domain/{snapshot-manager.js → snapshot-manager.ts} +103 -100
- package/core/domain/{task-analyzer.js → task-analyzer.ts} +82 -43
- package/core/domain/task-stack/index.ts +19 -0
- package/core/domain/task-stack/parser.ts +86 -0
- package/core/domain/task-stack/storage.ts +123 -0
- package/core/domain/task-stack/task-stack.ts +340 -0
- package/core/domain/task-stack/types.ts +51 -0
- package/core/domain/task-stack.ts +8 -0
- package/core/{index.js → index.ts} +61 -18
- package/core/infrastructure/{agent-detector.js → agent-detector.ts} +62 -23
- package/core/infrastructure/agents/{claude-agent.js → claude-agent.ts} +61 -21
- package/core/infrastructure/{author-detector.js → author-detector.ts} +42 -49
- package/core/infrastructure/{capability-installer.js → capability-installer.ts} +51 -27
- package/core/infrastructure/{command-installer.js → command-installer/command-installer.ts} +43 -144
- package/core/infrastructure/command-installer/global-config.ts +106 -0
- package/core/infrastructure/command-installer/index.ts +25 -0
- package/core/infrastructure/command-installer/types.ts +41 -0
- package/core/infrastructure/command-installer.ts +8 -0
- package/core/infrastructure/{config-manager.js → config-manager.ts} +60 -80
- package/core/infrastructure/{editors-config.js → editors-config.ts} +33 -31
- package/core/infrastructure/legacy-installer-detector/cleanup.ts +216 -0
- package/core/infrastructure/legacy-installer-detector/detection.ts +95 -0
- package/core/infrastructure/legacy-installer-detector/index.ts +171 -0
- package/core/infrastructure/legacy-installer-detector/migration.ts +87 -0
- package/core/infrastructure/legacy-installer-detector/types.ts +42 -0
- package/core/infrastructure/legacy-installer-detector.ts +7 -0
- package/core/infrastructure/migrator/file-operations.ts +125 -0
- package/core/infrastructure/migrator/index.ts +288 -0
- package/core/infrastructure/migrator/project-scanner.ts +89 -0
- package/core/infrastructure/migrator/reports.ts +117 -0
- package/core/infrastructure/migrator/types.ts +124 -0
- package/core/infrastructure/migrator/validation.ts +94 -0
- package/core/infrastructure/migrator/version-migration.ts +117 -0
- package/core/infrastructure/migrator.ts +10 -0
- package/core/infrastructure/{path-manager.js → path-manager.ts} +51 -91
- package/core/infrastructure/session-manager/index.ts +23 -0
- package/core/infrastructure/session-manager/migration.ts +88 -0
- package/core/infrastructure/session-manager/session-manager.ts +307 -0
- package/core/infrastructure/session-manager/types.ts +45 -0
- package/core/infrastructure/session-manager.ts +8 -0
- package/core/infrastructure/{setup.js → setup.ts} +29 -21
- package/core/infrastructure/{update-checker.js → update-checker.ts} +40 -18
- package/core/outcomes/analyzer.ts +333 -0
- package/core/outcomes/index.ts +34 -0
- package/core/outcomes/recorder.ts +194 -0
- package/core/outcomes/types.ts +145 -0
- package/core/plugin/{hooks.js → hooks.ts} +56 -58
- package/core/plugin/{index.js → index.ts} +19 -8
- package/core/plugin/{loader.js → loader.ts} +87 -69
- package/core/plugin/{registry.js → registry.ts} +49 -45
- package/core/plugins/{webhook.js → webhook.ts} +43 -27
- package/core/schemas/agents.ts +27 -0
- package/core/schemas/analysis.ts +41 -0
- package/core/schemas/ideas.ts +83 -0
- package/core/schemas/index.ts +73 -0
- package/core/schemas/outcomes.ts +22 -0
- package/core/schemas/project.ts +26 -0
- package/core/schemas/roadmap.ts +90 -0
- package/core/schemas/shipped.ts +82 -0
- package/core/schemas/state.ts +107 -0
- package/core/session/index.ts +17 -0
- package/core/session/{metrics.js → metrics.ts} +64 -46
- package/core/session/{index.js → session-manager.ts} +51 -117
- package/core/session/types.ts +29 -0
- package/core/session/utils.ts +57 -0
- package/core/state/index.ts +25 -0
- package/core/state/manager.ts +376 -0
- package/core/state/types.ts +185 -0
- package/core/tsconfig.json +22 -0
- package/core/types/index.ts +506 -0
- package/core/utils/{animations.js → animations.ts} +74 -28
- package/core/utils/{branding.js → branding.ts} +29 -4
- package/core/utils/{date-helper.js → date-helper.ts} +31 -74
- package/core/utils/file-helper.ts +262 -0
- package/core/utils/{jsonl-helper.js → jsonl-helper.ts} +71 -107
- package/core/utils/{logger.js → logger.ts} +24 -12
- package/core/utils/{output.js → output.ts} +25 -13
- package/core/utils/{project-capabilities.js → project-capabilities.ts} +31 -18
- package/core/utils/{session-helper.js → session-helper.ts} +79 -66
- package/core/utils/{version.js → version.ts} +23 -31
- package/core/view-generator.ts +536 -0
- package/package.json +23 -17
- package/packages/shared/.turbo/turbo-build.log +14 -0
- package/packages/shared/dist/index.d.ts +8 -613
- package/packages/shared/dist/index.d.ts.map +1 -0
- package/packages/shared/dist/index.js +4110 -118
- package/packages/shared/dist/schemas.d.ts +408 -0
- package/packages/shared/dist/schemas.d.ts.map +1 -0
- package/packages/shared/dist/types.d.ts +144 -0
- package/packages/shared/dist/types.d.ts.map +1 -0
- package/packages/shared/dist/unified.d.ts +139 -0
- package/packages/shared/dist/unified.d.ts.map +1 -0
- package/packages/shared/dist/utils.d.ts +60 -0
- package/packages/shared/dist/utils.d.ts.map +1 -0
- package/packages/shared/package.json +4 -4
- package/packages/shared/src/index.ts +1 -0
- package/packages/shared/src/unified.ts +174 -0
- package/packages/web/app/api/claude/sessions/route.ts +1 -1
- package/packages/web/app/api/claude/status/route.ts +1 -1
- package/packages/web/app/api/migrate/route.ts +46 -0
- package/packages/web/app/api/projects/[id]/route.ts +1 -1
- package/packages/web/app/api/projects/[id]/stats/route.ts +30 -2
- package/packages/web/app/api/projects/[id]/status/route.ts +1 -1
- package/packages/web/app/api/projects/route.ts +1 -1
- package/packages/web/app/api/settings/route.ts +97 -0
- package/packages/web/app/api/v2/projects/[id]/unified/route.ts +57 -0
- package/packages/web/app/globals.css +38 -0
- package/packages/web/app/layout.tsx +10 -2
- package/packages/web/app/page.tsx +9 -224
- package/packages/web/app/project/[id]/page.tsx +191 -63
- package/packages/web/app/project/[id]/stats/loading.tsx +43 -0
- package/packages/web/app/project/[id]/stats/page.tsx +203 -403
- package/packages/web/app/settings/page.tsx +222 -2
- package/packages/web/components/ActivityTimeline/ActivityTimeline.constants.ts +2 -0
- package/packages/web/components/ActivityTimeline/ActivityTimeline.tsx +50 -0
- package/packages/web/components/ActivityTimeline/ActivityTimeline.types.ts +8 -0
- package/packages/web/components/ActivityTimeline/hooks/index.ts +2 -0
- package/packages/web/components/ActivityTimeline/hooks/useExpandable.ts +9 -0
- package/packages/web/components/ActivityTimeline/hooks/useGroupedEvents.ts +23 -0
- package/packages/web/components/ActivityTimeline/index.ts +2 -0
- package/packages/web/components/AgentsCard/AgentsCard.tsx +63 -0
- package/packages/web/components/AgentsCard/AgentsCard.types.ts +13 -0
- package/packages/web/components/AgentsCard/index.ts +2 -0
- package/packages/web/components/AppSidebar/AppSidebar.tsx +134 -0
- package/packages/web/components/AppSidebar/index.ts +1 -0
- package/packages/web/components/BackLink/BackLink.tsx +18 -0
- package/packages/web/components/BackLink/BackLink.types.ts +5 -0
- package/packages/web/components/BackLink/index.ts +2 -0
- package/packages/web/components/BentoCard/BentoCard.constants.ts +16 -0
- package/packages/web/components/BentoCard/BentoCard.tsx +47 -0
- package/packages/web/components/BentoCard/BentoCard.types.ts +15 -0
- package/packages/web/components/BentoCard/index.ts +2 -0
- package/packages/web/components/BentoCardSkeleton/BentoCardSkeleton.constants.ts +9 -0
- package/packages/web/components/BentoCardSkeleton/BentoCardSkeleton.tsx +18 -0
- package/packages/web/components/BentoCardSkeleton/BentoCardSkeleton.types.ts +5 -0
- package/packages/web/components/BentoCardSkeleton/index.ts +2 -0
- package/packages/web/components/BentoGrid/BentoGrid.tsx +18 -0
- package/packages/web/components/BentoGrid/BentoGrid.types.ts +4 -0
- package/packages/web/components/BentoGrid/index.ts +2 -0
- package/packages/web/components/CommandButton/index.ts +1 -0
- package/packages/web/components/ConnectionStatus/index.ts +1 -0
- package/packages/web/components/DashboardContent/DashboardContent.tsx +254 -0
- package/packages/web/components/DashboardContent/index.ts +1 -0
- package/packages/web/components/DateGroup/DateGroup.tsx +18 -0
- package/packages/web/components/DateGroup/DateGroup.types.ts +6 -0
- package/packages/web/components/DateGroup/DateGroup.utils.ts +11 -0
- package/packages/web/components/DateGroup/index.ts +2 -0
- package/packages/web/components/EmptyState/EmptyState.tsx +58 -0
- package/packages/web/components/EmptyState/EmptyState.types.ts +10 -0
- package/packages/web/components/EmptyState/index.ts +2 -0
- package/packages/web/components/EventRow/EventRow.constants.ts +10 -0
- package/packages/web/components/EventRow/EventRow.tsx +49 -0
- package/packages/web/components/EventRow/EventRow.types.ts +7 -0
- package/packages/web/components/EventRow/EventRow.utils.ts +49 -0
- package/packages/web/components/EventRow/index.ts +2 -0
- package/packages/web/components/ExpandButton/ExpandButton.tsx +18 -0
- package/packages/web/components/ExpandButton/ExpandButton.types.ts +6 -0
- package/packages/web/components/ExpandButton/index.ts +2 -0
- package/packages/web/components/HealthGradientBackground/HealthGradientBackground.tsx +14 -0
- package/packages/web/components/HealthGradientBackground/HealthGradientBackground.types.ts +5 -0
- package/packages/web/components/HealthGradientBackground/HealthGradientBackground.utils.ts +13 -0
- package/packages/web/components/HealthGradientBackground/index.ts +2 -0
- package/packages/web/components/HeroSection/HeroSection.tsx +55 -0
- package/packages/web/components/HeroSection/HeroSection.types.ts +14 -0
- package/packages/web/components/HeroSection/HeroSection.utils.ts +7 -0
- package/packages/web/components/HeroSection/hooks/index.ts +2 -0
- package/packages/web/components/HeroSection/hooks/useCountUp.ts +45 -0
- package/packages/web/components/HeroSection/hooks/useWeeklyActivity.ts +18 -0
- package/packages/web/components/HeroSection/index.ts +2 -0
- package/packages/web/components/IdeasCard/IdeasCard.tsx +48 -0
- package/packages/web/components/IdeasCard/IdeasCard.types.ts +9 -0
- package/packages/web/components/IdeasCard/index.ts +2 -0
- package/packages/web/components/InsightMessage/InsightMessage.tsx +9 -0
- package/packages/web/components/InsightMessage/InsightMessage.types.ts +3 -0
- package/packages/web/components/InsightMessage/index.ts +2 -0
- package/packages/web/components/Logo/index.ts +1 -0
- package/packages/web/components/MarkdownContent/index.ts +1 -0
- package/packages/web/components/NowCard/NowCard.tsx +93 -0
- package/packages/web/components/NowCard/NowCard.types.ts +15 -0
- package/packages/web/components/NowCard/index.ts +2 -0
- package/packages/web/components/ProgressRing/ProgressRing.constants.ts +20 -0
- package/packages/web/components/ProgressRing/ProgressRing.tsx +51 -0
- package/packages/web/components/ProgressRing/ProgressRing.types.ts +11 -0
- package/packages/web/components/ProgressRing/index.ts +2 -0
- package/packages/web/components/ProjectAvatar/index.ts +1 -0
- package/packages/web/components/Providers/index.ts +1 -0
- package/packages/web/components/QueueCard/QueueCard.tsx +72 -0
- package/packages/web/components/QueueCard/QueueCard.types.ts +11 -0
- package/packages/web/components/QueueCard/QueueCard.utils.ts +12 -0
- package/packages/web/components/QueueCard/index.ts +2 -0
- package/packages/web/components/RoadmapCard/RoadmapCard.tsx +77 -0
- package/packages/web/components/RoadmapCard/RoadmapCard.types.ts +15 -0
- package/packages/web/components/RoadmapCard/index.ts +2 -0
- package/packages/web/components/ShipsCard/ShipsCard.tsx +52 -0
- package/packages/web/components/ShipsCard/ShipsCard.types.ts +12 -0
- package/packages/web/components/ShipsCard/ShipsCard.utils.ts +4 -0
- package/packages/web/components/ShipsCard/index.ts +2 -0
- package/packages/web/components/SparklineChart/SparklineChart.tsx +38 -0
- package/packages/web/components/SparklineChart/SparklineChart.types.ts +6 -0
- package/packages/web/components/SparklineChart/index.ts +2 -0
- package/packages/web/components/StreakCard/StreakCard.constants.ts +2 -0
- package/packages/web/components/StreakCard/StreakCard.tsx +53 -0
- package/packages/web/components/StreakCard/StreakCard.types.ts +4 -0
- package/packages/web/components/StreakCard/index.ts +2 -0
- package/packages/web/components/TasksCounter/TasksCounter.tsx +14 -0
- package/packages/web/components/TasksCounter/TasksCounter.types.ts +3 -0
- package/packages/web/components/TasksCounter/index.ts +2 -0
- package/packages/web/components/TechStackBadges/index.ts +1 -0
- package/packages/web/components/{TerminalTab.tsx → TerminalTabs/TerminalTab.tsx} +11 -0
- package/packages/web/components/{TerminalTabs.tsx → TerminalTabs/TerminalTabs.tsx} +29 -28
- package/packages/web/components/TerminalTabs/index.ts +1 -0
- package/packages/web/components/VelocityBadge/VelocityBadge.tsx +27 -0
- package/packages/web/components/VelocityBadge/VelocityBadge.types.ts +3 -0
- package/packages/web/components/VelocityBadge/index.ts +2 -0
- package/packages/web/components/VelocityCard/VelocityCard.tsx +71 -0
- package/packages/web/components/VelocityCard/VelocityCard.types.ts +7 -0
- package/packages/web/components/VelocityCard/index.ts +2 -0
- package/packages/web/components/WeeklySparkline/WeeklySparkline.tsx +13 -0
- package/packages/web/components/WeeklySparkline/WeeklySparkline.types.ts +3 -0
- package/packages/web/components/WeeklySparkline/index.ts +2 -0
- package/packages/web/components/ui/input.tsx +21 -0
- package/packages/web/components/ui/tooltip.tsx +2 -2
- package/packages/web/context/TerminalTabsContext.tsx +46 -1
- package/packages/web/hooks/useClaudeTerminal.ts +71 -21
- package/packages/web/hooks/useProjectStats.ts +55 -0
- package/packages/web/hooks/useProjects.ts +6 -6
- package/packages/web/lib/actions/projects.ts +15 -0
- package/packages/web/lib/json-loader.ts +630 -0
- package/packages/web/lib/services/index.ts +9 -0
- package/packages/web/lib/services/migration.server.ts +598 -0
- package/packages/web/lib/services/projects.server.ts +52 -0
- package/packages/web/lib/services/stats.server.ts +264 -0
- package/packages/web/lib/unified-loader.ts +396 -0
- package/packages/web/next-env.d.ts +1 -1
- package/packages/web/package.json +10 -6
- package/packages/web/server.ts +36 -6
- package/templates/commands/done.md +76 -32
- package/templates/commands/feature.md +121 -47
- package/templates/commands/idea.md +81 -8
- package/templates/commands/now.md +41 -17
- package/templates/commands/ship.md +64 -25
- package/templates/commands/sync.md +28 -3
- package/core/agentic/agent-router.js +0 -128
- package/core/agentic/chain-of-thought.js +0 -578
- package/core/agentic/command-executor.js +0 -421
- package/core/agentic/context-filter.js +0 -354
- package/core/agentic/ground-truth.js +0 -591
- package/core/agentic/loop-detector.js +0 -406
- package/core/agentic/memory-system.js +0 -850
- package/core/agentic/parallel-tools.js +0 -366
- package/core/agentic/plan-mode.js +0 -572
- package/core/agentic/prompt-builder.js +0 -338
- package/core/agentic/response-templates.js +0 -290
- package/core/agentic/semantic-compression.js +0 -517
- package/core/agentic/think-blocks.js +0 -657
- package/core/agentic/tool-registry.js +0 -184
- package/core/agentic/validation-rules.js +0 -380
- package/core/command-registry.js +0 -698
- package/core/commands.js +0 -2237
- package/core/domain/task-stack.js +0 -497
- package/core/infrastructure/legacy-installer-detector.js +0 -546
- package/core/infrastructure/migrator.js +0 -799
- package/core/infrastructure/session-manager.js +0 -390
- package/core/utils/file-helper.js +0 -329
- package/packages/web/app/api/projects/[id]/delete/route.ts +0 -21
- package/packages/web/app/api/stats/route.ts +0 -38
- package/packages/web/components/AppSidebar.tsx +0 -113
- package/packages/web/hooks/useStats.ts +0 -28
- /package/packages/web/components/{CommandButton.tsx → CommandButton/CommandButton.tsx} +0 -0
- /package/packages/web/components/{ConnectionStatus.tsx → ConnectionStatus/ConnectionStatus.tsx} +0 -0
- /package/packages/web/components/{Logo.tsx → Logo/Logo.tsx} +0 -0
- /package/packages/web/components/{MarkdownContent.tsx → MarkdownContent/MarkdownContent.tsx} +0 -0
- /package/packages/web/components/{ProjectAvatar.tsx → ProjectAvatar/ProjectAvatar.tsx} +0 -0
- /package/packages/web/components/{providers.tsx → Providers/Providers.tsx} +0 -0
- /package/packages/web/components/{TechStackBadges.tsx → TechStackBadges/TechStackBadges.tsx} +0 -0
|
@@ -0,0 +1,333 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Outcome Analyzer
|
|
3
|
+
*
|
|
4
|
+
* Analyzes outcomes to extract patterns and insights.
|
|
5
|
+
* Powers the learning loop for better estimates and agent selection.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import outcomeRecorder from './recorder'
|
|
9
|
+
import type { Outcome, OutcomeSummary, QualityScore } from './types'
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Pattern detected from outcomes.
|
|
13
|
+
*/
|
|
14
|
+
export interface DetectedPattern {
|
|
15
|
+
/** Pattern description */
|
|
16
|
+
description: string
|
|
17
|
+
|
|
18
|
+
/** Confidence level (0-1) */
|
|
19
|
+
confidence: number
|
|
20
|
+
|
|
21
|
+
/** Number of occurrences supporting this pattern */
|
|
22
|
+
occurrences: number
|
|
23
|
+
|
|
24
|
+
/** Suggested action based on pattern */
|
|
25
|
+
suggestedAction?: string
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Agent performance metrics.
|
|
30
|
+
*/
|
|
31
|
+
export interface AgentMetrics {
|
|
32
|
+
/** Agent name */
|
|
33
|
+
agent: string
|
|
34
|
+
|
|
35
|
+
/** Number of tasks completed */
|
|
36
|
+
tasksCompleted: number
|
|
37
|
+
|
|
38
|
+
/** Success rate (0-100) */
|
|
39
|
+
successRate: number
|
|
40
|
+
|
|
41
|
+
/** Average quality score */
|
|
42
|
+
avgQualityScore: number
|
|
43
|
+
|
|
44
|
+
/** Estimate accuracy */
|
|
45
|
+
estimateAccuracy: number
|
|
46
|
+
|
|
47
|
+
/** Best task types for this agent */
|
|
48
|
+
bestFor: string[]
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* OutcomeAnalyzer - Extracts insights from outcomes.
|
|
53
|
+
*/
|
|
54
|
+
export class OutcomeAnalyzer {
|
|
55
|
+
/**
|
|
56
|
+
* Generate summary of all outcomes.
|
|
57
|
+
*/
|
|
58
|
+
async summarize(projectId: string): Promise<OutcomeSummary> {
|
|
59
|
+
const outcomes = await outcomeRecorder.getAll(projectId)
|
|
60
|
+
|
|
61
|
+
if (outcomes.length === 0) {
|
|
62
|
+
return {
|
|
63
|
+
totalOutcomes: 0,
|
|
64
|
+
avgQualityScore: 0,
|
|
65
|
+
estimateAccuracy: 0,
|
|
66
|
+
topBlockers: [],
|
|
67
|
+
topAgents: [],
|
|
68
|
+
patternsDetected: [],
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
// Calculate average quality
|
|
73
|
+
const avgQuality =
|
|
74
|
+
outcomes.reduce((sum, o) => sum + o.qualityScore, 0) / outcomes.length
|
|
75
|
+
|
|
76
|
+
// Calculate estimate accuracy
|
|
77
|
+
const estimateAccuracy = await outcomeRecorder.getEstimateAccuracy(projectId)
|
|
78
|
+
|
|
79
|
+
// Find top blockers
|
|
80
|
+
const blockerCounts = new Map<string, number>()
|
|
81
|
+
for (const outcome of outcomes) {
|
|
82
|
+
for (const blocker of outcome.blockers || []) {
|
|
83
|
+
blockerCounts.set(blocker, (blockerCounts.get(blocker) || 0) + 1)
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
const topBlockers = [...blockerCounts.entries()]
|
|
87
|
+
.sort((a, b) => b[1] - a[1])
|
|
88
|
+
.slice(0, 5)
|
|
89
|
+
.map(([blocker]) => blocker)
|
|
90
|
+
|
|
91
|
+
// Find top agents
|
|
92
|
+
const agentMetrics = await this.getAgentMetrics(projectId)
|
|
93
|
+
const topAgents = agentMetrics
|
|
94
|
+
.sort((a, b) => b.successRate - a.successRate)
|
|
95
|
+
.slice(0, 3)
|
|
96
|
+
.map((m) => m.agent)
|
|
97
|
+
|
|
98
|
+
// Detect patterns
|
|
99
|
+
const patterns = await this.detectPatterns(projectId)
|
|
100
|
+
const patternsDetected = patterns.map((p) => p.description)
|
|
101
|
+
|
|
102
|
+
return {
|
|
103
|
+
totalOutcomes: outcomes.length,
|
|
104
|
+
avgQualityScore: Math.round(avgQuality * 10) / 10,
|
|
105
|
+
estimateAccuracy,
|
|
106
|
+
topBlockers,
|
|
107
|
+
topAgents,
|
|
108
|
+
patternsDetected,
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* Get metrics for each agent.
|
|
114
|
+
*/
|
|
115
|
+
async getAgentMetrics(projectId: string): Promise<AgentMetrics[]> {
|
|
116
|
+
const outcomes = await outcomeRecorder.getAll(projectId)
|
|
117
|
+
|
|
118
|
+
// Group by agent
|
|
119
|
+
const byAgent = new Map<string, Outcome[]>()
|
|
120
|
+
for (const outcome of outcomes) {
|
|
121
|
+
const agent = outcome.agentUsed || 'unknown'
|
|
122
|
+
if (!byAgent.has(agent)) {
|
|
123
|
+
byAgent.set(agent, [])
|
|
124
|
+
}
|
|
125
|
+
byAgent.get(agent)!.push(outcome)
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
const metrics: AgentMetrics[] = []
|
|
129
|
+
|
|
130
|
+
for (const [agent, agentOutcomes] of byAgent) {
|
|
131
|
+
const tasksCompleted = agentOutcomes.length
|
|
132
|
+
const successful = agentOutcomes.filter((o) => o.completedAsPlanned)
|
|
133
|
+
const successRate = Math.round((successful.length / tasksCompleted) * 100)
|
|
134
|
+
|
|
135
|
+
const avgQuality =
|
|
136
|
+
agentOutcomes.reduce((sum, o) => sum + o.qualityScore, 0) / tasksCompleted
|
|
137
|
+
|
|
138
|
+
// Calculate estimate accuracy for this agent
|
|
139
|
+
const accurateEstimates = agentOutcomes.filter((o) => {
|
|
140
|
+
if (!o.variance) return false
|
|
141
|
+
const variance = this.parseVariance(o.variance)
|
|
142
|
+
const estimated = this.parseDuration(o.estimatedDuration)
|
|
143
|
+
if (estimated === 0) return false
|
|
144
|
+
return Math.abs(variance) / estimated <= 0.2
|
|
145
|
+
})
|
|
146
|
+
const estimateAccuracy = Math.round(
|
|
147
|
+
(accurateEstimates.length / tasksCompleted) * 100
|
|
148
|
+
)
|
|
149
|
+
|
|
150
|
+
// Find best task types
|
|
151
|
+
const taskTypes = new Map<string, number>()
|
|
152
|
+
for (const o of agentOutcomes.filter((o) => o.completedAsPlanned)) {
|
|
153
|
+
for (const tag of o.tags || []) {
|
|
154
|
+
taskTypes.set(tag, (taskTypes.get(tag) || 0) + 1)
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
const bestFor = [...taskTypes.entries()]
|
|
158
|
+
.sort((a, b) => b[1] - a[1])
|
|
159
|
+
.slice(0, 3)
|
|
160
|
+
.map(([type]) => type)
|
|
161
|
+
|
|
162
|
+
metrics.push({
|
|
163
|
+
agent,
|
|
164
|
+
tasksCompleted,
|
|
165
|
+
successRate,
|
|
166
|
+
avgQualityScore: Math.round(avgQuality * 10) / 10,
|
|
167
|
+
estimateAccuracy,
|
|
168
|
+
bestFor,
|
|
169
|
+
})
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
return metrics
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
/**
|
|
176
|
+
* Detect patterns from outcomes.
|
|
177
|
+
*/
|
|
178
|
+
async detectPatterns(projectId: string): Promise<DetectedPattern[]> {
|
|
179
|
+
const outcomes = await outcomeRecorder.getAll(projectId)
|
|
180
|
+
const patterns: DetectedPattern[] = []
|
|
181
|
+
|
|
182
|
+
if (outcomes.length < 3) {
|
|
183
|
+
return patterns // Need at least 3 outcomes to detect patterns
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
// Pattern: Consistent underestimation
|
|
187
|
+
const underestimated = outcomes.filter((o) => {
|
|
188
|
+
const variance = this.parseVariance(o.variance)
|
|
189
|
+
return variance > 0
|
|
190
|
+
})
|
|
191
|
+
if (underestimated.length / outcomes.length > 0.6) {
|
|
192
|
+
patterns.push({
|
|
193
|
+
description: 'Tasks consistently take longer than estimated',
|
|
194
|
+
confidence: underestimated.length / outcomes.length,
|
|
195
|
+
occurrences: underestimated.length,
|
|
196
|
+
suggestedAction: 'Add 30% buffer to estimates',
|
|
197
|
+
})
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
// Pattern: Consistent overestimation
|
|
201
|
+
const overestimated = outcomes.filter((o) => {
|
|
202
|
+
const variance = this.parseVariance(o.variance)
|
|
203
|
+
return variance < 0
|
|
204
|
+
})
|
|
205
|
+
if (overestimated.length / outcomes.length > 0.6) {
|
|
206
|
+
patterns.push({
|
|
207
|
+
description: 'Tasks consistently finish faster than estimated',
|
|
208
|
+
confidence: overestimated.length / outcomes.length,
|
|
209
|
+
occurrences: overestimated.length,
|
|
210
|
+
suggestedAction: 'Reduce estimates by 20%',
|
|
211
|
+
})
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
// Pattern: Common blockers
|
|
215
|
+
const blockerCounts = new Map<string, number>()
|
|
216
|
+
for (const outcome of outcomes) {
|
|
217
|
+
for (const blocker of outcome.blockers || []) {
|
|
218
|
+
blockerCounts.set(blocker, (blockerCounts.get(blocker) || 0) + 1)
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
for (const [blocker, count] of blockerCounts) {
|
|
222
|
+
if (count >= 3) {
|
|
223
|
+
patterns.push({
|
|
224
|
+
description: `Recurring blocker: ${blocker}`,
|
|
225
|
+
confidence: count / outcomes.length,
|
|
226
|
+
occurrences: count,
|
|
227
|
+
suggestedAction: `Address root cause of "${blocker}"`,
|
|
228
|
+
})
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
// Pattern: Agent performance
|
|
233
|
+
const agentMetrics = await this.getAgentMetrics(projectId)
|
|
234
|
+
for (const metrics of agentMetrics) {
|
|
235
|
+
if (metrics.tasksCompleted >= 5 && metrics.successRate > 90) {
|
|
236
|
+
patterns.push({
|
|
237
|
+
description: `${metrics.agent} has high success rate (${metrics.successRate}%)`,
|
|
238
|
+
confidence: 0.9,
|
|
239
|
+
occurrences: metrics.tasksCompleted,
|
|
240
|
+
suggestedAction: `Prefer ${metrics.agent} for similar tasks`,
|
|
241
|
+
})
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
return patterns.sort((a, b) => b.confidence - a.confidence)
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
/**
|
|
249
|
+
* Suggest estimate for a task type based on history.
|
|
250
|
+
*/
|
|
251
|
+
async suggestEstimate(
|
|
252
|
+
projectId: string,
|
|
253
|
+
taskType: string
|
|
254
|
+
): Promise<string | null> {
|
|
255
|
+
const outcomes = await outcomeRecorder.getAll(projectId)
|
|
256
|
+
|
|
257
|
+
// Filter by task type (using tags)
|
|
258
|
+
const relevant = outcomes.filter((o) => o.tags?.includes(taskType))
|
|
259
|
+
|
|
260
|
+
if (relevant.length < 2) {
|
|
261
|
+
return null // Not enough data
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
// Calculate average actual duration
|
|
265
|
+
const totalMinutes = relevant.reduce((sum, o) => {
|
|
266
|
+
return sum + this.parseDuration(o.actualDuration)
|
|
267
|
+
}, 0)
|
|
268
|
+
|
|
269
|
+
const avgMinutes = Math.round(totalMinutes / relevant.length)
|
|
270
|
+
|
|
271
|
+
// Format as duration string
|
|
272
|
+
if (avgMinutes >= 60) {
|
|
273
|
+
const hours = Math.floor(avgMinutes / 60)
|
|
274
|
+
const mins = avgMinutes % 60
|
|
275
|
+
return mins > 0 ? `${hours}h ${mins}m` : `${hours}h`
|
|
276
|
+
}
|
|
277
|
+
return `${avgMinutes}m`
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
/**
|
|
281
|
+
* Suggest best agent for a task type.
|
|
282
|
+
*/
|
|
283
|
+
async suggestAgent(projectId: string, taskType: string): Promise<string | null> {
|
|
284
|
+
const agentMetrics = await this.getAgentMetrics(projectId)
|
|
285
|
+
|
|
286
|
+
// Find agents good at this task type
|
|
287
|
+
const suitable = agentMetrics.filter((m) => m.bestFor.includes(taskType))
|
|
288
|
+
|
|
289
|
+
if (suitable.length === 0) {
|
|
290
|
+
return null
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
// Return the one with highest success rate
|
|
294
|
+
return suitable.sort((a, b) => b.successRate - a.successRate)[0].agent
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
/**
|
|
298
|
+
* Parse variance string to minutes.
|
|
299
|
+
*/
|
|
300
|
+
private parseVariance(variance: string): number {
|
|
301
|
+
const match = variance.match(/^([+-])(\d+)([mh])$/)
|
|
302
|
+
if (!match) return 0
|
|
303
|
+
|
|
304
|
+
const sign = match[1] === '-' ? -1 : 1
|
|
305
|
+
const value = parseInt(match[2], 10)
|
|
306
|
+
const unit = match[3]
|
|
307
|
+
|
|
308
|
+
return sign * (unit === 'h' ? value * 60 : value)
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
/**
|
|
312
|
+
* Parse duration string to minutes.
|
|
313
|
+
*/
|
|
314
|
+
private parseDuration(duration: string): number {
|
|
315
|
+
let minutes = 0
|
|
316
|
+
|
|
317
|
+
const hourMatch = duration.match(/(\d+)h/)
|
|
318
|
+
if (hourMatch) {
|
|
319
|
+
minutes += parseInt(hourMatch[1], 10) * 60
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
const minMatch = duration.match(/(\d+)m/)
|
|
323
|
+
if (minMatch) {
|
|
324
|
+
minutes += parseInt(minMatch[1], 10)
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
return minutes
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
// Singleton instance
|
|
332
|
+
const outcomeAnalyzer = new OutcomeAnalyzer()
|
|
333
|
+
export default outcomeAnalyzer
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Outcomes Module
|
|
3
|
+
*
|
|
4
|
+
* Records and analyzes execution outcomes for learning.
|
|
5
|
+
*
|
|
6
|
+
* @example
|
|
7
|
+
* ```typescript
|
|
8
|
+
* import { outcomeRecorder, outcomeAnalyzer } from './outcomes'
|
|
9
|
+
*
|
|
10
|
+
* // Record an outcome
|
|
11
|
+
* await outcomeRecorder.record(projectId, {
|
|
12
|
+
* sessionId: 'session_123',
|
|
13
|
+
* command: '/p:now',
|
|
14
|
+
* task: 'implement auth',
|
|
15
|
+
* startedAt: '2025-12-09T14:00:00Z',
|
|
16
|
+
* completedAt: '2025-12-09T16:30:00Z',
|
|
17
|
+
* estimatedDuration: '2h',
|
|
18
|
+
* actualDuration: '2h 30m',
|
|
19
|
+
* variance: '+30m',
|
|
20
|
+
* completedAsPlanned: true,
|
|
21
|
+
* qualityScore: 4,
|
|
22
|
+
* agentUsed: 'backend-specialist',
|
|
23
|
+
* tags: ['auth', 'backend']
|
|
24
|
+
* })
|
|
25
|
+
*
|
|
26
|
+
* // Analyze outcomes
|
|
27
|
+
* const summary = await outcomeAnalyzer.summarize(projectId)
|
|
28
|
+
* const patterns = await outcomeAnalyzer.detectPatterns(projectId)
|
|
29
|
+
* ```
|
|
30
|
+
*/
|
|
31
|
+
|
|
32
|
+
export { OutcomeRecorder, default as outcomeRecorder } from './recorder'
|
|
33
|
+
export { OutcomeAnalyzer, default as outcomeAnalyzer } from './analyzer'
|
|
34
|
+
export * from './types'
|
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Outcome Recorder
|
|
3
|
+
*
|
|
4
|
+
* Records execution outcomes for learning and analysis.
|
|
5
|
+
* Appends to JSONL files for efficient streaming.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import path from 'path'
|
|
9
|
+
import * as fileHelper from '../utils/file-helper'
|
|
10
|
+
import pathManager from '../infrastructure/path-manager'
|
|
11
|
+
import type { Outcome, OutcomeInput, OutcomeFilter } from './types'
|
|
12
|
+
|
|
13
|
+
const OUTCOMES_DIR = 'outcomes'
|
|
14
|
+
const OUTCOMES_FILE = 'outcomes.jsonl'
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* OutcomeRecorder - Records and retrieves execution outcomes.
|
|
18
|
+
*/
|
|
19
|
+
export class OutcomeRecorder {
|
|
20
|
+
/**
|
|
21
|
+
* Get outcomes directory path for a project.
|
|
22
|
+
*/
|
|
23
|
+
private getOutcomesDir(projectId: string): string {
|
|
24
|
+
const globalPath = pathManager.getGlobalProjectPath(projectId)
|
|
25
|
+
return path.join(globalPath, OUTCOMES_DIR)
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Get outcomes file path for a project.
|
|
30
|
+
*/
|
|
31
|
+
private getOutcomesPath(projectId: string): string {
|
|
32
|
+
return path.join(this.getOutcomesDir(projectId), OUTCOMES_FILE)
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Record an outcome.
|
|
37
|
+
*/
|
|
38
|
+
async record(projectId: string, input: OutcomeInput): Promise<Outcome> {
|
|
39
|
+
const outcome: Outcome = {
|
|
40
|
+
...input,
|
|
41
|
+
id: `outcome_${Date.now()}_${Math.random().toString(36).slice(2, 8)}`,
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
const outcomesPath = this.getOutcomesPath(projectId)
|
|
45
|
+
|
|
46
|
+
// Ensure directory exists
|
|
47
|
+
await fileHelper.ensureDir(path.dirname(outcomesPath))
|
|
48
|
+
|
|
49
|
+
// Append to JSONL
|
|
50
|
+
await fileHelper.appendLine(outcomesPath, JSON.stringify(outcome))
|
|
51
|
+
|
|
52
|
+
return outcome
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Get all outcomes for a project.
|
|
57
|
+
*/
|
|
58
|
+
async getAll(projectId: string): Promise<Outcome[]> {
|
|
59
|
+
const outcomesPath = this.getOutcomesPath(projectId)
|
|
60
|
+
|
|
61
|
+
if (!(await fileHelper.fileExists(outcomesPath))) {
|
|
62
|
+
return []
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
const content = await fileHelper.readFile(outcomesPath)
|
|
66
|
+
if (!content.trim()) {
|
|
67
|
+
return []
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
return content
|
|
71
|
+
.trim()
|
|
72
|
+
.split('\n')
|
|
73
|
+
.filter((line) => line.trim())
|
|
74
|
+
.map((line) => JSON.parse(line) as Outcome)
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Get outcomes matching a filter.
|
|
79
|
+
*/
|
|
80
|
+
async filter(projectId: string, filter: OutcomeFilter): Promise<Outcome[]> {
|
|
81
|
+
const all = await this.getAll(projectId)
|
|
82
|
+
|
|
83
|
+
return all.filter((outcome) => {
|
|
84
|
+
if (filter.sessionId && outcome.sessionId !== filter.sessionId) {
|
|
85
|
+
return false
|
|
86
|
+
}
|
|
87
|
+
if (filter.command && outcome.command !== filter.command) {
|
|
88
|
+
return false
|
|
89
|
+
}
|
|
90
|
+
if (filter.agent && outcome.agentUsed !== filter.agent) {
|
|
91
|
+
return false
|
|
92
|
+
}
|
|
93
|
+
if (filter.fromDate && outcome.startedAt < filter.fromDate) {
|
|
94
|
+
return false
|
|
95
|
+
}
|
|
96
|
+
if (filter.toDate && outcome.completedAt > filter.toDate) {
|
|
97
|
+
return false
|
|
98
|
+
}
|
|
99
|
+
if (filter.minQuality && outcome.qualityScore < filter.minQuality) {
|
|
100
|
+
return false
|
|
101
|
+
}
|
|
102
|
+
if (filter.tags && filter.tags.length > 0) {
|
|
103
|
+
const outcomeTags = outcome.tags || []
|
|
104
|
+
if (!filter.tags.some((tag) => outcomeTags.includes(tag))) {
|
|
105
|
+
return false
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
return true
|
|
109
|
+
})
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* Get recent outcomes (last N).
|
|
114
|
+
*/
|
|
115
|
+
async getRecent(projectId: string, count: number = 10): Promise<Outcome[]> {
|
|
116
|
+
const all = await this.getAll(projectId)
|
|
117
|
+
return all.slice(-count)
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* Get outcomes for a specific command.
|
|
122
|
+
*/
|
|
123
|
+
async getByCommand(projectId: string, command: string): Promise<Outcome[]> {
|
|
124
|
+
return this.filter(projectId, { command })
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
/**
|
|
128
|
+
* Get outcomes for a specific agent.
|
|
129
|
+
*/
|
|
130
|
+
async getByAgent(projectId: string, agent: string): Promise<Outcome[]> {
|
|
131
|
+
return this.filter(projectId, { agent })
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* Calculate estimate accuracy.
|
|
136
|
+
*/
|
|
137
|
+
async getEstimateAccuracy(projectId: string): Promise<number> {
|
|
138
|
+
const outcomes = await this.getAll(projectId)
|
|
139
|
+
|
|
140
|
+
if (outcomes.length === 0) {
|
|
141
|
+
return 0
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
// Count outcomes where variance was within 20%
|
|
145
|
+
const accurate = outcomes.filter((o) => {
|
|
146
|
+
if (!o.variance) return false
|
|
147
|
+
const variance = this.parseVariance(o.variance)
|
|
148
|
+
const estimated = this.parseDuration(o.estimatedDuration)
|
|
149
|
+
if (estimated === 0) return false
|
|
150
|
+
return Math.abs(variance) / estimated <= 0.2
|
|
151
|
+
})
|
|
152
|
+
|
|
153
|
+
return Math.round((accurate.length / outcomes.length) * 100)
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
/**
|
|
157
|
+
* Parse variance string to minutes.
|
|
158
|
+
* "+30m" → 30, "-15m" → -15
|
|
159
|
+
*/
|
|
160
|
+
private parseVariance(variance: string): number {
|
|
161
|
+
const match = variance.match(/^([+-])(\d+)([mh])$/)
|
|
162
|
+
if (!match) return 0
|
|
163
|
+
|
|
164
|
+
const sign = match[1] === '-' ? -1 : 1
|
|
165
|
+
const value = parseInt(match[2], 10)
|
|
166
|
+
const unit = match[3]
|
|
167
|
+
|
|
168
|
+
return sign * (unit === 'h' ? value * 60 : value)
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
/**
|
|
172
|
+
* Parse duration string to minutes.
|
|
173
|
+
* "2h" → 120, "30m" → 30, "1h 30m" → 90
|
|
174
|
+
*/
|
|
175
|
+
private parseDuration(duration: string): number {
|
|
176
|
+
let minutes = 0
|
|
177
|
+
|
|
178
|
+
const hourMatch = duration.match(/(\d+)h/)
|
|
179
|
+
if (hourMatch) {
|
|
180
|
+
minutes += parseInt(hourMatch[1], 10) * 60
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
const minMatch = duration.match(/(\d+)m/)
|
|
184
|
+
if (minMatch) {
|
|
185
|
+
minutes += parseInt(minMatch[1], 10)
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
return minutes
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
// Singleton instance
|
|
193
|
+
const outcomeRecorder = new OutcomeRecorder()
|
|
194
|
+
export default outcomeRecorder
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Outcome Types
|
|
3
|
+
*
|
|
4
|
+
* Types for recording execution results.
|
|
5
|
+
* Enables learning from past executions.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Quality score for task completion.
|
|
10
|
+
* 1 = Poor, 5 = Excellent
|
|
11
|
+
*/
|
|
12
|
+
export type QualityScore = 1 | 2 | 3 | 4 | 5
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Outcome of a command or task execution.
|
|
16
|
+
*
|
|
17
|
+
* @property id - Unique outcome ID
|
|
18
|
+
* @property sessionId - Session this outcome belongs to
|
|
19
|
+
* @property command - Command that was executed
|
|
20
|
+
* @property task - Task description
|
|
21
|
+
*/
|
|
22
|
+
export interface Outcome {
|
|
23
|
+
/** Unique outcome ID */
|
|
24
|
+
id: string
|
|
25
|
+
|
|
26
|
+
/** Session this outcome belongs to */
|
|
27
|
+
sessionId: string
|
|
28
|
+
|
|
29
|
+
/** Command that was executed */
|
|
30
|
+
command: string
|
|
31
|
+
|
|
32
|
+
/** Task description */
|
|
33
|
+
task: string
|
|
34
|
+
|
|
35
|
+
// =========== Timing ===========
|
|
36
|
+
|
|
37
|
+
/** When execution started */
|
|
38
|
+
startedAt: string
|
|
39
|
+
|
|
40
|
+
/** When execution completed */
|
|
41
|
+
completedAt: string
|
|
42
|
+
|
|
43
|
+
/** Estimated duration (before execution) */
|
|
44
|
+
estimatedDuration: string
|
|
45
|
+
|
|
46
|
+
/** Actual duration */
|
|
47
|
+
actualDuration: string
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Variance from estimate.
|
|
51
|
+
* Positive = took longer ("+30m")
|
|
52
|
+
* Negative = faster ("-15m")
|
|
53
|
+
*/
|
|
54
|
+
variance: string
|
|
55
|
+
|
|
56
|
+
// =========== Quality ===========
|
|
57
|
+
|
|
58
|
+
/** Whether task was completed as planned */
|
|
59
|
+
completedAsPlanned: boolean
|
|
60
|
+
|
|
61
|
+
/** Quality score (1-5) */
|
|
62
|
+
qualityScore: QualityScore
|
|
63
|
+
|
|
64
|
+
/** Blockers encountered during execution */
|
|
65
|
+
blockers?: string[]
|
|
66
|
+
|
|
67
|
+
/** Error messages if any */
|
|
68
|
+
errors?: string[]
|
|
69
|
+
|
|
70
|
+
// =========== Agent ===========
|
|
71
|
+
|
|
72
|
+
/** Agent used for this task */
|
|
73
|
+
agentUsed?: string
|
|
74
|
+
|
|
75
|
+
/** Agent confidence level (0-1) */
|
|
76
|
+
agentConfidence?: number
|
|
77
|
+
|
|
78
|
+
/** Whether agent performed well */
|
|
79
|
+
agentPerformedWell?: boolean
|
|
80
|
+
|
|
81
|
+
// =========== Learning ===========
|
|
82
|
+
|
|
83
|
+
/** Pattern detected from this execution */
|
|
84
|
+
patternDetected?: string
|
|
85
|
+
|
|
86
|
+
/** Suggested estimate for similar tasks */
|
|
87
|
+
nextTimeEstimate?: string
|
|
88
|
+
|
|
89
|
+
/** Tags for categorization */
|
|
90
|
+
tags?: string[]
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* Summary of outcomes for analysis.
|
|
95
|
+
*/
|
|
96
|
+
export interface OutcomeSummary {
|
|
97
|
+
/** Total outcomes analyzed */
|
|
98
|
+
totalOutcomes: number
|
|
99
|
+
|
|
100
|
+
/** Average quality score */
|
|
101
|
+
avgQualityScore: number
|
|
102
|
+
|
|
103
|
+
/** Estimate accuracy percentage (0-100) */
|
|
104
|
+
estimateAccuracy: number
|
|
105
|
+
|
|
106
|
+
/** Most common blockers */
|
|
107
|
+
topBlockers: string[]
|
|
108
|
+
|
|
109
|
+
/** Best performing agents */
|
|
110
|
+
topAgents: string[]
|
|
111
|
+
|
|
112
|
+
/** Patterns detected */
|
|
113
|
+
patternsDetected: string[]
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* Outcome filter options.
|
|
118
|
+
*/
|
|
119
|
+
export interface OutcomeFilter {
|
|
120
|
+
/** Filter by session ID */
|
|
121
|
+
sessionId?: string
|
|
122
|
+
|
|
123
|
+
/** Filter by command */
|
|
124
|
+
command?: string
|
|
125
|
+
|
|
126
|
+
/** Filter by agent */
|
|
127
|
+
agent?: string
|
|
128
|
+
|
|
129
|
+
/** Filter by date range start */
|
|
130
|
+
fromDate?: string
|
|
131
|
+
|
|
132
|
+
/** Filter by date range end */
|
|
133
|
+
toDate?: string
|
|
134
|
+
|
|
135
|
+
/** Filter by minimum quality */
|
|
136
|
+
minQuality?: QualityScore
|
|
137
|
+
|
|
138
|
+
/** Filter by tags */
|
|
139
|
+
tags?: string[]
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
* Outcome creation input.
|
|
144
|
+
*/
|
|
145
|
+
export type OutcomeInput = Omit<Outcome, 'id'>
|