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,1069 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Prompt Builder
|
|
3
|
-
* Builds prompts for Claude based on templates and context.
|
|
4
|
-
* Claude decides what to do - NO if/else logic here.
|
|
5
|
-
*
|
|
6
|
-
* Auto-injects unified state, learned patterns, and performance stats.
|
|
7
|
-
*
|
|
8
|
-
* @module agentic/prompt-builder
|
|
9
|
-
* @version 5.0
|
|
10
|
-
*/
|
|
11
|
-
|
|
12
|
-
import fs from 'node:fs/promises'
|
|
13
|
-
import path from 'node:path'
|
|
14
|
-
import { outcomeAnalyzer } from '../outcomes'
|
|
15
|
-
import type { CommandContextEntry } from '../schemas/command-context'
|
|
16
|
-
import { queueStorage, stateStorage } from '../storage'
|
|
17
|
-
import type {
|
|
18
|
-
LearnedPatterns,
|
|
19
|
-
Memory,
|
|
20
|
-
OrchestratorContext,
|
|
21
|
-
PlanInfo,
|
|
22
|
-
PromptAgent,
|
|
23
|
-
PromptContext,
|
|
24
|
-
PromptProjectState,
|
|
25
|
-
PromptState,
|
|
26
|
-
Template,
|
|
27
|
-
ThinkBlock,
|
|
28
|
-
} from '../types'
|
|
29
|
-
import { getErrorMessage, isNotFoundError } from '../types/fs'
|
|
30
|
-
import { fileExists } from '../utils/fs-helpers'
|
|
31
|
-
import { PACKAGE_ROOT } from '../utils/version'
|
|
32
|
-
import { buildAntiHallucinationBlock, type ProjectGroundTruth } from './anti-hallucination'
|
|
33
|
-
import { loadCommandContextConfig, resolveCommandContextFull } from './command-context'
|
|
34
|
-
import { buildEnvironmentBlock } from './environment-block'
|
|
35
|
-
import {
|
|
36
|
-
budgetsFromCoordinator,
|
|
37
|
-
DEFAULT_BUDGETS,
|
|
38
|
-
filterSkillsByDomains,
|
|
39
|
-
InjectionBudgetTracker,
|
|
40
|
-
truncateToTokenBudget,
|
|
41
|
-
} from './injection-validator'
|
|
42
|
-
import { deduplicateTechStack } from './tech-normalizer'
|
|
43
|
-
import type { TokenBudgetCoordinator } from './token-budget'
|
|
44
|
-
|
|
45
|
-
// =============================================================================
|
|
46
|
-
// Section Priority (PRJ-301)
|
|
47
|
-
// =============================================================================
|
|
48
|
-
|
|
49
|
-
/**
|
|
50
|
-
* Prompt section priorities for budget trimming.
|
|
51
|
-
* When token budget is tight, optional sections are dropped first.
|
|
52
|
-
*
|
|
53
|
-
* @see PRJ-301
|
|
54
|
-
*/
|
|
55
|
-
export type SectionPriority = 'critical' | 'important' | 'optional'
|
|
56
|
-
|
|
57
|
-
/**
|
|
58
|
-
* Canonical section ordering for prompt assembly.
|
|
59
|
-
* Based on research of 25+ system prompts from Claude Code, Gemini, ChatGPT.
|
|
60
|
-
*
|
|
61
|
-
* @see PRJ-301
|
|
62
|
-
*/
|
|
63
|
-
export const PROMPT_SECTION_ORDER = [
|
|
64
|
-
'identity', // Who the model is (agent + role)
|
|
65
|
-
'environment', // Where: project, git, platform, model
|
|
66
|
-
'ground_truth', // Sealed analysis: ecosystem, stack, patterns
|
|
67
|
-
'capabilities', // Tools, agents, skills, plan mode
|
|
68
|
-
'constraints', // Anti-hallucination rules (BEFORE task context)
|
|
69
|
-
'task_context', // Files, state, memories, learned patterns
|
|
70
|
-
'task', // Template content + subtasks (the actual instructions)
|
|
71
|
-
'output_schema', // Structured response format
|
|
72
|
-
'efficiency', // Token efficiency directive
|
|
73
|
-
] as const
|
|
74
|
-
|
|
75
|
-
// Re-export types for convenience
|
|
76
|
-
export type {
|
|
77
|
-
Frontmatter,
|
|
78
|
-
LearnedPatterns,
|
|
79
|
-
Memory,
|
|
80
|
-
PlanInfo,
|
|
81
|
-
Template,
|
|
82
|
-
ThinkBlock,
|
|
83
|
-
} from '../types'
|
|
84
|
-
|
|
85
|
-
// Local type aliases for backward compatibility
|
|
86
|
-
type ProjectState = PromptProjectState
|
|
87
|
-
type Agent = PromptAgent
|
|
88
|
-
type Context = PromptContext
|
|
89
|
-
type State = PromptState
|
|
90
|
-
|
|
91
|
-
/**
|
|
92
|
-
* Cached template entry with TTL support
|
|
93
|
-
* @see PRJ-76
|
|
94
|
-
*/
|
|
95
|
-
interface CachedTemplate {
|
|
96
|
-
content: string
|
|
97
|
-
loadedAt: number
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
/**
|
|
101
|
-
* Builds prompts for Claude using templates, context, and learned patterns.
|
|
102
|
-
* Supports plan mode, think blocks, and quality checklists.
|
|
103
|
-
* Auto-injects unified state and performance insights.
|
|
104
|
-
*
|
|
105
|
-
* Uses lazy loading for templates with 60s TTL cache.
|
|
106
|
-
* @see PRJ-76
|
|
107
|
-
*/
|
|
108
|
-
class PromptBuilder {
|
|
109
|
-
private _checklistsCache: Record<string, string> | null = null
|
|
110
|
-
private _checklistsCacheTime: number = 0
|
|
111
|
-
private _checklistRoutingCache: string | null = null
|
|
112
|
-
private _checklistRoutingCacheTime: number = 0
|
|
113
|
-
private _currentContext: Context | null = null
|
|
114
|
-
private _stateCache: Map<string, { state: ProjectState; timestamp: number }> = new Map()
|
|
115
|
-
private _stateCacheTTL = 5000 // 5 seconds
|
|
116
|
-
private _templateCache: Map<string, CachedTemplate> = new Map()
|
|
117
|
-
private readonly TEMPLATE_CACHE_TTL_MS = 60_000 // 60 seconds
|
|
118
|
-
|
|
119
|
-
/** Active token budget coordinator (PRJ-266) */
|
|
120
|
-
private _coordinator: TokenBudgetCoordinator | null = null
|
|
121
|
-
|
|
122
|
-
/**
|
|
123
|
-
* Get a template with TTL caching.
|
|
124
|
-
* Returns cached content if within TTL, otherwise loads from disk.
|
|
125
|
-
* @see PRJ-76
|
|
126
|
-
*/
|
|
127
|
-
async getTemplate(templatePath: string): Promise<string | null> {
|
|
128
|
-
const cached = this._templateCache.get(templatePath)
|
|
129
|
-
const now = Date.now()
|
|
130
|
-
|
|
131
|
-
if (cached && now - cached.loadedAt < this.TEMPLATE_CACHE_TTL_MS) {
|
|
132
|
-
return cached.content
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
try {
|
|
136
|
-
if (await fileExists(templatePath)) {
|
|
137
|
-
const content = await fs.readFile(templatePath, 'utf-8')
|
|
138
|
-
this._templateCache.set(templatePath, { content, loadedAt: now })
|
|
139
|
-
return content
|
|
140
|
-
}
|
|
141
|
-
} catch (error) {
|
|
142
|
-
if (!isNotFoundError(error)) {
|
|
143
|
-
console.error(`Template loading warning: ${getErrorMessage(error)}`)
|
|
144
|
-
}
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
return null
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
/**
|
|
151
|
-
* Clear the template cache (for testing or forced refresh)
|
|
152
|
-
* @see PRJ-76
|
|
153
|
-
*/
|
|
154
|
-
clearTemplateCache(): void {
|
|
155
|
-
this._templateCache.clear()
|
|
156
|
-
this._checklistsCache = null
|
|
157
|
-
this._checklistsCacheTime = 0
|
|
158
|
-
this._checklistRoutingCache = null
|
|
159
|
-
this._checklistRoutingCacheTime = 0
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
/**
|
|
163
|
-
* Set the token budget coordinator for model-aware budget management.
|
|
164
|
-
* When set, budget allocations flow from the coordinator instead of defaults.
|
|
165
|
-
*
|
|
166
|
-
* @see PRJ-266
|
|
167
|
-
*/
|
|
168
|
-
setCoordinator(coordinator: TokenBudgetCoordinator | null): void {
|
|
169
|
-
this._coordinator = coordinator
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
/** Get the active coordinator (may be null) */
|
|
173
|
-
getCoordinator(): TokenBudgetCoordinator | null {
|
|
174
|
-
return this._coordinator
|
|
175
|
-
}
|
|
176
|
-
|
|
177
|
-
/**
|
|
178
|
-
* Get effective injection budgets.
|
|
179
|
-
* Uses coordinator allocation when available, falls back to DEFAULT_BUDGETS.
|
|
180
|
-
*
|
|
181
|
-
* @see PRJ-266
|
|
182
|
-
*/
|
|
183
|
-
private getEffectiveBudgets() {
|
|
184
|
-
if (this._coordinator) {
|
|
185
|
-
return budgetsFromCoordinator(this._coordinator)
|
|
186
|
-
}
|
|
187
|
-
return DEFAULT_BUDGETS
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
/**
|
|
191
|
-
* Reset context (for testing)
|
|
192
|
-
*/
|
|
193
|
-
resetContext(): void {
|
|
194
|
-
this._currentContext = null
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
/**
|
|
198
|
-
* Set context for testing
|
|
199
|
-
*/
|
|
200
|
-
setContext(context: Context | null): void {
|
|
201
|
-
this._currentContext = context
|
|
202
|
-
}
|
|
203
|
-
|
|
204
|
-
/**
|
|
205
|
-
* Load a specific CLAUDE module for SMART commands (PRJ-94)
|
|
206
|
-
* These modules extend the base global CLAUDE.md for complex operations
|
|
207
|
-
*/
|
|
208
|
-
async loadModule(moduleName: string): Promise<string | null> {
|
|
209
|
-
const modulePath = path.join(PACKAGE_ROOT, 'templates/global/modules', moduleName)
|
|
210
|
-
return this.getTemplate(modulePath)
|
|
211
|
-
}
|
|
212
|
-
|
|
213
|
-
/**
|
|
214
|
-
* Get additional modules needed for SMART commands (PRJ-94)
|
|
215
|
-
* Now config-driven via command-context.config.json (PRJ-298)
|
|
216
|
-
*/
|
|
217
|
-
getModulesForCommand(_commandName: string, commandContext?: CommandContextEntry): string[] {
|
|
218
|
-
if (commandContext) {
|
|
219
|
-
return commandContext.modules
|
|
220
|
-
}
|
|
221
|
-
// Fallback if called without config (shouldn't happen after PRJ-298)
|
|
222
|
-
return []
|
|
223
|
-
}
|
|
224
|
-
|
|
225
|
-
/**
|
|
226
|
-
* Load quality checklists from templates/checklists/
|
|
227
|
-
* Uses lazy loading with TTL cache.
|
|
228
|
-
* @see PRJ-76
|
|
229
|
-
*/
|
|
230
|
-
async loadChecklists(): Promise<Record<string, string>> {
|
|
231
|
-
const now = Date.now()
|
|
232
|
-
|
|
233
|
-
// Check if cache is still valid
|
|
234
|
-
if (this._checklistsCache && now - this._checklistsCacheTime < this.TEMPLATE_CACHE_TTL_MS) {
|
|
235
|
-
return this._checklistsCache
|
|
236
|
-
}
|
|
237
|
-
|
|
238
|
-
const checklistsDir = path.join(__dirname, '..', '..', 'templates', 'checklists')
|
|
239
|
-
const checklists: Record<string, string> = {}
|
|
240
|
-
|
|
241
|
-
try {
|
|
242
|
-
if (await fileExists(checklistsDir)) {
|
|
243
|
-
const files = (await fs.readdir(checklistsDir)).filter((f: string) => f.endsWith('.md'))
|
|
244
|
-
for (const file of files) {
|
|
245
|
-
const name = file.replace('.md', '')
|
|
246
|
-
const templatePath = path.join(checklistsDir, file)
|
|
247
|
-
// Use getTemplate for individual files to leverage per-file caching
|
|
248
|
-
const content = await this.getTemplate(templatePath)
|
|
249
|
-
if (content) {
|
|
250
|
-
checklists[name] = content
|
|
251
|
-
}
|
|
252
|
-
}
|
|
253
|
-
}
|
|
254
|
-
} catch (error) {
|
|
255
|
-
// Silent fail - checklists are optional enhancement
|
|
256
|
-
if (!isNotFoundError(error)) {
|
|
257
|
-
console.error(`Checklist loading warning: ${getErrorMessage(error)}`)
|
|
258
|
-
}
|
|
259
|
-
}
|
|
260
|
-
|
|
261
|
-
this._checklistsCache = checklists
|
|
262
|
-
this._checklistsCacheTime = now
|
|
263
|
-
return checklists
|
|
264
|
-
}
|
|
265
|
-
|
|
266
|
-
/**
|
|
267
|
-
* Get unified project state from MD managers.
|
|
268
|
-
*/
|
|
269
|
-
async getProjectState(projectId: string): Promise<ProjectState | null> {
|
|
270
|
-
if (!projectId) return null
|
|
271
|
-
|
|
272
|
-
const cached = this._stateCache.get(projectId)
|
|
273
|
-
if (cached && Date.now() - cached.timestamp < this._stateCacheTTL) {
|
|
274
|
-
return cached.state
|
|
275
|
-
}
|
|
276
|
-
|
|
277
|
-
try {
|
|
278
|
-
const [stateData, queueData] = await Promise.all([
|
|
279
|
-
stateStorage.read(projectId),
|
|
280
|
-
queueStorage.read(projectId),
|
|
281
|
-
])
|
|
282
|
-
|
|
283
|
-
const state: ProjectState = {
|
|
284
|
-
projectId,
|
|
285
|
-
currentTask: stateData.currentTask,
|
|
286
|
-
queue: queueData.tasks,
|
|
287
|
-
}
|
|
288
|
-
|
|
289
|
-
this._stateCache.set(projectId, { state, timestamp: Date.now() })
|
|
290
|
-
return state
|
|
291
|
-
} catch (error) {
|
|
292
|
-
if (isNotFoundError(error) || error instanceof SyntaxError) {
|
|
293
|
-
return null
|
|
294
|
-
}
|
|
295
|
-
throw error
|
|
296
|
-
}
|
|
297
|
-
}
|
|
298
|
-
|
|
299
|
-
/**
|
|
300
|
-
* Build auto-injected context from MD state.
|
|
301
|
-
* This is automatically added to every prompt.
|
|
302
|
-
*/
|
|
303
|
-
async buildInjectedContext(projectId: string): Promise<string | null> {
|
|
304
|
-
if (!projectId) return null
|
|
305
|
-
|
|
306
|
-
const state = await this.getProjectState(projectId)
|
|
307
|
-
if (!state) return null
|
|
308
|
-
|
|
309
|
-
const parts: string[] = []
|
|
310
|
-
|
|
311
|
-
// Current state
|
|
312
|
-
parts.push('## AUTO-INJECTED CONTEXT')
|
|
313
|
-
parts.push('')
|
|
314
|
-
|
|
315
|
-
// Current task
|
|
316
|
-
if (state.currentTask) {
|
|
317
|
-
const elapsed = this.calculateElapsed(state.currentTask.startedAt)
|
|
318
|
-
parts.push(`**Current Task**: ${state.currentTask.description}`)
|
|
319
|
-
parts.push(`- Started: ${elapsed} ago`)
|
|
320
|
-
} else {
|
|
321
|
-
parts.push('**Current Task**: None')
|
|
322
|
-
}
|
|
323
|
-
parts.push('')
|
|
324
|
-
|
|
325
|
-
// Queue summary
|
|
326
|
-
if (state.queue.length > 0) {
|
|
327
|
-
parts.push(`**Queue**: ${state.queue.length} tasks pending`)
|
|
328
|
-
const top3 = state.queue.slice(0, 3)
|
|
329
|
-
for (const task of top3) {
|
|
330
|
-
parts.push(`- [${task.priority}] ${task.description}`)
|
|
331
|
-
}
|
|
332
|
-
if (state.queue.length > 3) {
|
|
333
|
-
parts.push(`- ... and ${state.queue.length - 3} more`)
|
|
334
|
-
}
|
|
335
|
-
}
|
|
336
|
-
parts.push('')
|
|
337
|
-
|
|
338
|
-
// Get detected patterns from outcomes
|
|
339
|
-
try {
|
|
340
|
-
const patterns = await outcomeAnalyzer.detectPatterns(projectId)
|
|
341
|
-
if (patterns.length > 0) {
|
|
342
|
-
parts.push('**Project Conventions**')
|
|
343
|
-
for (const pattern of patterns.slice(0, 3)) {
|
|
344
|
-
parts.push(`- ${pattern.description}`)
|
|
345
|
-
if (pattern.suggestedAction) {
|
|
346
|
-
parts.push(` → ${pattern.suggestedAction}`)
|
|
347
|
-
}
|
|
348
|
-
}
|
|
349
|
-
parts.push('')
|
|
350
|
-
}
|
|
351
|
-
} catch (error) {
|
|
352
|
-
// Outcomes not available yet - expected for new projects
|
|
353
|
-
if (!isNotFoundError(error) && !(error instanceof SyntaxError)) {
|
|
354
|
-
console.error(`Outcome detection warning: ${getErrorMessage(error)}`)
|
|
355
|
-
}
|
|
356
|
-
}
|
|
357
|
-
|
|
358
|
-
parts.push('---')
|
|
359
|
-
parts.push('')
|
|
360
|
-
|
|
361
|
-
const result = parts.join('\n')
|
|
362
|
-
return truncateToTokenBudget(result, this.getEffectiveBudgets().autoContext)
|
|
363
|
-
}
|
|
364
|
-
|
|
365
|
-
/**
|
|
366
|
-
* Calculate elapsed time from ISO timestamp.
|
|
367
|
-
*/
|
|
368
|
-
private calculateElapsed(isoTimestamp: string): string {
|
|
369
|
-
const start = new Date(isoTimestamp).getTime()
|
|
370
|
-
const now = Date.now()
|
|
371
|
-
const diffMs = now - start
|
|
372
|
-
|
|
373
|
-
const minutes = Math.floor(diffMs / 60000)
|
|
374
|
-
const hours = Math.floor(minutes / 60)
|
|
375
|
-
const days = Math.floor(hours / 24)
|
|
376
|
-
|
|
377
|
-
if (days > 0) return `${days}d ${hours % 24}h`
|
|
378
|
-
if (hours > 0) return `${hours}h ${minutes % 60}m`
|
|
379
|
-
return `${minutes}m`
|
|
380
|
-
}
|
|
381
|
-
|
|
382
|
-
/**
|
|
383
|
-
* Load checklist routing template for Claude to decide which checklists apply
|
|
384
|
-
* Uses lazy loading with TTL cache.
|
|
385
|
-
* @see PRJ-76
|
|
386
|
-
*/
|
|
387
|
-
async loadChecklistRouting(): Promise<string | null> {
|
|
388
|
-
const now = Date.now()
|
|
389
|
-
|
|
390
|
-
// Check if cache is still valid
|
|
391
|
-
if (
|
|
392
|
-
this._checklistRoutingCache &&
|
|
393
|
-
now - this._checklistRoutingCacheTime < this.TEMPLATE_CACHE_TTL_MS
|
|
394
|
-
) {
|
|
395
|
-
return this._checklistRoutingCache
|
|
396
|
-
}
|
|
397
|
-
|
|
398
|
-
const routingPath = path.join(
|
|
399
|
-
__dirname,
|
|
400
|
-
'..',
|
|
401
|
-
'..',
|
|
402
|
-
'templates',
|
|
403
|
-
'agentic',
|
|
404
|
-
'checklist-routing.md'
|
|
405
|
-
)
|
|
406
|
-
|
|
407
|
-
// Use getTemplate for consistent caching behavior
|
|
408
|
-
const content = await this.getTemplate(routingPath)
|
|
409
|
-
if (content) {
|
|
410
|
-
this._checklistRoutingCache = content
|
|
411
|
-
this._checklistRoutingCacheTime = now
|
|
412
|
-
}
|
|
413
|
-
|
|
414
|
-
return this._checklistRoutingCache || null
|
|
415
|
-
}
|
|
416
|
-
|
|
417
|
-
/**
|
|
418
|
-
* Build a complete prompt with auto-injected context.
|
|
419
|
-
* This is the preferred method - automatically includes state and insights.
|
|
420
|
-
*/
|
|
421
|
-
async buildWithInjection(
|
|
422
|
-
template: Template,
|
|
423
|
-
context: Context & { projectId?: string },
|
|
424
|
-
state: State,
|
|
425
|
-
agent: Agent | null = null,
|
|
426
|
-
learnedPatterns: LearnedPatterns | null = null,
|
|
427
|
-
thinkBlock: ThinkBlock | null = null,
|
|
428
|
-
relevantMemories: Memory[] | null = null,
|
|
429
|
-
planInfo: PlanInfo | null = null
|
|
430
|
-
): Promise<string> {
|
|
431
|
-
const parts: string[] = []
|
|
432
|
-
|
|
433
|
-
// Auto-inject unified context first
|
|
434
|
-
if (context.projectId) {
|
|
435
|
-
const injected = await this.buildInjectedContext(context.projectId)
|
|
436
|
-
if (injected) {
|
|
437
|
-
parts.push(injected)
|
|
438
|
-
}
|
|
439
|
-
}
|
|
440
|
-
|
|
441
|
-
// Build the rest using existing method
|
|
442
|
-
const basePrompt = await this.build(
|
|
443
|
-
template,
|
|
444
|
-
context,
|
|
445
|
-
state,
|
|
446
|
-
agent,
|
|
447
|
-
learnedPatterns,
|
|
448
|
-
thinkBlock,
|
|
449
|
-
relevantMemories,
|
|
450
|
-
planInfo
|
|
451
|
-
)
|
|
452
|
-
|
|
453
|
-
parts.push(basePrompt)
|
|
454
|
-
|
|
455
|
-
return parts.join('')
|
|
456
|
-
}
|
|
457
|
-
|
|
458
|
-
/**
|
|
459
|
-
* Build a complete prompt for Claude from template, context, and enhancements.
|
|
460
|
-
*
|
|
461
|
-
* Section ordering follows research-backed pattern (PRJ-301):
|
|
462
|
-
* Identity → Environment → Ground Truth → Capabilities → Constraints →
|
|
463
|
-
* Task Context → Task → Output Schema → Efficiency
|
|
464
|
-
*
|
|
465
|
-
* @deprecated Use buildWithInjection for auto-injected context
|
|
466
|
-
*/
|
|
467
|
-
async build(
|
|
468
|
-
template: Template,
|
|
469
|
-
context: Context,
|
|
470
|
-
state: State,
|
|
471
|
-
agent: Agent | null = null,
|
|
472
|
-
learnedPatterns: LearnedPatterns | null = null,
|
|
473
|
-
thinkBlock: ThinkBlock | null = null,
|
|
474
|
-
relevantMemories: Memory[] | null = null,
|
|
475
|
-
planInfo: PlanInfo | null = null,
|
|
476
|
-
orchestratorContext: OrchestratorContext | null = null
|
|
477
|
-
): Promise<string> {
|
|
478
|
-
const parts: string[] = []
|
|
479
|
-
|
|
480
|
-
// Store context for use in helper methods
|
|
481
|
-
this._currentContext = context
|
|
482
|
-
|
|
483
|
-
// PRJ-298: Config-driven command context (replaces 4 hardcoded lists)
|
|
484
|
-
const commandName = template.frontmatter?.name?.replace('p:', '') || ''
|
|
485
|
-
let commandContext: CommandContextEntry
|
|
486
|
-
try {
|
|
487
|
-
const config = await loadCommandContextConfig()
|
|
488
|
-
const resolved = resolveCommandContextFull(config, commandName, template)
|
|
489
|
-
commandContext = resolved.entry
|
|
490
|
-
} catch {
|
|
491
|
-
// Fallback: sensible defaults if config fails to load
|
|
492
|
-
commandContext = { agents: true, patterns: true, checklist: false, modules: [] }
|
|
493
|
-
}
|
|
494
|
-
|
|
495
|
-
// =========================================================================
|
|
496
|
-
// SECTION 1: IDENTITY (critical)
|
|
497
|
-
// Tell the LLM what it is before anything else.
|
|
498
|
-
// =========================================================================
|
|
499
|
-
|
|
500
|
-
const needsAgent = commandContext.agents
|
|
501
|
-
|
|
502
|
-
if (agent && needsAgent) {
|
|
503
|
-
parts.push(`# AGENT: ${agent.name}\n`)
|
|
504
|
-
if (agent.role) parts.push(`Role: ${agent.role}\n`)
|
|
505
|
-
if (agent.skills?.length) parts.push(`Skills: ${agent.skills.join(', ')}\n`)
|
|
506
|
-
parts.push(`\nApply specialized expertise. Read agent file for details if needed.\n\n`)
|
|
507
|
-
}
|
|
508
|
-
|
|
509
|
-
parts.push(`TASK: ${template.frontmatter.description}\n`)
|
|
510
|
-
|
|
511
|
-
if (template.frontmatter['allowed-tools']) {
|
|
512
|
-
parts.push(`TOOLS: ${template.frontmatter['allowed-tools'].join(', ')}\n`)
|
|
513
|
-
}
|
|
514
|
-
|
|
515
|
-
const params = context as { params?: { task?: string; description?: string } }
|
|
516
|
-
if (params.params?.task || params.params?.description) {
|
|
517
|
-
parts.push(`INPUT: ${params.params.task || params.params.description}\n`)
|
|
518
|
-
}
|
|
519
|
-
|
|
520
|
-
// =========================================================================
|
|
521
|
-
// SECTION 2: ENVIRONMENT (important)
|
|
522
|
-
// Structured env block: project, git, platform, model.
|
|
523
|
-
// =========================================================================
|
|
524
|
-
|
|
525
|
-
const projectPath = (context as { projectPath?: string }).projectPath
|
|
526
|
-
if (projectPath) {
|
|
527
|
-
const projectName = orchestratorContext?.project?.id
|
|
528
|
-
? path.basename(projectPath)
|
|
529
|
-
: path.basename(projectPath)
|
|
530
|
-
const envBlock = buildEnvironmentBlock({
|
|
531
|
-
projectName,
|
|
532
|
-
projectPath,
|
|
533
|
-
isGitRepo: true,
|
|
534
|
-
gitBranch: orchestratorContext?.realContext?.gitBranch,
|
|
535
|
-
})
|
|
536
|
-
parts.push(`\n${envBlock}\n`)
|
|
537
|
-
}
|
|
538
|
-
|
|
539
|
-
// =========================================================================
|
|
540
|
-
// SECTION 3: GROUND TRUTH (important)
|
|
541
|
-
// Sealed analysis: ecosystem, domains, stack, code patterns.
|
|
542
|
-
// LLM knows the project reality before seeing task context.
|
|
543
|
-
// =========================================================================
|
|
544
|
-
|
|
545
|
-
if (orchestratorContext) {
|
|
546
|
-
const sa = orchestratorContext.sealedAnalysis
|
|
547
|
-
parts.push('\n## PROJECT ANALYSIS (Sealed)\n')
|
|
548
|
-
parts.push(`**Ecosystem**: ${orchestratorContext.project.ecosystem}\n`)
|
|
549
|
-
parts.push(`**Primary Domain**: ${orchestratorContext.primaryDomain}\n`)
|
|
550
|
-
parts.push(`**Domains**: ${orchestratorContext.detectedDomains.join(', ')}\n`)
|
|
551
|
-
|
|
552
|
-
// Inject sealed analysis data (PRJ-260)
|
|
553
|
-
if (sa) {
|
|
554
|
-
if (sa.languages.length > 0) {
|
|
555
|
-
parts.push(`**Languages**: ${sa.languages.join(', ')}\n`)
|
|
556
|
-
}
|
|
557
|
-
if (sa.frameworks.length > 0) {
|
|
558
|
-
parts.push(`**Frameworks**: ${sa.frameworks.join(', ')}\n`)
|
|
559
|
-
}
|
|
560
|
-
if (sa.packageManager) {
|
|
561
|
-
parts.push(`**Package Manager**: ${sa.packageManager}\n`)
|
|
562
|
-
}
|
|
563
|
-
if (sa.sourceDir) {
|
|
564
|
-
parts.push(`**Source Dir**: ${sa.sourceDir}\n`)
|
|
565
|
-
}
|
|
566
|
-
if (sa.testDir) {
|
|
567
|
-
parts.push(`**Test Dir**: ${sa.testDir}\n`)
|
|
568
|
-
}
|
|
569
|
-
parts.push(`**Files Analyzed**: ${sa.fileCount}\n`)
|
|
570
|
-
parts.push(
|
|
571
|
-
`**Analysis Status**: ${sa.status}${sa.commitHash ? ` (commit: ${sa.commitHash.slice(0, 8)})` : ''}\n`
|
|
572
|
-
)
|
|
573
|
-
|
|
574
|
-
if (sa.patterns.length > 0) {
|
|
575
|
-
parts.push('\n### Code Patterns (Follow These)\n')
|
|
576
|
-
for (const p of sa.patterns) {
|
|
577
|
-
parts.push(`- **${p.name}**: ${p.description}${p.location ? ` (${p.location})` : ''}\n`)
|
|
578
|
-
}
|
|
579
|
-
}
|
|
580
|
-
|
|
581
|
-
if (sa.antiPatterns.length > 0) {
|
|
582
|
-
parts.push('\n### Anti-Patterns (Avoid These)\n')
|
|
583
|
-
for (const ap of sa.antiPatterns) {
|
|
584
|
-
parts.push(`- **${ap.issue}** in \`${ap.file}\` — ${ap.suggestion}\n`)
|
|
585
|
-
}
|
|
586
|
-
}
|
|
587
|
-
}
|
|
588
|
-
|
|
589
|
-
parts.push('\n')
|
|
590
|
-
}
|
|
591
|
-
|
|
592
|
-
const needsPatterns = commandContext.patterns
|
|
593
|
-
const codePatternsContent = state?.codePatterns || ''
|
|
594
|
-
if (needsPatterns && codePatternsContent && codePatternsContent.trim()) {
|
|
595
|
-
const patternSummary = this.extractPatternSummary(codePatternsContent)
|
|
596
|
-
if (patternSummary) {
|
|
597
|
-
parts.push('## CODE PATTERNS\n')
|
|
598
|
-
parts.push(patternSummary)
|
|
599
|
-
parts.push('\nFull patterns: Read analysis/patterns.md\n')
|
|
600
|
-
}
|
|
601
|
-
}
|
|
602
|
-
|
|
603
|
-
const analysisContent = state?.analysis || ''
|
|
604
|
-
if (needsPatterns && analysisContent && analysisContent.trim()) {
|
|
605
|
-
const stackMatch =
|
|
606
|
-
analysisContent.match(/Stack[:\s]+([^\n]+)/i) ||
|
|
607
|
-
analysisContent.match(/Technology[:\s]+([^\n]+)/i)
|
|
608
|
-
const stack = stackMatch ? stackMatch[1].trim() : 'detected'
|
|
609
|
-
|
|
610
|
-
parts.push(`\n## STACK\nStack: ${stack}\n`)
|
|
611
|
-
if (!codePatternsContent) {
|
|
612
|
-
parts.push(
|
|
613
|
-
'Read analysis/repo-summary.md + similar files before coding. Match patterns exactly.\n'
|
|
614
|
-
)
|
|
615
|
-
}
|
|
616
|
-
}
|
|
617
|
-
|
|
618
|
-
// =========================================================================
|
|
619
|
-
// SECTION 4: CAPABILITIES (important)
|
|
620
|
-
// Available agents, skills, modules, plan mode.
|
|
621
|
-
// =========================================================================
|
|
622
|
-
|
|
623
|
-
if (orchestratorContext) {
|
|
624
|
-
// Loaded agents
|
|
625
|
-
if (orchestratorContext.agents.length > 0) {
|
|
626
|
-
parts.push('\n### LOADED AGENTS (Project-Specific Specialists)\n\n')
|
|
627
|
-
for (const orcAgent of orchestratorContext.agents) {
|
|
628
|
-
parts.push(`#### Agent: ${orcAgent.name} (${orcAgent.domain})\n`)
|
|
629
|
-
if (orcAgent.effort) parts.push(`Effort: ${orcAgent.effort}\n`)
|
|
630
|
-
if (orcAgent.model) parts.push(`Model: ${orcAgent.model}\n`)
|
|
631
|
-
if (orcAgent.skills.length > 0) {
|
|
632
|
-
parts.push(`Skills: ${orcAgent.skills.join(', ')}\n`)
|
|
633
|
-
}
|
|
634
|
-
const truncatedContent = truncateToTokenBudget(
|
|
635
|
-
orcAgent.content,
|
|
636
|
-
this.getEffectiveBudgets().agentContent
|
|
637
|
-
)
|
|
638
|
-
parts.push(`\`\`\`markdown\n${truncatedContent}\n\`\`\`\n\n`)
|
|
639
|
-
}
|
|
640
|
-
}
|
|
641
|
-
|
|
642
|
-
// Loaded skills (filtered by domain)
|
|
643
|
-
const relevantSkills = filterSkillsByDomains(
|
|
644
|
-
orchestratorContext.skills,
|
|
645
|
-
orchestratorContext.detectedDomains
|
|
646
|
-
)
|
|
647
|
-
if (relevantSkills.length > 0) {
|
|
648
|
-
parts.push('### LOADED SKILLS (From Agent Frontmatter)\n\n')
|
|
649
|
-
for (const skill of relevantSkills) {
|
|
650
|
-
parts.push(`#### Skill: ${skill.name}\n`)
|
|
651
|
-
const truncatedContent = truncateToTokenBudget(
|
|
652
|
-
skill.content,
|
|
653
|
-
this.getEffectiveBudgets().skillContent
|
|
654
|
-
)
|
|
655
|
-
parts.push(`\`\`\`markdown\n${truncatedContent}\n\`\`\`\n\n`)
|
|
656
|
-
}
|
|
657
|
-
}
|
|
658
|
-
}
|
|
659
|
-
|
|
660
|
-
// Additional modules for SMART commands (PRJ-94/PRJ-298)
|
|
661
|
-
const additionalModules = this.getModulesForCommand(commandName, commandContext)
|
|
662
|
-
if (additionalModules.length > 0) {
|
|
663
|
-
for (const moduleName of additionalModules) {
|
|
664
|
-
const moduleContent = await this.loadModule(moduleName)
|
|
665
|
-
if (moduleContent) {
|
|
666
|
-
parts.push('\n')
|
|
667
|
-
parts.push(moduleContent)
|
|
668
|
-
}
|
|
669
|
-
}
|
|
670
|
-
}
|
|
671
|
-
|
|
672
|
-
// Plan mode / approval
|
|
673
|
-
if (planInfo?.isPlanning) {
|
|
674
|
-
parts.push(
|
|
675
|
-
`\n## PLAN MODE\nRead-only. Gather info → Analyze → Propose plan → Wait for approval.\n`
|
|
676
|
-
)
|
|
677
|
-
if (planInfo.allowedTools) parts.push(`Tools: ${planInfo.allowedTools.join(', ')}\n`)
|
|
678
|
-
}
|
|
679
|
-
if (planInfo?.requiresApproval) {
|
|
680
|
-
parts.push(
|
|
681
|
-
`\n## APPROVAL REQUIRED\nShow changes, list affected files, ask for confirmation.\n`
|
|
682
|
-
)
|
|
683
|
-
}
|
|
684
|
-
|
|
685
|
-
// =========================================================================
|
|
686
|
-
// SECTION 5: CONSTRAINTS (critical)
|
|
687
|
-
// Anti-hallucination rules BEFORE task context.
|
|
688
|
-
// LLM has constraints loaded before processing code/files.
|
|
689
|
-
// =========================================================================
|
|
690
|
-
|
|
691
|
-
if (projectPath) {
|
|
692
|
-
const sa = orchestratorContext?.sealedAnalysis
|
|
693
|
-
// PRJ-300: prefer sealed analysis frameworks as primary tech stack,
|
|
694
|
-
// falling back to repo conventions. Deduplicate with normalized matching.
|
|
695
|
-
const rawStack = [
|
|
696
|
-
...(sa?.frameworks || []),
|
|
697
|
-
...(orchestratorContext?.project?.conventions || []),
|
|
698
|
-
]
|
|
699
|
-
const groundTruth: ProjectGroundTruth = {
|
|
700
|
-
projectPath,
|
|
701
|
-
language: orchestratorContext?.project?.ecosystem,
|
|
702
|
-
framework: sa?.frameworks?.[0],
|
|
703
|
-
techStack: deduplicateTechStack(rawStack),
|
|
704
|
-
domains: this.extractDomains(state),
|
|
705
|
-
fileCount: context.files?.length || context.filteredSize || 0,
|
|
706
|
-
availableAgents: orchestratorContext?.agents?.map((a) => a.name) || [],
|
|
707
|
-
// Inject sealed analysis data for enriched grounding (PRJ-260)
|
|
708
|
-
analysisLanguages: sa?.languages || [],
|
|
709
|
-
analysisFrameworks: sa?.frameworks || [],
|
|
710
|
-
analysisPackageManager: sa?.packageManager,
|
|
711
|
-
}
|
|
712
|
-
parts.push(`\n${buildAntiHallucinationBlock(groundTruth)}\n`)
|
|
713
|
-
} else {
|
|
714
|
-
// Fallback: compressed rules when no project context available
|
|
715
|
-
parts.push(this.buildCriticalRules())
|
|
716
|
-
}
|
|
717
|
-
|
|
718
|
-
// =========================================================================
|
|
719
|
-
// SECTION 6: TASK CONTEXT (important)
|
|
720
|
-
// Files, codebase context, state, memories, patterns — all the data
|
|
721
|
-
// the LLM needs to work with, presented after it knows the rules.
|
|
722
|
-
// =========================================================================
|
|
723
|
-
|
|
724
|
-
// Codebase context (proactively gathered)
|
|
725
|
-
if (orchestratorContext?.realContext) {
|
|
726
|
-
const rc = orchestratorContext.realContext
|
|
727
|
-
parts.push('\n### CODEBASE CONTEXT\n\n')
|
|
728
|
-
|
|
729
|
-
parts.push(`**Git State**: Branch \`${rc.gitBranch}\` | ${rc.gitStatus}\n\n`)
|
|
730
|
-
|
|
731
|
-
if (rc.relevantFiles.length > 0) {
|
|
732
|
-
parts.push('**Relevant Files** (scored by task relevance):\n')
|
|
733
|
-
parts.push('| Score | File | Why |\n')
|
|
734
|
-
parts.push('|-------|------|-----|\n')
|
|
735
|
-
for (const f of rc.relevantFiles.slice(0, 8)) {
|
|
736
|
-
parts.push(`| ${f.score} | ${f.path} | ${f.reason} |\n`)
|
|
737
|
-
}
|
|
738
|
-
parts.push('\n')
|
|
739
|
-
}
|
|
740
|
-
|
|
741
|
-
if (rc.signatures.length > 0) {
|
|
742
|
-
parts.push('**Code Signatures** (top files):\n')
|
|
743
|
-
for (const sig of rc.signatures) {
|
|
744
|
-
parts.push(`\`\`\`typescript\n// ${sig.path}\n${sig.content}\n\`\`\`\n`)
|
|
745
|
-
}
|
|
746
|
-
parts.push('\n')
|
|
747
|
-
}
|
|
748
|
-
|
|
749
|
-
if (rc.recentFiles.length > 0) {
|
|
750
|
-
parts.push('**Recently Changed**: ')
|
|
751
|
-
const recentSummary = rc.recentFiles
|
|
752
|
-
.slice(0, 5)
|
|
753
|
-
.map((f) => `${f.path} (${f.lastChanged})`)
|
|
754
|
-
.join(', ')
|
|
755
|
-
parts.push(`${recentSummary}\n\n`)
|
|
756
|
-
}
|
|
757
|
-
}
|
|
758
|
-
|
|
759
|
-
// File list
|
|
760
|
-
const files = context.files || []
|
|
761
|
-
if (files.length > 0) {
|
|
762
|
-
const top5 = files.slice(0, 5).join(', ')
|
|
763
|
-
parts.push(`\n## FILES: ${files.length} available. Top: ${top5}\n`)
|
|
764
|
-
parts.push('Read BEFORE modifying. Use Glob/Grep to find more.\n\n')
|
|
765
|
-
} else if (projectPath) {
|
|
766
|
-
parts.push(`\n## PROJECT: ${projectPath}\nRead files before modifying.\n\n`)
|
|
767
|
-
}
|
|
768
|
-
|
|
769
|
-
// Project state
|
|
770
|
-
const relevantState = this.filterRelevantState(state)
|
|
771
|
-
if (relevantState) {
|
|
772
|
-
parts.push('\n## PRJCT STATE (Project Management Data)\n')
|
|
773
|
-
parts.push(relevantState)
|
|
774
|
-
parts.push('\n')
|
|
775
|
-
}
|
|
776
|
-
|
|
777
|
-
// Velocity context (PRJ-296) — estimation guidance from historical data
|
|
778
|
-
if (orchestratorContext?.velocityContext) {
|
|
779
|
-
parts.push('\n### VELOCITY (Historical Estimation Data)\n\n')
|
|
780
|
-
parts.push(orchestratorContext.velocityContext)
|
|
781
|
-
parts.push('\n\n')
|
|
782
|
-
}
|
|
783
|
-
|
|
784
|
-
// Learned patterns
|
|
785
|
-
if (learnedPatterns && Object.keys(learnedPatterns).some((k) => learnedPatterns[k])) {
|
|
786
|
-
parts.push('\n## PROJECT DEFAULTS (apply automatically)\n')
|
|
787
|
-
for (const [key, value] of Object.entries(learnedPatterns)) {
|
|
788
|
-
if (value) {
|
|
789
|
-
parts.push(`- ${key}: ${value}\n`)
|
|
790
|
-
}
|
|
791
|
-
}
|
|
792
|
-
}
|
|
793
|
-
|
|
794
|
-
// Think block
|
|
795
|
-
if (thinkBlock?.plan && thinkBlock.plan.length > 0) {
|
|
796
|
-
parts.push('\n## THINK FIRST (reasoning from analysis)\n')
|
|
797
|
-
if (thinkBlock.conclusions && thinkBlock.conclusions.length > 0) {
|
|
798
|
-
parts.push('Conclusions:\n')
|
|
799
|
-
for (const c of thinkBlock.conclusions) {
|
|
800
|
-
parts.push(` → ${c}\n`)
|
|
801
|
-
}
|
|
802
|
-
}
|
|
803
|
-
parts.push('Plan:\n')
|
|
804
|
-
for (let i = 0; i < thinkBlock.plan.length; i++) {
|
|
805
|
-
parts.push(` ${i + 1}. ${thinkBlock.plan[i]}\n`)
|
|
806
|
-
}
|
|
807
|
-
parts.push(`Confidence: ${Math.round((thinkBlock.confidence || 0.5) * 100)}%\n`)
|
|
808
|
-
}
|
|
809
|
-
|
|
810
|
-
// Relevant memories
|
|
811
|
-
if (relevantMemories && relevantMemories.length > 0) {
|
|
812
|
-
parts.push('\n## CONTEXT (apply these)\n')
|
|
813
|
-
for (const memory of relevantMemories) {
|
|
814
|
-
parts.push(`- **${memory.title}**: ${memory.content}\n`)
|
|
815
|
-
if (memory.tags && memory.tags.length > 0) {
|
|
816
|
-
parts.push(` Tags: ${memory.tags.join(', ')}\n`)
|
|
817
|
-
}
|
|
818
|
-
}
|
|
819
|
-
}
|
|
820
|
-
|
|
821
|
-
parts.push('\n---\n')
|
|
822
|
-
|
|
823
|
-
// =========================================================================
|
|
824
|
-
// SECTION 7: TASK (critical)
|
|
825
|
-
// Template content (actual instructions) + subtasks.
|
|
826
|
-
// LLM reads this AFTER knowing identity, env, rules, and context.
|
|
827
|
-
// =========================================================================
|
|
828
|
-
|
|
829
|
-
parts.push(template.content)
|
|
830
|
-
|
|
831
|
-
// Subtasks (if fragmented)
|
|
832
|
-
if (orchestratorContext?.requiresFragmentation && orchestratorContext.subtasks) {
|
|
833
|
-
parts.push('\n### SUBTASKS (Execute in Order)\n\n')
|
|
834
|
-
parts.push(
|
|
835
|
-
'**IMPORTANT**: Focus on the CURRENT subtask. Use `p. done` when complete to advance.\n\n'
|
|
836
|
-
)
|
|
837
|
-
parts.push('| # | Domain | Description | Status |\n')
|
|
838
|
-
parts.push('|---|--------|-------------|--------|\n')
|
|
839
|
-
|
|
840
|
-
for (const subtask of orchestratorContext.subtasks) {
|
|
841
|
-
const statusIcon =
|
|
842
|
-
subtask.status === 'in_progress'
|
|
843
|
-
? '▶️ **CURRENT**'
|
|
844
|
-
: subtask.status === 'completed'
|
|
845
|
-
? '✅ Done'
|
|
846
|
-
: subtask.status === 'failed'
|
|
847
|
-
? '❌ Failed'
|
|
848
|
-
: '⏳ Pending'
|
|
849
|
-
parts.push(
|
|
850
|
-
`| ${subtask.order} | ${subtask.domain} | ${subtask.description} | ${statusIcon} |\n`
|
|
851
|
-
)
|
|
852
|
-
}
|
|
853
|
-
|
|
854
|
-
const currentSubtask = orchestratorContext.subtasks.find((s) => s.status === 'in_progress')
|
|
855
|
-
if (currentSubtask) {
|
|
856
|
-
parts.push(
|
|
857
|
-
`\n**FOCUS ON SUBTASK #${currentSubtask.order}**: ${currentSubtask.description}\n`
|
|
858
|
-
)
|
|
859
|
-
parts.push(`Agent: ${currentSubtask.agent} | Domain: ${currentSubtask.domain}\n`)
|
|
860
|
-
if (currentSubtask.dependsOn.length > 0) {
|
|
861
|
-
parts.push(`Dependencies: ${currentSubtask.dependsOn.join(', ')}\n`)
|
|
862
|
-
}
|
|
863
|
-
|
|
864
|
-
// Inject previous subtask handoff for context continuity (PRJ-262)
|
|
865
|
-
if (currentSubtask.handoff) {
|
|
866
|
-
const h = currentSubtask.handoff
|
|
867
|
-
parts.push('\n### Previous Subtask Handoff\n\n')
|
|
868
|
-
parts.push(`**From:** ${h.fromSubtask}\n\n`)
|
|
869
|
-
parts.push('**What was done:**\n')
|
|
870
|
-
for (const item of h.whatWasDone) {
|
|
871
|
-
parts.push(`- ${item}\n`)
|
|
872
|
-
}
|
|
873
|
-
if (h.filesChanged.length > 0) {
|
|
874
|
-
parts.push('\n**Files changed:**\n')
|
|
875
|
-
for (const f of h.filesChanged) {
|
|
876
|
-
parts.push(`- \`${f.path}\` (${f.action})\n`)
|
|
877
|
-
}
|
|
878
|
-
}
|
|
879
|
-
parts.push(`\n**Context for this subtask:**\n${h.outputForNextAgent}\n`)
|
|
880
|
-
}
|
|
881
|
-
}
|
|
882
|
-
parts.push('\n')
|
|
883
|
-
}
|
|
884
|
-
|
|
885
|
-
// =========================================================================
|
|
886
|
-
// SECTION 8: OUTPUT (important)
|
|
887
|
-
// Output schema and quality checklists.
|
|
888
|
-
// =========================================================================
|
|
889
|
-
|
|
890
|
-
// Output schema (PRJ-264)
|
|
891
|
-
const schemaType = this.getSchemaTypeForCommand(commandName)
|
|
892
|
-
if (schemaType) {
|
|
893
|
-
const { renderSchemaForPrompt } = await import('../schemas/llm-output')
|
|
894
|
-
const schemaBlock = renderSchemaForPrompt(schemaType)
|
|
895
|
-
if (schemaBlock) {
|
|
896
|
-
parts.push(`\n${schemaBlock}\n`)
|
|
897
|
-
}
|
|
898
|
-
}
|
|
899
|
-
|
|
900
|
-
// Quality checklists (PRJ-298)
|
|
901
|
-
if (commandContext.checklist) {
|
|
902
|
-
const routing = await this.loadChecklistRouting()
|
|
903
|
-
const checklists = await this.loadChecklists()
|
|
904
|
-
|
|
905
|
-
if (routing && Object.keys(checklists).length > 0) {
|
|
906
|
-
parts.push('\n## QUALITY CHECKLISTS\n')
|
|
907
|
-
parts.push(
|
|
908
|
-
'Apply relevant checklists based on task. Read checklist-routing.md for guidance.\n'
|
|
909
|
-
)
|
|
910
|
-
parts.push(`Available: ${Object.keys(checklists).join(', ')}\n`)
|
|
911
|
-
parts.push('Path: templates/checklists/{name}.md\n')
|
|
912
|
-
parts.push('Use Read tool to load checklists you determine are relevant.\n')
|
|
913
|
-
}
|
|
914
|
-
}
|
|
915
|
-
|
|
916
|
-
// =========================================================================
|
|
917
|
-
// SECTION 9: EFFICIENCY (critical)
|
|
918
|
-
// Token efficiency directive — be concise, no preamble.
|
|
919
|
-
// =========================================================================
|
|
920
|
-
|
|
921
|
-
parts.push(this.buildEfficiencyDirective())
|
|
922
|
-
|
|
923
|
-
return parts.join('')
|
|
924
|
-
}
|
|
925
|
-
|
|
926
|
-
/**
|
|
927
|
-
* Filter state data to include only relevant portions for the prompt.
|
|
928
|
-
* Uses InjectionBudgetTracker to enforce cumulative token limits.
|
|
929
|
-
*/
|
|
930
|
-
filterRelevantState(state: State): string | null {
|
|
931
|
-
if (!state || Object.keys(state).length === 0) return null
|
|
932
|
-
|
|
933
|
-
const budgets = this.getEffectiveBudgets()
|
|
934
|
-
const tracker = new InjectionBudgetTracker({ totalPrompt: budgets.stateData })
|
|
935
|
-
const criticalFiles = ['now', 'next', 'context', 'analysis', 'codePatterns']
|
|
936
|
-
const relevant: string[] = []
|
|
937
|
-
|
|
938
|
-
for (const [key, content] of Object.entries(state)) {
|
|
939
|
-
if (content && (content as string).trim()) {
|
|
940
|
-
const sectionBudget = criticalFiles.includes(key) ? 500 : 250
|
|
941
|
-
const section = tracker.addSection(`### ${key}\n${content}`, sectionBudget)
|
|
942
|
-
if (section) relevant.push(section)
|
|
943
|
-
}
|
|
944
|
-
}
|
|
945
|
-
|
|
946
|
-
return relevant.length > 0 ? relevant.join('\n\n') : null
|
|
947
|
-
}
|
|
948
|
-
|
|
949
|
-
/**
|
|
950
|
-
* Build an analysis prompt for pre-action investigation tasks
|
|
951
|
-
*/
|
|
952
|
-
buildAnalysis(
|
|
953
|
-
analysisType: string,
|
|
954
|
-
context: { projectPath: string; projectId?: string }
|
|
955
|
-
): string {
|
|
956
|
-
const parts: string[] = []
|
|
957
|
-
|
|
958
|
-
parts.push(`# Analyze: ${analysisType}\n\n`)
|
|
959
|
-
parts.push('Read the project context and provide your analysis.\n')
|
|
960
|
-
parts.push('No predetermined patterns - decide based on what you find.\n\n')
|
|
961
|
-
|
|
962
|
-
parts.push('## Project Context\n')
|
|
963
|
-
parts.push(`- Path: ${context.projectPath}\n`)
|
|
964
|
-
parts.push(`- ID: ${context.projectId}\n\n`)
|
|
965
|
-
|
|
966
|
-
return parts.join('')
|
|
967
|
-
}
|
|
968
|
-
|
|
969
|
-
/**
|
|
970
|
-
* Extract compressed pattern summary
|
|
971
|
-
*/
|
|
972
|
-
extractPatternSummary(content: string): string | null {
|
|
973
|
-
if (!content) return null
|
|
974
|
-
|
|
975
|
-
const parts: string[] = []
|
|
976
|
-
|
|
977
|
-
const conventionsMatch = content.match(/## Conventions[\s\S]*?(?=##|$)/i)
|
|
978
|
-
if (conventionsMatch) {
|
|
979
|
-
const conventions = conventionsMatch[0]
|
|
980
|
-
.split('\n')
|
|
981
|
-
.filter((line) => line.includes(':') || line.startsWith('-'))
|
|
982
|
-
.slice(0, 6)
|
|
983
|
-
.join('\n')
|
|
984
|
-
if (conventions) parts.push(conventions)
|
|
985
|
-
}
|
|
986
|
-
|
|
987
|
-
const antiPatternsMatch = content.match(/### High Priority[\s\S]*?(?=###|##|$)/i)
|
|
988
|
-
if (antiPatternsMatch) {
|
|
989
|
-
const antiPatterns = antiPatternsMatch[0].substring(0, 300)
|
|
990
|
-
parts.push(`\nAvoid:\n${antiPatterns}`)
|
|
991
|
-
}
|
|
992
|
-
|
|
993
|
-
const joined = parts.join('\n')
|
|
994
|
-
const result = truncateToTokenBudget(joined, 200) // ~800 chars
|
|
995
|
-
return result || null
|
|
996
|
-
}
|
|
997
|
-
|
|
998
|
-
/**
|
|
999
|
-
* Map command names to their expected output schema type.
|
|
1000
|
-
* Returns null for commands that don't need structured output.
|
|
1001
|
-
*/
|
|
1002
|
-
private getSchemaTypeForCommand(commandName: string): string | null {
|
|
1003
|
-
const schemaMap: Record<string, string> = {
|
|
1004
|
-
task: 'subtaskBreakdown',
|
|
1005
|
-
bug: 'classification',
|
|
1006
|
-
}
|
|
1007
|
-
return schemaMap[commandName] ?? null
|
|
1008
|
-
}
|
|
1009
|
-
|
|
1010
|
-
/**
|
|
1011
|
-
* Build critical anti-hallucination rules section.
|
|
1012
|
-
* Used as fallback when full anti-hallucination block can't be built
|
|
1013
|
-
* (e.g., no project path available).
|
|
1014
|
-
*/
|
|
1015
|
-
buildCriticalRules(): string {
|
|
1016
|
-
const fileCount = this._currentContext?.files?.length || this._currentContext?.filteredSize || 0
|
|
1017
|
-
return `
|
|
1018
|
-
## RULES (CRITICAL)
|
|
1019
|
-
1. **READ FIRST**: Use Read tool BEFORE modifying any file. Never assume code structure.
|
|
1020
|
-
2. **MATCH PATTERNS**: Follow existing style, architecture, naming, imports exactly.
|
|
1021
|
-
3. **NO HALLUCINATIONS**: Don't invent files, functions, or paths. If unsure, READ first.
|
|
1022
|
-
4. **GIT SAFETY**: Never use checkout/reset --hard/clean. Always check status first.
|
|
1023
|
-
5. **VERIFY**: After writing, confirm code matches project patterns.
|
|
1024
|
-
Context: ${fileCount} files available. Read what you need.
|
|
1025
|
-
`
|
|
1026
|
-
}
|
|
1027
|
-
|
|
1028
|
-
/**
|
|
1029
|
-
* Build token efficiency directive (PRJ-301).
|
|
1030
|
-
* Instructs the LLM to be concise and avoid wasting tokens on preamble.
|
|
1031
|
-
*/
|
|
1032
|
-
buildEfficiencyDirective(): string {
|
|
1033
|
-
return `
|
|
1034
|
-
## OUTPUT RULES
|
|
1035
|
-
- Be concise. Maximum 4 lines of explanation unless asked for detail.
|
|
1036
|
-
- No preamble ("Here is...", "I'll help you...", "Based on...").
|
|
1037
|
-
- No postamble (summaries, next steps suggestions unless asked).
|
|
1038
|
-
- When executing code: show the code, not the explanation.
|
|
1039
|
-
- Prefer structured output (JSON) over free text when applicable.
|
|
1040
|
-
|
|
1041
|
-
EXECUTE: Follow flow. Use tools. Decide.
|
|
1042
|
-
`
|
|
1043
|
-
}
|
|
1044
|
-
|
|
1045
|
-
/**
|
|
1046
|
-
* Extract domain flags from state data.
|
|
1047
|
-
* Returns the domains object if available in the raw state.
|
|
1048
|
-
*/
|
|
1049
|
-
private extractDomains(state: State): ProjectGroundTruth['domains'] | undefined {
|
|
1050
|
-
if (!state) return undefined
|
|
1051
|
-
// State may contain raw domains from state.json (loaded by context-builder)
|
|
1052
|
-
const raw = state as Record<string, unknown>
|
|
1053
|
-
if (raw.domains && typeof raw.domains === 'object') {
|
|
1054
|
-
const d = raw.domains as Record<string, boolean>
|
|
1055
|
-
return {
|
|
1056
|
-
hasFrontend: d.hasFrontend ?? false,
|
|
1057
|
-
hasBackend: d.hasBackend ?? false,
|
|
1058
|
-
hasDatabase: d.hasDatabase ?? false,
|
|
1059
|
-
hasTesting: d.hasTesting ?? false,
|
|
1060
|
-
hasDocker: d.hasDocker ?? false,
|
|
1061
|
-
}
|
|
1062
|
-
}
|
|
1063
|
-
return undefined
|
|
1064
|
-
}
|
|
1065
|
-
}
|
|
1066
|
-
|
|
1067
|
-
const promptBuilder = new PromptBuilder()
|
|
1068
|
-
export default promptBuilder
|
|
1069
|
-
export { PromptBuilder }
|