prjct-cli 1.22.0 → 1.24.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 +230 -0
- package/bin/prjct +30 -13
- package/dist/bin/prjct-core.mjs +1748 -0
- package/dist/bin/prjct.mjs +17 -36672
- package/dist/cli/linear.mjs +14 -0
- package/dist/daemon/entry.mjs +1429 -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,579 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Orchestrator Executor
|
|
3
|
-
*
|
|
4
|
-
* EXECUTES orchestration in TypeScript - not just paths.
|
|
5
|
-
* This module:
|
|
6
|
-
* 1. Detects domains from task description
|
|
7
|
-
* 2. Loads relevant agents from {globalPath}/agents/
|
|
8
|
-
* 3. Loads skills from agent frontmatter
|
|
9
|
-
* 4. Determines if task should be fragmented
|
|
10
|
-
* 5. Creates subtasks in state.json if fragmented
|
|
11
|
-
*
|
|
12
|
-
* @module agentic/orchestrator-executor
|
|
13
|
-
* @version 1.0.0
|
|
14
|
-
*/
|
|
15
|
-
|
|
16
|
-
import { exec as execCallback } from 'node:child_process'
|
|
17
|
-
import fs from 'node:fs/promises'
|
|
18
|
-
import os from 'node:os'
|
|
19
|
-
import path from 'node:path'
|
|
20
|
-
import { promisify } from 'node:util'
|
|
21
|
-
import { findRelevantFiles } from '../context-tools/files-tool'
|
|
22
|
-
import { getRecentFiles } from '../context-tools/recent-tool'
|
|
23
|
-
import { extractSignatures } from '../context-tools/signatures-tool'
|
|
24
|
-
import { calculateVelocity, formatVelocityContext } from '../domain/velocity'
|
|
25
|
-
import configManager from '../infrastructure/config-manager'
|
|
26
|
-
import pathManager from '../infrastructure/path-manager'
|
|
27
|
-
import outcomeRecorder from '../outcomes/recorder'
|
|
28
|
-
import { DEFAULT_VELOCITY_CONFIG } from '../schemas/velocity'
|
|
29
|
-
import { analysisStorage, stateStorage } from '../storage'
|
|
30
|
-
import type {
|
|
31
|
-
LoadedAgent,
|
|
32
|
-
LoadedSkill,
|
|
33
|
-
OrchestratorContext,
|
|
34
|
-
OrchestratorSubtask,
|
|
35
|
-
RealCodebaseContext,
|
|
36
|
-
SealedAnalysisContext,
|
|
37
|
-
} from '../types'
|
|
38
|
-
import { getErrorMessage, isNotFoundError } from '../types/fs'
|
|
39
|
-
import domainClassifier, { type ProjectContext } from './domain-classifier'
|
|
40
|
-
import { parseFrontmatter } from './template-loader'
|
|
41
|
-
|
|
42
|
-
const execAsync = promisify(execCallback)
|
|
43
|
-
|
|
44
|
-
/**
|
|
45
|
-
* Domain dependency order - earlier domains should complete first
|
|
46
|
-
*/
|
|
47
|
-
const DOMAIN_DEPENDENCY_ORDER = ['database', 'backend', 'frontend', 'testing', 'devops']
|
|
48
|
-
|
|
49
|
-
// =============================================================================
|
|
50
|
-
// Orchestrator Executor Class
|
|
51
|
-
// =============================================================================
|
|
52
|
-
|
|
53
|
-
export class OrchestratorExecutor {
|
|
54
|
-
/**
|
|
55
|
-
* Main entry point - executes full orchestration
|
|
56
|
-
*
|
|
57
|
-
* @param command - The command being executed (e.g., 'task')
|
|
58
|
-
* @param taskDescription - The task description from user
|
|
59
|
-
* @param projectPath - Path to the project
|
|
60
|
-
* @returns Full orchestrator context with loaded agents, skills, and subtasks
|
|
61
|
-
*/
|
|
62
|
-
async execute(
|
|
63
|
-
command: string,
|
|
64
|
-
taskDescription: string,
|
|
65
|
-
projectPath: string
|
|
66
|
-
): Promise<OrchestratorContext> {
|
|
67
|
-
// Step 1: Get project info
|
|
68
|
-
const projectId = await configManager.getProjectId(projectPath)
|
|
69
|
-
const globalPath = pathManager.getGlobalProjectPath(projectId)
|
|
70
|
-
|
|
71
|
-
// Step 2: Load repo analysis for ecosystem info
|
|
72
|
-
const repoAnalysis = await this.loadRepoAnalysis(globalPath)
|
|
73
|
-
|
|
74
|
-
// Step 3: Detect domains from task + project context
|
|
75
|
-
const { domains, primary } = await this.detectDomains(taskDescription, projectId, repoAnalysis)
|
|
76
|
-
|
|
77
|
-
// Step 4: Load agents for detected domains
|
|
78
|
-
const agents = await this.loadAgents(domains, projectId)
|
|
79
|
-
|
|
80
|
-
// Step 5: Load skills from agent frontmatter
|
|
81
|
-
const skills = await this.loadSkills(agents)
|
|
82
|
-
|
|
83
|
-
// Step 6: Gather real codebase context, sealed analysis, and velocity in parallel
|
|
84
|
-
const [realContext, sealedAnalysis, velocityContext] = await Promise.all([
|
|
85
|
-
this.gatherRealContext(taskDescription, projectPath),
|
|
86
|
-
this.loadSealedAnalysis(projectId),
|
|
87
|
-
this.loadVelocityContext(projectId),
|
|
88
|
-
])
|
|
89
|
-
|
|
90
|
-
// Step 7: Determine if fragmentation is needed
|
|
91
|
-
const requiresFragmentation = this.shouldFragment(domains, taskDescription)
|
|
92
|
-
|
|
93
|
-
// Step 8: Create subtasks if fragmentation is required
|
|
94
|
-
let subtasks: OrchestratorSubtask[] | null = null
|
|
95
|
-
if (requiresFragmentation && command === 'task') {
|
|
96
|
-
subtasks = await this.createSubtasks(taskDescription, domains, agents, projectId)
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
return {
|
|
100
|
-
detectedDomains: domains,
|
|
101
|
-
primaryDomain: primary,
|
|
102
|
-
agents,
|
|
103
|
-
skills,
|
|
104
|
-
requiresFragmentation,
|
|
105
|
-
subtasks,
|
|
106
|
-
project: {
|
|
107
|
-
id: projectId,
|
|
108
|
-
ecosystem: repoAnalysis?.ecosystem || 'unknown',
|
|
109
|
-
conventions: repoAnalysis?.conventions || [],
|
|
110
|
-
},
|
|
111
|
-
realContext,
|
|
112
|
-
sealedAnalysis,
|
|
113
|
-
velocityContext,
|
|
114
|
-
}
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
/**
|
|
118
|
-
* Gather real codebase context proactively.
|
|
119
|
-
*
|
|
120
|
-
* Calls existing context tools (files-tool, recent-tool, signatures-tool)
|
|
121
|
-
* to build a briefing so the agent doesn't need to explore first.
|
|
122
|
-
*/
|
|
123
|
-
private async gatherRealContext(
|
|
124
|
-
taskDescription: string,
|
|
125
|
-
projectPath: string
|
|
126
|
-
): Promise<RealCodebaseContext | undefined> {
|
|
127
|
-
try {
|
|
128
|
-
// Run git state + relevant files + recent files in parallel
|
|
129
|
-
const [gitResult, filesResult, recentResult] = await Promise.all([
|
|
130
|
-
this.getGitState(projectPath),
|
|
131
|
-
findRelevantFiles(taskDescription, projectPath, { maxFiles: 10, minScore: 0.15 }),
|
|
132
|
-
getRecentFiles(projectPath, { commits: 10, maxFiles: 10 }),
|
|
133
|
-
])
|
|
134
|
-
|
|
135
|
-
// Extract signatures from top 3 relevant files
|
|
136
|
-
const topFiles = filesResult.files.slice(0, 3)
|
|
137
|
-
const signatureResults = await Promise.all(
|
|
138
|
-
topFiles.map(async (f) => {
|
|
139
|
-
try {
|
|
140
|
-
const result = await extractSignatures(f.path, projectPath)
|
|
141
|
-
if (result.signatures.length === 0) return null
|
|
142
|
-
const sigContent = result.signatures
|
|
143
|
-
.map((s) => `${s.exported ? 'export ' : ''}${s.type} ${s.name}: ${s.signature}`)
|
|
144
|
-
.join('\n')
|
|
145
|
-
return { path: f.path, content: sigContent }
|
|
146
|
-
} catch {
|
|
147
|
-
return null
|
|
148
|
-
}
|
|
149
|
-
})
|
|
150
|
-
)
|
|
151
|
-
|
|
152
|
-
return {
|
|
153
|
-
gitBranch: gitResult.branch,
|
|
154
|
-
gitStatus: gitResult.status,
|
|
155
|
-
relevantFiles: filesResult.files.map((f) => ({
|
|
156
|
-
path: f.path,
|
|
157
|
-
score: Math.round(f.score * 100),
|
|
158
|
-
reason: f.reasons.join(', '),
|
|
159
|
-
})),
|
|
160
|
-
recentFiles: recentResult.hotFiles.slice(0, 5).map((f) => ({
|
|
161
|
-
path: f.path,
|
|
162
|
-
lastChanged: f.lastChanged,
|
|
163
|
-
changes: f.changes,
|
|
164
|
-
})),
|
|
165
|
-
signatures: signatureResults.filter(
|
|
166
|
-
(s): s is { path: string; content: string } => s !== null
|
|
167
|
-
),
|
|
168
|
-
}
|
|
169
|
-
} catch {
|
|
170
|
-
// Non-critical — return undefined if context gathering fails
|
|
171
|
-
return undefined
|
|
172
|
-
}
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
/**
|
|
176
|
-
* Get current git state (branch + short status)
|
|
177
|
-
*/
|
|
178
|
-
private async getGitState(projectPath: string): Promise<{ branch: string; status: string }> {
|
|
179
|
-
try {
|
|
180
|
-
const [branchResult, statusResult] = await Promise.all([
|
|
181
|
-
execAsync('git branch --show-current', { cwd: projectPath }),
|
|
182
|
-
execAsync('git status --porcelain', { cwd: projectPath }),
|
|
183
|
-
])
|
|
184
|
-
|
|
185
|
-
const branch = branchResult.stdout.trim() || 'main'
|
|
186
|
-
const lines = statusResult.stdout.trim().split('\n').filter(Boolean)
|
|
187
|
-
|
|
188
|
-
let modified = 0
|
|
189
|
-
let untracked = 0
|
|
190
|
-
let staged = 0
|
|
191
|
-
for (const line of lines) {
|
|
192
|
-
const code = line.substring(0, 2)
|
|
193
|
-
if (code.startsWith('??')) untracked++
|
|
194
|
-
else if (code[0] !== ' ' && code[0] !== '?') staged++
|
|
195
|
-
else modified++
|
|
196
|
-
}
|
|
197
|
-
|
|
198
|
-
const parts: string[] = []
|
|
199
|
-
if (staged > 0) parts.push(`${staged} staged`)
|
|
200
|
-
if (modified > 0) parts.push(`${modified} modified`)
|
|
201
|
-
if (untracked > 0) parts.push(`${untracked} untracked`)
|
|
202
|
-
const status = parts.length > 0 ? parts.join(', ') : 'clean'
|
|
203
|
-
|
|
204
|
-
return { branch, status }
|
|
205
|
-
} catch {
|
|
206
|
-
return { branch: 'unknown', status: 'git unavailable' }
|
|
207
|
-
}
|
|
208
|
-
}
|
|
209
|
-
|
|
210
|
-
/**
|
|
211
|
-
* Load sealed/active analysis from analysis storage (PRJ-260).
|
|
212
|
-
* Returns sealed if available, otherwise draft as fallback.
|
|
213
|
-
* Returns null if no analysis exists (graceful degradation).
|
|
214
|
-
*/
|
|
215
|
-
private async loadSealedAnalysis(projectId: string): Promise<SealedAnalysisContext | null> {
|
|
216
|
-
try {
|
|
217
|
-
const analysis = await analysisStorage.getActive(projectId)
|
|
218
|
-
if (!analysis) return null
|
|
219
|
-
|
|
220
|
-
return {
|
|
221
|
-
languages: analysis.languages,
|
|
222
|
-
frameworks: analysis.frameworks,
|
|
223
|
-
packageManager: analysis.packageManager,
|
|
224
|
-
sourceDir: analysis.sourceDir,
|
|
225
|
-
testDir: analysis.testDir,
|
|
226
|
-
fileCount: analysis.fileCount,
|
|
227
|
-
patterns: analysis.patterns,
|
|
228
|
-
antiPatterns: analysis.antiPatterns,
|
|
229
|
-
status: analysis.status ?? 'draft',
|
|
230
|
-
commitHash: analysis.commitHash,
|
|
231
|
-
}
|
|
232
|
-
} catch {
|
|
233
|
-
// Graceful degradation — analysis is optional enhancement
|
|
234
|
-
return null
|
|
235
|
-
}
|
|
236
|
-
}
|
|
237
|
-
|
|
238
|
-
/**
|
|
239
|
-
* Load velocity context for estimation guidance (PRJ-296).
|
|
240
|
-
* Returns formatted string for prompt injection, or null if no data.
|
|
241
|
-
*/
|
|
242
|
-
private async loadVelocityContext(projectId: string): Promise<string | null> {
|
|
243
|
-
try {
|
|
244
|
-
const outcomes = await outcomeRecorder.getAll(projectId)
|
|
245
|
-
if (outcomes.length === 0) return null
|
|
246
|
-
|
|
247
|
-
const metrics = calculateVelocity(outcomes, DEFAULT_VELOCITY_CONFIG)
|
|
248
|
-
if (metrics.sprints.length === 0) return null
|
|
249
|
-
|
|
250
|
-
return formatVelocityContext(metrics)
|
|
251
|
-
} catch {
|
|
252
|
-
return null
|
|
253
|
-
}
|
|
254
|
-
}
|
|
255
|
-
|
|
256
|
-
/**
|
|
257
|
-
* Load repo-analysis.json for project context
|
|
258
|
-
*/
|
|
259
|
-
private async loadRepoAnalysis(
|
|
260
|
-
globalPath: string
|
|
261
|
-
): Promise<{ ecosystem: string; conventions: string[]; technologies?: string[] } | null> {
|
|
262
|
-
try {
|
|
263
|
-
const analysisPath = path.join(globalPath, 'analysis', 'repo-analysis.json')
|
|
264
|
-
const content = await fs.readFile(analysisPath, 'utf-8')
|
|
265
|
-
return JSON.parse(content)
|
|
266
|
-
} catch (error) {
|
|
267
|
-
if (isNotFoundError(error)) return null
|
|
268
|
-
console.warn('Failed to load repo-analysis.json:', getErrorMessage(error))
|
|
269
|
-
return null
|
|
270
|
-
}
|
|
271
|
-
}
|
|
272
|
-
|
|
273
|
-
/**
|
|
274
|
-
* Detect which domains are relevant for this task.
|
|
275
|
-
*
|
|
276
|
-
* Uses LLM-based classification with fallback chain (PRJ-299):
|
|
277
|
-
* cache → confirmed patterns → LLM → heuristic
|
|
278
|
-
*/
|
|
279
|
-
async detectDomains(
|
|
280
|
-
taskDescription: string,
|
|
281
|
-
projectId: string,
|
|
282
|
-
repoAnalysis: { ecosystem: string; technologies?: string[] } | null
|
|
283
|
-
): Promise<{ domains: string[]; primary: string }> {
|
|
284
|
-
const globalPath = pathManager.getGlobalProjectPath(projectId)
|
|
285
|
-
const availableAgents = await this.getAvailableAgentNames(globalPath)
|
|
286
|
-
|
|
287
|
-
// Load state.json for project domain info
|
|
288
|
-
let projectDomains = {
|
|
289
|
-
hasFrontend: false,
|
|
290
|
-
hasBackend: true,
|
|
291
|
-
hasDatabase: false,
|
|
292
|
-
hasTesting: false,
|
|
293
|
-
hasDocker: false,
|
|
294
|
-
}
|
|
295
|
-
try {
|
|
296
|
-
const statePath = path.join(globalPath, 'storage', 'state.json')
|
|
297
|
-
const stateContent = await fs.readFile(statePath, 'utf-8')
|
|
298
|
-
const state = JSON.parse(stateContent)
|
|
299
|
-
if (state.domains) {
|
|
300
|
-
projectDomains = state.domains
|
|
301
|
-
}
|
|
302
|
-
} catch {
|
|
303
|
-
// Use defaults
|
|
304
|
-
}
|
|
305
|
-
|
|
306
|
-
const context: ProjectContext = {
|
|
307
|
-
domains: projectDomains,
|
|
308
|
-
agents: availableAgents,
|
|
309
|
-
stack: repoAnalysis ? { language: repoAnalysis.ecosystem } : undefined,
|
|
310
|
-
}
|
|
311
|
-
|
|
312
|
-
const { classification } = await domainClassifier.classify(
|
|
313
|
-
taskDescription,
|
|
314
|
-
projectId,
|
|
315
|
-
globalPath,
|
|
316
|
-
context
|
|
317
|
-
)
|
|
318
|
-
|
|
319
|
-
const domains = [classification.primaryDomain, ...classification.secondaryDomains]
|
|
320
|
-
|
|
321
|
-
// Filter to domains that have corresponding agents
|
|
322
|
-
const validDomains = domains.filter((domain) =>
|
|
323
|
-
availableAgents.some(
|
|
324
|
-
(agent) =>
|
|
325
|
-
agent === domain || agent.includes(domain) || domain.includes(agent.replace('.md', ''))
|
|
326
|
-
)
|
|
327
|
-
)
|
|
328
|
-
|
|
329
|
-
if (validDomains.length === 0) {
|
|
330
|
-
return { domains: ['general'], primary: 'general' }
|
|
331
|
-
}
|
|
332
|
-
|
|
333
|
-
return { domains: validDomains, primary: validDomains[0] }
|
|
334
|
-
}
|
|
335
|
-
|
|
336
|
-
/**
|
|
337
|
-
* Get list of available agent file names
|
|
338
|
-
*/
|
|
339
|
-
private async getAvailableAgentNames(globalPath: string): Promise<string[]> {
|
|
340
|
-
try {
|
|
341
|
-
const agentsDir = path.join(globalPath, 'agents')
|
|
342
|
-
const files = await fs.readdir(agentsDir)
|
|
343
|
-
return files.filter((f) => f.endsWith('.md')).map((f) => f.replace('.md', ''))
|
|
344
|
-
} catch {
|
|
345
|
-
return []
|
|
346
|
-
}
|
|
347
|
-
}
|
|
348
|
-
|
|
349
|
-
/**
|
|
350
|
-
* Load agents for the detected domains
|
|
351
|
-
*
|
|
352
|
-
* Reads agent markdown files from {globalPath}/agents/
|
|
353
|
-
* and extracts their content and skills from frontmatter.
|
|
354
|
-
*
|
|
355
|
-
* Uses parallel file reads for performance (PRJ-110).
|
|
356
|
-
*/
|
|
357
|
-
async loadAgents(domains: string[], projectId: string): Promise<LoadedAgent[]> {
|
|
358
|
-
const globalPath = pathManager.getGlobalProjectPath(projectId)
|
|
359
|
-
const agentsDir = path.join(globalPath, 'agents')
|
|
360
|
-
|
|
361
|
-
// Load all domain agents in parallel
|
|
362
|
-
const agentPromises = domains.map(async (domain): Promise<LoadedAgent | null> => {
|
|
363
|
-
// Try exact match first, then variations
|
|
364
|
-
const possibleNames = [`${domain}.md`, `${domain}-agent.md`, `prjct-${domain}.md`]
|
|
365
|
-
|
|
366
|
-
for (const fileName of possibleNames) {
|
|
367
|
-
const filePath = path.join(agentsDir, fileName)
|
|
368
|
-
try {
|
|
369
|
-
const content = await fs.readFile(filePath, 'utf-8')
|
|
370
|
-
const { frontmatter, body } = this.parseAgentFile(content)
|
|
371
|
-
|
|
372
|
-
return {
|
|
373
|
-
name: fileName.replace('.md', ''),
|
|
374
|
-
domain,
|
|
375
|
-
content: body,
|
|
376
|
-
skills: frontmatter.skills || [],
|
|
377
|
-
filePath,
|
|
378
|
-
effort: frontmatter.effort as LoadedAgent['effort'],
|
|
379
|
-
model: frontmatter.model as string | undefined,
|
|
380
|
-
}
|
|
381
|
-
} catch {
|
|
382
|
-
// Try next variation
|
|
383
|
-
}
|
|
384
|
-
}
|
|
385
|
-
return null
|
|
386
|
-
})
|
|
387
|
-
|
|
388
|
-
const results = await Promise.all(agentPromises)
|
|
389
|
-
return results.filter((agent): agent is LoadedAgent => agent !== null)
|
|
390
|
-
}
|
|
391
|
-
|
|
392
|
-
/**
|
|
393
|
-
* Parse agent markdown file to extract frontmatter and body
|
|
394
|
-
*/
|
|
395
|
-
private parseAgentFile(content: string): {
|
|
396
|
-
frontmatter: { skills?: string[]; [key: string]: unknown }
|
|
397
|
-
body: string
|
|
398
|
-
} {
|
|
399
|
-
const parsed = parseFrontmatter(content)
|
|
400
|
-
|
|
401
|
-
// Convert skills from string to array if needed
|
|
402
|
-
const frontmatter = { ...parsed.frontmatter }
|
|
403
|
-
if (typeof frontmatter.skills === 'string') {
|
|
404
|
-
// Handle comma-separated string
|
|
405
|
-
frontmatter.skills = (frontmatter.skills as string).split(',').map((s) => s.trim())
|
|
406
|
-
}
|
|
407
|
-
|
|
408
|
-
return {
|
|
409
|
-
frontmatter: frontmatter as { skills?: string[]; [key: string]: unknown },
|
|
410
|
-
body: parsed.content,
|
|
411
|
-
}
|
|
412
|
-
}
|
|
413
|
-
|
|
414
|
-
/**
|
|
415
|
-
* Load skills from agent frontmatter
|
|
416
|
-
*
|
|
417
|
-
* Skills are stored in ~/.claude/skills/{name}.md
|
|
418
|
-
*
|
|
419
|
-
* Uses parallel file reads for performance (PRJ-110).
|
|
420
|
-
*/
|
|
421
|
-
async loadSkills(agents: LoadedAgent[]): Promise<LoadedSkill[]> {
|
|
422
|
-
const skillsDir = path.join(os.homedir(), '.claude', 'skills')
|
|
423
|
-
|
|
424
|
-
// Collect unique skill names from all agents, tracking which agents need them
|
|
425
|
-
const skillToAgents = new Map<string, string[]>()
|
|
426
|
-
for (const agent of agents) {
|
|
427
|
-
for (const skillName of agent.skills) {
|
|
428
|
-
const existing = skillToAgents.get(skillName) || []
|
|
429
|
-
existing.push(agent.name)
|
|
430
|
-
skillToAgents.set(skillName, existing)
|
|
431
|
-
}
|
|
432
|
-
}
|
|
433
|
-
|
|
434
|
-
// Load all skills in parallel
|
|
435
|
-
const skillPromises = Array.from(skillToAgents.keys()).map(
|
|
436
|
-
async (skillName): Promise<LoadedSkill | null> => {
|
|
437
|
-
// Check both patterns: flat file and subdirectory (ecosystem standard)
|
|
438
|
-
const flatPath = path.join(skillsDir, `${skillName}.md`)
|
|
439
|
-
const subdirPath = path.join(skillsDir, skillName, 'SKILL.md')
|
|
440
|
-
|
|
441
|
-
// Prefer subdirectory format (ecosystem standard)
|
|
442
|
-
try {
|
|
443
|
-
const content = await fs.readFile(subdirPath, 'utf-8')
|
|
444
|
-
return { name: skillName, content, filePath: subdirPath }
|
|
445
|
-
} catch {
|
|
446
|
-
// Fall back to flat file
|
|
447
|
-
try {
|
|
448
|
-
const content = await fs.readFile(flatPath, 'utf-8')
|
|
449
|
-
return { name: skillName, content, filePath: flatPath }
|
|
450
|
-
} catch {
|
|
451
|
-
// Skill not found — log warning with agent context
|
|
452
|
-
const agentNames = skillToAgents.get(skillName) || []
|
|
453
|
-
console.warn(
|
|
454
|
-
`⚠ Skill "${skillName}" not installed (needed by: ${agentNames.join(', ')}). Run \`prjct sync\` to auto-install.`
|
|
455
|
-
)
|
|
456
|
-
return null
|
|
457
|
-
}
|
|
458
|
-
}
|
|
459
|
-
}
|
|
460
|
-
)
|
|
461
|
-
|
|
462
|
-
const results = await Promise.all(skillPromises)
|
|
463
|
-
return results.filter((skill): skill is LoadedSkill => skill !== null)
|
|
464
|
-
}
|
|
465
|
-
|
|
466
|
-
/**
|
|
467
|
-
* Determine if task should be fragmented into subtasks
|
|
468
|
-
*
|
|
469
|
-
* Fragmentation is needed when:
|
|
470
|
-
* - 3+ domains are involved
|
|
471
|
-
* - Task explicitly mentions multiple areas
|
|
472
|
-
* - Task is complex (many keywords)
|
|
473
|
-
*/
|
|
474
|
-
shouldFragment(domains: string[], taskDescription: string): boolean {
|
|
475
|
-
// Always fragment if 3+ domains
|
|
476
|
-
if (domains.length >= 3) return true
|
|
477
|
-
|
|
478
|
-
// Check for explicit multi-area keywords
|
|
479
|
-
const multiAreaIndicators = [
|
|
480
|
-
'full stack',
|
|
481
|
-
'fullstack',
|
|
482
|
-
'end to end',
|
|
483
|
-
'e2e',
|
|
484
|
-
'complete feature',
|
|
485
|
-
'from database to ui',
|
|
486
|
-
'across layers',
|
|
487
|
-
]
|
|
488
|
-
|
|
489
|
-
const taskLower = taskDescription.toLowerCase()
|
|
490
|
-
for (const indicator of multiAreaIndicators) {
|
|
491
|
-
if (taskLower.includes(indicator)) return true
|
|
492
|
-
}
|
|
493
|
-
|
|
494
|
-
// Check word count - very long tasks often need fragmentation
|
|
495
|
-
const wordCount = taskDescription.split(/\s+/).length
|
|
496
|
-
if (wordCount > 30 && domains.length >= 2) return true
|
|
497
|
-
|
|
498
|
-
return false
|
|
499
|
-
}
|
|
500
|
-
|
|
501
|
-
/**
|
|
502
|
-
* Create subtasks for a fragmented task
|
|
503
|
-
*
|
|
504
|
-
* Orders subtasks by domain dependency (database -> backend -> frontend)
|
|
505
|
-
* and stores them in state.json
|
|
506
|
-
*/
|
|
507
|
-
async createSubtasks(
|
|
508
|
-
taskDescription: string,
|
|
509
|
-
domains: string[],
|
|
510
|
-
agents: LoadedAgent[],
|
|
511
|
-
projectId: string
|
|
512
|
-
): Promise<OrchestratorSubtask[]> {
|
|
513
|
-
// Sort domains by dependency order
|
|
514
|
-
const sortedDomains = [...domains].sort((a, b) => {
|
|
515
|
-
const orderA = DOMAIN_DEPENDENCY_ORDER.indexOf(a)
|
|
516
|
-
const orderB = DOMAIN_DEPENDENCY_ORDER.indexOf(b)
|
|
517
|
-
// Unknown domains go last
|
|
518
|
-
return (orderA === -1 ? 99 : orderA) - (orderB === -1 ? 99 : orderB)
|
|
519
|
-
})
|
|
520
|
-
|
|
521
|
-
// Create subtask for each domain
|
|
522
|
-
const subtasks: OrchestratorSubtask[] = sortedDomains.map((domain, index) => {
|
|
523
|
-
// Find the agent for this domain
|
|
524
|
-
const agent = agents.find((a) => a.domain === domain)
|
|
525
|
-
const agentFile = agent ? `${agent.name}.md` : `${domain}.md`
|
|
526
|
-
|
|
527
|
-
// Determine dependencies - each subtask depends on previous ones
|
|
528
|
-
const dependsOn = sortedDomains.slice(0, index).map((_d, i) => `subtask-${i + 1}`)
|
|
529
|
-
|
|
530
|
-
return {
|
|
531
|
-
id: `subtask-${index + 1}`,
|
|
532
|
-
description: this.generateSubtaskDescription(taskDescription, domain),
|
|
533
|
-
domain,
|
|
534
|
-
agent: agentFile,
|
|
535
|
-
status: index === 0 ? 'in_progress' : 'pending',
|
|
536
|
-
dependsOn,
|
|
537
|
-
order: index + 1,
|
|
538
|
-
}
|
|
539
|
-
})
|
|
540
|
-
|
|
541
|
-
// Store subtasks in state.json via state storage
|
|
542
|
-
await stateStorage.createSubtasks(
|
|
543
|
-
projectId,
|
|
544
|
-
subtasks.map((st) => ({
|
|
545
|
-
id: st.id,
|
|
546
|
-
description: st.description,
|
|
547
|
-
domain: st.domain,
|
|
548
|
-
agent: st.agent,
|
|
549
|
-
dependsOn: st.dependsOn,
|
|
550
|
-
}))
|
|
551
|
-
)
|
|
552
|
-
|
|
553
|
-
return subtasks
|
|
554
|
-
}
|
|
555
|
-
|
|
556
|
-
/**
|
|
557
|
-
* Generate a domain-specific subtask description
|
|
558
|
-
*/
|
|
559
|
-
private generateSubtaskDescription(fullTask: string, domain: string): string {
|
|
560
|
-
const domainDescriptions: Record<string, string> = {
|
|
561
|
-
database: 'Set up data layer: schema, models, migrations',
|
|
562
|
-
backend: 'Implement API: routes, controllers, services, validation',
|
|
563
|
-
frontend: 'Build UI: components, forms, state management',
|
|
564
|
-
testing: 'Write tests: unit, integration, e2e',
|
|
565
|
-
devops: 'Configure deployment: CI/CD, environment, containers',
|
|
566
|
-
uxui: 'Design user experience: flows, accessibility, styling',
|
|
567
|
-
}
|
|
568
|
-
|
|
569
|
-
const prefix = domainDescriptions[domain] || `Handle ${domain} aspects`
|
|
570
|
-
return `[${domain.toUpperCase()}] ${prefix} for: ${fullTask.substring(0, 80)}${fullTask.length > 80 ? '...' : ''}`
|
|
571
|
-
}
|
|
572
|
-
}
|
|
573
|
-
|
|
574
|
-
// =============================================================================
|
|
575
|
-
// Singleton Export
|
|
576
|
-
// =============================================================================
|
|
577
|
-
|
|
578
|
-
export const orchestratorExecutor = new OrchestratorExecutor()
|
|
579
|
-
export default orchestratorExecutor
|