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,842 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* NestedContextResolver - Discovers and resolves nested PRJCT.md and AGENTS.md files in monorepos
|
|
3
|
-
*
|
|
4
|
-
* Responsible for:
|
|
5
|
-
* - Finding all PRJCT.md and AGENTS.md files in a monorepo
|
|
6
|
-
* - Building a hierarchy of context (root → packages)
|
|
7
|
-
* - Resolving inheritance between parent and child contexts/agents
|
|
8
|
-
*
|
|
9
|
-
* Pattern from OpenAI Codex AGENTS.md: "Scope = directory tree. Deeper files take precedence."
|
|
10
|
-
*/
|
|
11
|
-
|
|
12
|
-
import fs from 'node:fs/promises'
|
|
13
|
-
import path from 'node:path'
|
|
14
|
-
import pathManager, {
|
|
15
|
-
type MonorepoInfo,
|
|
16
|
-
type MonorepoPackage,
|
|
17
|
-
} from '../infrastructure/path-manager'
|
|
18
|
-
import * as fileHelper from '../utils/file-helper'
|
|
19
|
-
|
|
20
|
-
// ============================================================================
|
|
21
|
-
// TYPES
|
|
22
|
-
// ============================================================================
|
|
23
|
-
|
|
24
|
-
export interface NestedContext {
|
|
25
|
-
/** Absolute path to the PRJCT.md file */
|
|
26
|
-
path: string
|
|
27
|
-
/** Relative path from monorepo root */
|
|
28
|
-
relativePath: string
|
|
29
|
-
/** Depth in the directory tree (0 = root) */
|
|
30
|
-
depth: number
|
|
31
|
-
/** Parent context (null for root) */
|
|
32
|
-
parent: NestedContext | null
|
|
33
|
-
/** Child contexts */
|
|
34
|
-
children: NestedContext[]
|
|
35
|
-
/** Raw content of the PRJCT.md file */
|
|
36
|
-
content: string
|
|
37
|
-
/** Parsed sections from the PRJCT.md */
|
|
38
|
-
sections: ContextSection[]
|
|
39
|
-
/** Associated package info (if in a monorepo package) */
|
|
40
|
-
package: MonorepoPackage | null
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
export interface ContextSection {
|
|
44
|
-
/** Section name (e.g., "Rules", "Patterns", "Stack") */
|
|
45
|
-
name: string
|
|
46
|
-
/** Section content */
|
|
47
|
-
content: string
|
|
48
|
-
/** Whether this section should override parent */
|
|
49
|
-
override: boolean
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
export interface ResolvedContext {
|
|
53
|
-
/** The final merged content */
|
|
54
|
-
content: string
|
|
55
|
-
/** Sources that contributed to this context (from root to leaf) */
|
|
56
|
-
sources: string[]
|
|
57
|
-
/** Sections that were overridden */
|
|
58
|
-
overrides: string[]
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
// ============================================================================
|
|
62
|
-
// AGENTS.md TYPES
|
|
63
|
-
// ============================================================================
|
|
64
|
-
|
|
65
|
-
export interface AgentDefinition {
|
|
66
|
-
/** Agent name (e.g., "frontend", "backend", "database") */
|
|
67
|
-
name: string
|
|
68
|
-
/** Description of what this agent handles */
|
|
69
|
-
description: string
|
|
70
|
-
/** Domain this agent specializes in */
|
|
71
|
-
domain?: string
|
|
72
|
-
/** Trigger phrases that activate this agent */
|
|
73
|
-
triggers?: string[]
|
|
74
|
-
/** Rules/guidelines for this agent */
|
|
75
|
-
rules?: string[]
|
|
76
|
-
/** Code patterns this agent follows */
|
|
77
|
-
patterns?: string[]
|
|
78
|
-
/** Example interactions */
|
|
79
|
-
examples?: string[]
|
|
80
|
-
/** Whether this agent overrides parent definition */
|
|
81
|
-
override?: boolean
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
export interface NestedAgents {
|
|
85
|
-
/** Absolute path to the AGENTS.md file */
|
|
86
|
-
path: string
|
|
87
|
-
/** Relative path from monorepo root */
|
|
88
|
-
relativePath: string
|
|
89
|
-
/** Depth in the directory tree (0 = root) */
|
|
90
|
-
depth: number
|
|
91
|
-
/** Parent agents file (null for root) */
|
|
92
|
-
parent: NestedAgents | null
|
|
93
|
-
/** Child agents files */
|
|
94
|
-
children: NestedAgents[]
|
|
95
|
-
/** Raw content of the AGENTS.md file */
|
|
96
|
-
content: string
|
|
97
|
-
/** Parsed agent definitions */
|
|
98
|
-
agents: AgentDefinition[]
|
|
99
|
-
/** Associated package info (if in a monorepo package) */
|
|
100
|
-
package: MonorepoPackage | null
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
export interface ResolvedAgents {
|
|
104
|
-
/** The merged agent definitions (deeper overrides shallower) */
|
|
105
|
-
agents: AgentDefinition[]
|
|
106
|
-
/** Sources that contributed to these agents (from root to leaf) */
|
|
107
|
-
sources: string[]
|
|
108
|
-
/** Agents that were overridden */
|
|
109
|
-
overrides: string[]
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
// ============================================================================
|
|
113
|
-
// NESTED CONTEXT RESOLVER
|
|
114
|
-
// ============================================================================
|
|
115
|
-
|
|
116
|
-
export class NestedContextResolver {
|
|
117
|
-
private rootPath: string
|
|
118
|
-
private monoInfo: MonorepoInfo | null = null
|
|
119
|
-
|
|
120
|
-
constructor(rootPath: string) {
|
|
121
|
-
this.rootPath = path.resolve(rootPath)
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
/**
|
|
125
|
-
* Initialize the resolver with monorepo detection
|
|
126
|
-
*/
|
|
127
|
-
async initialize(): Promise<void> {
|
|
128
|
-
this.monoInfo = await pathManager.detectMonorepo(this.rootPath)
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
/**
|
|
132
|
-
* Discover all PRJCT.md files in the project/monorepo
|
|
133
|
-
*/
|
|
134
|
-
async discoverContextFiles(): Promise<NestedContext[]> {
|
|
135
|
-
const contexts: NestedContext[] = []
|
|
136
|
-
|
|
137
|
-
// Always check root
|
|
138
|
-
const rootPrjctPath = path.join(this.rootPath, 'PRJCT.md')
|
|
139
|
-
if (await fileHelper.fileExists(rootPrjctPath)) {
|
|
140
|
-
const rootContext = await this.loadContext(rootPrjctPath, null)
|
|
141
|
-
contexts.push(rootContext)
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
// If monorepo, check each package
|
|
145
|
-
if (this.monoInfo?.isMonorepo) {
|
|
146
|
-
for (const pkg of this.monoInfo.packages) {
|
|
147
|
-
const pkgPrjctPath = path.join(pkg.path, 'PRJCT.md')
|
|
148
|
-
if (await fileHelper.fileExists(pkgPrjctPath)) {
|
|
149
|
-
const parentContext = contexts.find((c) => c.depth === 0) || null
|
|
150
|
-
const pkgContext = await this.loadContext(pkgPrjctPath, parentContext, pkg)
|
|
151
|
-
contexts.push(pkgContext)
|
|
152
|
-
|
|
153
|
-
if (parentContext) {
|
|
154
|
-
parentContext.children.push(pkgContext)
|
|
155
|
-
}
|
|
156
|
-
}
|
|
157
|
-
}
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
// Also scan for any PRJCT.md in subdirectories (non-package)
|
|
161
|
-
const additionalContexts = await this.scanForNestedContexts(this.rootPath, contexts)
|
|
162
|
-
contexts.push(...additionalContexts)
|
|
163
|
-
|
|
164
|
-
return contexts
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
/**
|
|
168
|
-
* Load a single PRJCT.md file into a NestedContext
|
|
169
|
-
*/
|
|
170
|
-
private async loadContext(
|
|
171
|
-
filePath: string,
|
|
172
|
-
parent: NestedContext | null,
|
|
173
|
-
pkg: MonorepoPackage | null = null
|
|
174
|
-
): Promise<NestedContext> {
|
|
175
|
-
const content = await fs.readFile(filePath, 'utf-8')
|
|
176
|
-
const relativePath = path.relative(this.rootPath, filePath)
|
|
177
|
-
const depth = relativePath.split(path.sep).length - 1
|
|
178
|
-
|
|
179
|
-
return {
|
|
180
|
-
path: filePath,
|
|
181
|
-
relativePath,
|
|
182
|
-
depth,
|
|
183
|
-
parent,
|
|
184
|
-
children: [],
|
|
185
|
-
content,
|
|
186
|
-
sections: this.parseSections(content),
|
|
187
|
-
package: pkg,
|
|
188
|
-
}
|
|
189
|
-
}
|
|
190
|
-
|
|
191
|
-
/**
|
|
192
|
-
* Parse PRJCT.md content into sections
|
|
193
|
-
*/
|
|
194
|
-
private parseSections(content: string): ContextSection[] {
|
|
195
|
-
const sections: ContextSection[] = []
|
|
196
|
-
const lines = content.split('\n')
|
|
197
|
-
|
|
198
|
-
let currentSection: ContextSection | null = null
|
|
199
|
-
let currentContent: string[] = []
|
|
200
|
-
|
|
201
|
-
for (const line of lines) {
|
|
202
|
-
// Check for section header (## or ###)
|
|
203
|
-
const headerMatch = line.match(/^##\s+(.+)$/)
|
|
204
|
-
if (headerMatch) {
|
|
205
|
-
// Save previous section
|
|
206
|
-
if (currentSection) {
|
|
207
|
-
currentSection.content = currentContent.join('\n').trim()
|
|
208
|
-
sections.push(currentSection)
|
|
209
|
-
}
|
|
210
|
-
|
|
211
|
-
// Check for override marker
|
|
212
|
-
const sectionName = headerMatch[1]
|
|
213
|
-
const override = sectionName.includes('@override') || sectionName.includes('(override)')
|
|
214
|
-
|
|
215
|
-
currentSection = {
|
|
216
|
-
name: sectionName.replace(/@override|\(override\)/gi, '').trim(),
|
|
217
|
-
content: '',
|
|
218
|
-
override,
|
|
219
|
-
}
|
|
220
|
-
currentContent = []
|
|
221
|
-
} else if (currentSection) {
|
|
222
|
-
currentContent.push(line)
|
|
223
|
-
}
|
|
224
|
-
}
|
|
225
|
-
|
|
226
|
-
// Save last section
|
|
227
|
-
if (currentSection) {
|
|
228
|
-
currentSection.content = currentContent.join('\n').trim()
|
|
229
|
-
sections.push(currentSection)
|
|
230
|
-
}
|
|
231
|
-
|
|
232
|
-
return sections
|
|
233
|
-
}
|
|
234
|
-
|
|
235
|
-
/**
|
|
236
|
-
* Scan for additional nested PRJCT.md files not in packages
|
|
237
|
-
*/
|
|
238
|
-
private async scanForNestedContexts(
|
|
239
|
-
dir: string,
|
|
240
|
-
existing: NestedContext[]
|
|
241
|
-
): Promise<NestedContext[]> {
|
|
242
|
-
const found: NestedContext[] = []
|
|
243
|
-
const existingPaths = new Set(existing.map((c) => c.path))
|
|
244
|
-
|
|
245
|
-
const scan = async (currentDir: string, depth: number): Promise<void> => {
|
|
246
|
-
// Limit depth to avoid infinite recursion
|
|
247
|
-
if (depth > 5) return
|
|
248
|
-
|
|
249
|
-
try {
|
|
250
|
-
const entries = await fs.readdir(currentDir, { withFileTypes: true })
|
|
251
|
-
|
|
252
|
-
for (const entry of entries) {
|
|
253
|
-
// Skip common non-project directories
|
|
254
|
-
if (
|
|
255
|
-
entry.name.startsWith('.') ||
|
|
256
|
-
entry.name === 'node_modules' ||
|
|
257
|
-
entry.name === 'dist' ||
|
|
258
|
-
entry.name === 'build' ||
|
|
259
|
-
entry.name === 'coverage'
|
|
260
|
-
) {
|
|
261
|
-
continue
|
|
262
|
-
}
|
|
263
|
-
|
|
264
|
-
if (entry.isDirectory()) {
|
|
265
|
-
const subDir = path.join(currentDir, entry.name)
|
|
266
|
-
const prjctPath = path.join(subDir, 'PRJCT.md')
|
|
267
|
-
|
|
268
|
-
if ((await fileHelper.fileExists(prjctPath)) && !existingPaths.has(prjctPath)) {
|
|
269
|
-
// Find parent context (closest ancestor with PRJCT.md)
|
|
270
|
-
const parent = this.findParentContext(prjctPath, existing.concat(found))
|
|
271
|
-
const context = await this.loadContext(prjctPath, parent)
|
|
272
|
-
found.push(context)
|
|
273
|
-
existingPaths.add(prjctPath)
|
|
274
|
-
|
|
275
|
-
if (parent) {
|
|
276
|
-
parent.children.push(context)
|
|
277
|
-
}
|
|
278
|
-
}
|
|
279
|
-
|
|
280
|
-
// Continue scanning subdirectories
|
|
281
|
-
await scan(subDir, depth + 1)
|
|
282
|
-
}
|
|
283
|
-
}
|
|
284
|
-
} catch {
|
|
285
|
-
// Permission denied or other error, skip
|
|
286
|
-
}
|
|
287
|
-
}
|
|
288
|
-
|
|
289
|
-
await scan(dir, 0)
|
|
290
|
-
return found
|
|
291
|
-
}
|
|
292
|
-
|
|
293
|
-
/**
|
|
294
|
-
* Find the parent context for a given path
|
|
295
|
-
*/
|
|
296
|
-
private findParentContext(filePath: string, contexts: NestedContext[]): NestedContext | null {
|
|
297
|
-
const fileDir = path.dirname(filePath)
|
|
298
|
-
|
|
299
|
-
// Sort by depth descending to find closest parent
|
|
300
|
-
const sorted = [...contexts].sort((a, b) => b.depth - a.depth)
|
|
301
|
-
|
|
302
|
-
for (const ctx of sorted) {
|
|
303
|
-
const ctxDir = path.dirname(ctx.path)
|
|
304
|
-
if (fileDir.startsWith(ctxDir) && fileDir !== ctxDir) {
|
|
305
|
-
return ctx
|
|
306
|
-
}
|
|
307
|
-
}
|
|
308
|
-
|
|
309
|
-
return null
|
|
310
|
-
}
|
|
311
|
-
|
|
312
|
-
/**
|
|
313
|
-
* Resolve context for a specific path by merging parent contexts
|
|
314
|
-
* Deeper files take precedence (can override parent sections)
|
|
315
|
-
*/
|
|
316
|
-
async resolveContextForPath(targetPath: string): Promise<ResolvedContext> {
|
|
317
|
-
const contexts = await this.discoverContextFiles()
|
|
318
|
-
|
|
319
|
-
// Find the most specific context for this path
|
|
320
|
-
const targetDir = path.resolve(targetPath)
|
|
321
|
-
let bestMatch: NestedContext | null = null
|
|
322
|
-
|
|
323
|
-
for (const ctx of contexts) {
|
|
324
|
-
const ctxDir = path.dirname(ctx.path)
|
|
325
|
-
if (targetDir.startsWith(ctxDir)) {
|
|
326
|
-
if (!bestMatch || ctx.depth > bestMatch.depth) {
|
|
327
|
-
bestMatch = ctx
|
|
328
|
-
}
|
|
329
|
-
}
|
|
330
|
-
}
|
|
331
|
-
|
|
332
|
-
if (!bestMatch) {
|
|
333
|
-
return {
|
|
334
|
-
content: '',
|
|
335
|
-
sources: [],
|
|
336
|
-
overrides: [],
|
|
337
|
-
}
|
|
338
|
-
}
|
|
339
|
-
|
|
340
|
-
// Build inheritance chain (from root to leaf)
|
|
341
|
-
const chain: NestedContext[] = []
|
|
342
|
-
let current: NestedContext | null = bestMatch
|
|
343
|
-
while (current) {
|
|
344
|
-
chain.unshift(current)
|
|
345
|
-
current = current.parent
|
|
346
|
-
}
|
|
347
|
-
|
|
348
|
-
// Merge sections following inheritance
|
|
349
|
-
return this.mergeContextChain(chain)
|
|
350
|
-
}
|
|
351
|
-
|
|
352
|
-
/**
|
|
353
|
-
* Merge a chain of contexts following inheritance rules
|
|
354
|
-
*/
|
|
355
|
-
private mergeContextChain(chain: NestedContext[]): ResolvedContext {
|
|
356
|
-
const mergedSections = new Map<string, string>()
|
|
357
|
-
const sources: string[] = []
|
|
358
|
-
const overrides: string[] = []
|
|
359
|
-
|
|
360
|
-
for (const ctx of chain) {
|
|
361
|
-
sources.push(ctx.relativePath)
|
|
362
|
-
|
|
363
|
-
for (const section of ctx.sections) {
|
|
364
|
-
if (section.override || !mergedSections.has(section.name)) {
|
|
365
|
-
mergedSections.set(section.name, section.content)
|
|
366
|
-
if (section.override) {
|
|
367
|
-
overrides.push(`${ctx.relativePath}:${section.name}`)
|
|
368
|
-
}
|
|
369
|
-
} else {
|
|
370
|
-
// Append to existing section
|
|
371
|
-
const existing = mergedSections.get(section.name) || ''
|
|
372
|
-
mergedSections.set(section.name, `${existing}\n\n${section.content}`)
|
|
373
|
-
}
|
|
374
|
-
}
|
|
375
|
-
}
|
|
376
|
-
|
|
377
|
-
// Rebuild content from merged sections
|
|
378
|
-
const parts: string[] = []
|
|
379
|
-
for (const [name, content] of mergedSections) {
|
|
380
|
-
parts.push(`## ${name}\n\n${content}`)
|
|
381
|
-
}
|
|
382
|
-
|
|
383
|
-
return {
|
|
384
|
-
content: parts.join('\n\n---\n\n'),
|
|
385
|
-
sources,
|
|
386
|
-
overrides,
|
|
387
|
-
}
|
|
388
|
-
}
|
|
389
|
-
|
|
390
|
-
/**
|
|
391
|
-
* Get context for a specific monorepo package
|
|
392
|
-
*/
|
|
393
|
-
async getPackageContext(packageName: string): Promise<ResolvedContext | null> {
|
|
394
|
-
if (!this.monoInfo?.isMonorepo) {
|
|
395
|
-
return null
|
|
396
|
-
}
|
|
397
|
-
|
|
398
|
-
const pkg = this.monoInfo.packages.find((p) => p.name === packageName)
|
|
399
|
-
if (!pkg) {
|
|
400
|
-
return null
|
|
401
|
-
}
|
|
402
|
-
|
|
403
|
-
return this.resolveContextForPath(pkg.path)
|
|
404
|
-
}
|
|
405
|
-
|
|
406
|
-
/**
|
|
407
|
-
* Get all package contexts in the monorepo
|
|
408
|
-
*/
|
|
409
|
-
async getAllPackageContexts(): Promise<Map<string, ResolvedContext>> {
|
|
410
|
-
const results = new Map<string, ResolvedContext>()
|
|
411
|
-
|
|
412
|
-
if (!this.monoInfo?.isMonorepo) {
|
|
413
|
-
return results
|
|
414
|
-
}
|
|
415
|
-
|
|
416
|
-
for (const pkg of this.monoInfo.packages) {
|
|
417
|
-
const ctx = await this.resolveContextForPath(pkg.path)
|
|
418
|
-
results.set(pkg.name, ctx)
|
|
419
|
-
}
|
|
420
|
-
|
|
421
|
-
return results
|
|
422
|
-
}
|
|
423
|
-
|
|
424
|
-
// ==========================================================================
|
|
425
|
-
// AGENTS.md DISCOVERY AND RESOLUTION
|
|
426
|
-
// ==========================================================================
|
|
427
|
-
|
|
428
|
-
/**
|
|
429
|
-
* Discover all AGENTS.md files in the project/monorepo
|
|
430
|
-
*/
|
|
431
|
-
async discoverAgentFiles(): Promise<NestedAgents[]> {
|
|
432
|
-
const agentFiles: NestedAgents[] = []
|
|
433
|
-
|
|
434
|
-
// Always check root
|
|
435
|
-
const rootAgentsPath = path.join(this.rootPath, 'AGENTS.md')
|
|
436
|
-
if (await fileHelper.fileExists(rootAgentsPath)) {
|
|
437
|
-
const rootAgents = await this.loadAgents(rootAgentsPath, null)
|
|
438
|
-
agentFiles.push(rootAgents)
|
|
439
|
-
}
|
|
440
|
-
|
|
441
|
-
// If monorepo, check each package
|
|
442
|
-
if (this.monoInfo?.isMonorepo) {
|
|
443
|
-
for (const pkg of this.monoInfo.packages) {
|
|
444
|
-
const pkgAgentsPath = path.join(pkg.path, 'AGENTS.md')
|
|
445
|
-
if (await fileHelper.fileExists(pkgAgentsPath)) {
|
|
446
|
-
const parentAgents = agentFiles.find((a) => a.depth === 0) || null
|
|
447
|
-
const pkgAgents = await this.loadAgents(pkgAgentsPath, parentAgents, pkg)
|
|
448
|
-
agentFiles.push(pkgAgents)
|
|
449
|
-
|
|
450
|
-
if (parentAgents) {
|
|
451
|
-
parentAgents.children.push(pkgAgents)
|
|
452
|
-
}
|
|
453
|
-
}
|
|
454
|
-
}
|
|
455
|
-
}
|
|
456
|
-
|
|
457
|
-
// Also scan for any AGENTS.md in subdirectories (non-package)
|
|
458
|
-
const additionalAgents = await this.scanForNestedAgents(this.rootPath, agentFiles)
|
|
459
|
-
agentFiles.push(...additionalAgents)
|
|
460
|
-
|
|
461
|
-
return agentFiles
|
|
462
|
-
}
|
|
463
|
-
|
|
464
|
-
/**
|
|
465
|
-
* Load a single AGENTS.md file into a NestedAgents structure
|
|
466
|
-
*/
|
|
467
|
-
private async loadAgents(
|
|
468
|
-
filePath: string,
|
|
469
|
-
parent: NestedAgents | null,
|
|
470
|
-
pkg: MonorepoPackage | null = null
|
|
471
|
-
): Promise<NestedAgents> {
|
|
472
|
-
const content = await fs.readFile(filePath, 'utf-8')
|
|
473
|
-
const relativePath = path.relative(this.rootPath, filePath)
|
|
474
|
-
const depth = relativePath.split(path.sep).length - 1
|
|
475
|
-
|
|
476
|
-
return {
|
|
477
|
-
path: filePath,
|
|
478
|
-
relativePath,
|
|
479
|
-
depth,
|
|
480
|
-
parent,
|
|
481
|
-
children: [],
|
|
482
|
-
content,
|
|
483
|
-
agents: this.parseAgents(content),
|
|
484
|
-
package: pkg,
|
|
485
|
-
}
|
|
486
|
-
}
|
|
487
|
-
|
|
488
|
-
/**
|
|
489
|
-
* Parse AGENTS.md content into agent definitions
|
|
490
|
-
*
|
|
491
|
-
* Expected format:
|
|
492
|
-
* ## AgentName @override?
|
|
493
|
-
*
|
|
494
|
-
* Description text here.
|
|
495
|
-
*
|
|
496
|
-
* ### Triggers
|
|
497
|
-
* - trigger phrase 1
|
|
498
|
-
* - trigger phrase 2
|
|
499
|
-
*
|
|
500
|
-
* ### Rules
|
|
501
|
-
* - rule 1
|
|
502
|
-
* - rule 2
|
|
503
|
-
*
|
|
504
|
-
* ### Patterns
|
|
505
|
-
* ```typescript
|
|
506
|
-
* // code pattern
|
|
507
|
-
* ```
|
|
508
|
-
*/
|
|
509
|
-
private parseAgents(content: string): AgentDefinition[] {
|
|
510
|
-
const agents: AgentDefinition[] = []
|
|
511
|
-
const lines = content.split('\n')
|
|
512
|
-
|
|
513
|
-
let currentAgent: AgentDefinition | null = null
|
|
514
|
-
let currentSubsection: string | null = null
|
|
515
|
-
let currentContent: string[] = []
|
|
516
|
-
|
|
517
|
-
const saveCurrentContent = () => {
|
|
518
|
-
if (!currentAgent) return
|
|
519
|
-
|
|
520
|
-
if (currentSubsection) {
|
|
521
|
-
const contentStr = currentContent.join('\n').trim()
|
|
522
|
-
switch (currentSubsection.toLowerCase()) {
|
|
523
|
-
case 'triggers':
|
|
524
|
-
currentAgent.triggers = this.parseListItems(contentStr)
|
|
525
|
-
break
|
|
526
|
-
case 'rules':
|
|
527
|
-
currentAgent.rules = this.parseListItems(contentStr)
|
|
528
|
-
break
|
|
529
|
-
case 'patterns':
|
|
530
|
-
currentAgent.patterns = this.parseCodeBlocks(contentStr)
|
|
531
|
-
break
|
|
532
|
-
case 'examples':
|
|
533
|
-
currentAgent.examples = this.parseListItems(contentStr)
|
|
534
|
-
break
|
|
535
|
-
case 'domain':
|
|
536
|
-
currentAgent.domain = contentStr
|
|
537
|
-
break
|
|
538
|
-
}
|
|
539
|
-
} else {
|
|
540
|
-
// This is the description
|
|
541
|
-
const desc = currentContent.join('\n').trim()
|
|
542
|
-
if (desc && !currentAgent.description) {
|
|
543
|
-
currentAgent.description = desc
|
|
544
|
-
}
|
|
545
|
-
}
|
|
546
|
-
currentContent = []
|
|
547
|
-
}
|
|
548
|
-
|
|
549
|
-
for (const line of lines) {
|
|
550
|
-
// Check for agent header (## AgentName)
|
|
551
|
-
const agentMatch = line.match(/^##\s+([^#].+)$/)
|
|
552
|
-
if (agentMatch) {
|
|
553
|
-
// Save previous agent
|
|
554
|
-
if (currentAgent) {
|
|
555
|
-
saveCurrentContent()
|
|
556
|
-
agents.push(currentAgent)
|
|
557
|
-
}
|
|
558
|
-
|
|
559
|
-
// Check for override marker
|
|
560
|
-
const agentName = agentMatch[1]
|
|
561
|
-
const override = agentName.includes('@override') || agentName.includes('(override)')
|
|
562
|
-
|
|
563
|
-
currentAgent = {
|
|
564
|
-
name: agentName.replace(/@override|\(override\)/gi, '').trim(),
|
|
565
|
-
description: '',
|
|
566
|
-
override,
|
|
567
|
-
}
|
|
568
|
-
currentSubsection = null
|
|
569
|
-
currentContent = []
|
|
570
|
-
continue
|
|
571
|
-
}
|
|
572
|
-
|
|
573
|
-
// Check for subsection header (### Triggers, ### Rules, etc.)
|
|
574
|
-
const subsectionMatch = line.match(/^###\s+(.+)$/)
|
|
575
|
-
if (subsectionMatch && currentAgent) {
|
|
576
|
-
saveCurrentContent()
|
|
577
|
-
currentSubsection = subsectionMatch[1].trim()
|
|
578
|
-
currentContent = []
|
|
579
|
-
continue
|
|
580
|
-
}
|
|
581
|
-
|
|
582
|
-
// Accumulate content
|
|
583
|
-
if (currentAgent) {
|
|
584
|
-
currentContent.push(line)
|
|
585
|
-
}
|
|
586
|
-
}
|
|
587
|
-
|
|
588
|
-
// Save last agent
|
|
589
|
-
if (currentAgent) {
|
|
590
|
-
saveCurrentContent()
|
|
591
|
-
agents.push(currentAgent)
|
|
592
|
-
}
|
|
593
|
-
|
|
594
|
-
return agents
|
|
595
|
-
}
|
|
596
|
-
|
|
597
|
-
/**
|
|
598
|
-
* Parse list items from content (lines starting with - or *)
|
|
599
|
-
*/
|
|
600
|
-
private parseListItems(content: string): string[] {
|
|
601
|
-
return content
|
|
602
|
-
.split('\n')
|
|
603
|
-
.filter((line) => line.match(/^\s*[-*]\s+/))
|
|
604
|
-
.map((line) => line.replace(/^\s*[-*]\s+/, '').trim())
|
|
605
|
-
.filter((item) => item.length > 0)
|
|
606
|
-
}
|
|
607
|
-
|
|
608
|
-
/**
|
|
609
|
-
* Parse code blocks from content
|
|
610
|
-
*/
|
|
611
|
-
private parseCodeBlocks(content: string): string[] {
|
|
612
|
-
const blocks: string[] = []
|
|
613
|
-
const codeBlockRegex = /```[\w]*\n([\s\S]*?)```/g
|
|
614
|
-
let match: RegExpExecArray | null
|
|
615
|
-
|
|
616
|
-
while ((match = codeBlockRegex.exec(content)) !== null) {
|
|
617
|
-
blocks.push(match[1].trim())
|
|
618
|
-
}
|
|
619
|
-
|
|
620
|
-
// If no code blocks, treat entire content as a pattern
|
|
621
|
-
if (blocks.length === 0 && content.trim()) {
|
|
622
|
-
blocks.push(content.trim())
|
|
623
|
-
}
|
|
624
|
-
|
|
625
|
-
return blocks
|
|
626
|
-
}
|
|
627
|
-
|
|
628
|
-
/**
|
|
629
|
-
* Scan for additional nested AGENTS.md files not in packages
|
|
630
|
-
*/
|
|
631
|
-
private async scanForNestedAgents(
|
|
632
|
-
dir: string,
|
|
633
|
-
existing: NestedAgents[]
|
|
634
|
-
): Promise<NestedAgents[]> {
|
|
635
|
-
const found: NestedAgents[] = []
|
|
636
|
-
const existingPaths = new Set(existing.map((a) => a.path))
|
|
637
|
-
|
|
638
|
-
const scan = async (currentDir: string, depth: number): Promise<void> => {
|
|
639
|
-
// Limit depth to avoid infinite recursion
|
|
640
|
-
if (depth > 5) return
|
|
641
|
-
|
|
642
|
-
try {
|
|
643
|
-
const entries = await fs.readdir(currentDir, { withFileTypes: true })
|
|
644
|
-
|
|
645
|
-
for (const entry of entries) {
|
|
646
|
-
// Skip common non-project directories
|
|
647
|
-
if (
|
|
648
|
-
entry.name.startsWith('.') ||
|
|
649
|
-
entry.name === 'node_modules' ||
|
|
650
|
-
entry.name === 'dist' ||
|
|
651
|
-
entry.name === 'build' ||
|
|
652
|
-
entry.name === 'coverage'
|
|
653
|
-
) {
|
|
654
|
-
continue
|
|
655
|
-
}
|
|
656
|
-
|
|
657
|
-
if (entry.isDirectory()) {
|
|
658
|
-
const subDir = path.join(currentDir, entry.name)
|
|
659
|
-
const agentsPath = path.join(subDir, 'AGENTS.md')
|
|
660
|
-
|
|
661
|
-
if ((await fileHelper.fileExists(agentsPath)) && !existingPaths.has(agentsPath)) {
|
|
662
|
-
// Find parent agents file (closest ancestor with AGENTS.md)
|
|
663
|
-
const parent = this.findParentAgents(agentsPath, existing.concat(found))
|
|
664
|
-
const agents = await this.loadAgents(agentsPath, parent)
|
|
665
|
-
found.push(agents)
|
|
666
|
-
existingPaths.add(agentsPath)
|
|
667
|
-
|
|
668
|
-
if (parent) {
|
|
669
|
-
parent.children.push(agents)
|
|
670
|
-
}
|
|
671
|
-
}
|
|
672
|
-
|
|
673
|
-
// Continue scanning subdirectories
|
|
674
|
-
await scan(subDir, depth + 1)
|
|
675
|
-
}
|
|
676
|
-
}
|
|
677
|
-
} catch {
|
|
678
|
-
// Permission denied or other error, skip
|
|
679
|
-
}
|
|
680
|
-
}
|
|
681
|
-
|
|
682
|
-
await scan(dir, 0)
|
|
683
|
-
return found
|
|
684
|
-
}
|
|
685
|
-
|
|
686
|
-
/**
|
|
687
|
-
* Find the parent agents file for a given path
|
|
688
|
-
*/
|
|
689
|
-
private findParentAgents(filePath: string, agentFiles: NestedAgents[]): NestedAgents | null {
|
|
690
|
-
const fileDir = path.dirname(filePath)
|
|
691
|
-
|
|
692
|
-
// Sort by depth descending to find closest parent
|
|
693
|
-
const sorted = [...agentFiles].sort((a, b) => b.depth - a.depth)
|
|
694
|
-
|
|
695
|
-
for (const agents of sorted) {
|
|
696
|
-
const agentsDir = path.dirname(agents.path)
|
|
697
|
-
if (fileDir.startsWith(agentsDir) && fileDir !== agentsDir) {
|
|
698
|
-
return agents
|
|
699
|
-
}
|
|
700
|
-
}
|
|
701
|
-
|
|
702
|
-
return null
|
|
703
|
-
}
|
|
704
|
-
|
|
705
|
-
/**
|
|
706
|
-
* Resolve agents for a specific path by merging parent agent definitions
|
|
707
|
-
* Deeper files take precedence (can override parent agents)
|
|
708
|
-
*/
|
|
709
|
-
async resolveAgentsForPath(targetPath: string): Promise<ResolvedAgents> {
|
|
710
|
-
const agentFiles = await this.discoverAgentFiles()
|
|
711
|
-
|
|
712
|
-
// Find the most specific agents file for this path
|
|
713
|
-
const targetDir = path.resolve(targetPath)
|
|
714
|
-
let bestMatch: NestedAgents | null = null
|
|
715
|
-
|
|
716
|
-
for (const agents of agentFiles) {
|
|
717
|
-
const agentsDir = path.dirname(agents.path)
|
|
718
|
-
if (targetDir.startsWith(agentsDir)) {
|
|
719
|
-
if (!bestMatch || agents.depth > bestMatch.depth) {
|
|
720
|
-
bestMatch = agents
|
|
721
|
-
}
|
|
722
|
-
}
|
|
723
|
-
}
|
|
724
|
-
|
|
725
|
-
if (!bestMatch) {
|
|
726
|
-
return {
|
|
727
|
-
agents: [],
|
|
728
|
-
sources: [],
|
|
729
|
-
overrides: [],
|
|
730
|
-
}
|
|
731
|
-
}
|
|
732
|
-
|
|
733
|
-
// Build inheritance chain (from root to leaf)
|
|
734
|
-
const chain: NestedAgents[] = []
|
|
735
|
-
let current: NestedAgents | null = bestMatch
|
|
736
|
-
while (current) {
|
|
737
|
-
chain.unshift(current)
|
|
738
|
-
current = current.parent
|
|
739
|
-
}
|
|
740
|
-
|
|
741
|
-
// Merge agents following inheritance
|
|
742
|
-
return this.mergeAgentsChain(chain)
|
|
743
|
-
}
|
|
744
|
-
|
|
745
|
-
/**
|
|
746
|
-
* Merge a chain of agent files following inheritance rules
|
|
747
|
-
*/
|
|
748
|
-
private mergeAgentsChain(chain: NestedAgents[]): ResolvedAgents {
|
|
749
|
-
const mergedAgents = new Map<string, AgentDefinition>()
|
|
750
|
-
const sources: string[] = []
|
|
751
|
-
const overrides: string[] = []
|
|
752
|
-
|
|
753
|
-
for (const agentFile of chain) {
|
|
754
|
-
sources.push(agentFile.relativePath)
|
|
755
|
-
|
|
756
|
-
for (const agent of agentFile.agents) {
|
|
757
|
-
const existing = mergedAgents.get(agent.name)
|
|
758
|
-
|
|
759
|
-
if (agent.override || !existing) {
|
|
760
|
-
// Override or new agent
|
|
761
|
-
mergedAgents.set(agent.name, { ...agent })
|
|
762
|
-
if (agent.override && existing) {
|
|
763
|
-
overrides.push(`${agentFile.relativePath}:${agent.name}`)
|
|
764
|
-
}
|
|
765
|
-
} else {
|
|
766
|
-
// Merge with existing agent
|
|
767
|
-
const merged: AgentDefinition = { ...existing }
|
|
768
|
-
|
|
769
|
-
// Append arrays
|
|
770
|
-
if (agent.triggers) {
|
|
771
|
-
merged.triggers = [...(existing.triggers || []), ...agent.triggers]
|
|
772
|
-
}
|
|
773
|
-
if (agent.rules) {
|
|
774
|
-
merged.rules = [...(existing.rules || []), ...agent.rules]
|
|
775
|
-
}
|
|
776
|
-
if (agent.patterns) {
|
|
777
|
-
merged.patterns = [...(existing.patterns || []), ...agent.patterns]
|
|
778
|
-
}
|
|
779
|
-
if (agent.examples) {
|
|
780
|
-
merged.examples = [...(existing.examples || []), ...agent.examples]
|
|
781
|
-
}
|
|
782
|
-
|
|
783
|
-
// Override scalar values if provided
|
|
784
|
-
if (agent.description) {
|
|
785
|
-
merged.description = `${existing.description}\n\n${agent.description}`
|
|
786
|
-
}
|
|
787
|
-
if (agent.domain) {
|
|
788
|
-
merged.domain = agent.domain
|
|
789
|
-
}
|
|
790
|
-
|
|
791
|
-
mergedAgents.set(agent.name, merged)
|
|
792
|
-
}
|
|
793
|
-
}
|
|
794
|
-
}
|
|
795
|
-
|
|
796
|
-
return {
|
|
797
|
-
agents: Array.from(mergedAgents.values()),
|
|
798
|
-
sources,
|
|
799
|
-
overrides,
|
|
800
|
-
}
|
|
801
|
-
}
|
|
802
|
-
|
|
803
|
-
/**
|
|
804
|
-
* Get agents for a specific monorepo package
|
|
805
|
-
*/
|
|
806
|
-
async getPackageAgents(packageName: string): Promise<ResolvedAgents | null> {
|
|
807
|
-
if (!this.monoInfo?.isMonorepo) {
|
|
808
|
-
return null
|
|
809
|
-
}
|
|
810
|
-
|
|
811
|
-
const pkg = this.monoInfo.packages.find((p) => p.name === packageName)
|
|
812
|
-
if (!pkg) {
|
|
813
|
-
return null
|
|
814
|
-
}
|
|
815
|
-
|
|
816
|
-
return this.resolveAgentsForPath(pkg.path)
|
|
817
|
-
}
|
|
818
|
-
|
|
819
|
-
/**
|
|
820
|
-
* Get all package agents in the monorepo
|
|
821
|
-
*/
|
|
822
|
-
async getAllPackageAgents(): Promise<Map<string, ResolvedAgents>> {
|
|
823
|
-
const results = new Map<string, ResolvedAgents>()
|
|
824
|
-
|
|
825
|
-
if (!this.monoInfo?.isMonorepo) {
|
|
826
|
-
return results
|
|
827
|
-
}
|
|
828
|
-
|
|
829
|
-
for (const pkg of this.monoInfo.packages) {
|
|
830
|
-
const agents = await this.resolveAgentsForPath(pkg.path)
|
|
831
|
-
results.set(pkg.name, agents)
|
|
832
|
-
}
|
|
833
|
-
|
|
834
|
-
return results
|
|
835
|
-
}
|
|
836
|
-
}
|
|
837
|
-
|
|
838
|
-
// ============================================================================
|
|
839
|
-
// EXPORTS
|
|
840
|
-
// ============================================================================
|
|
841
|
-
|
|
842
|
-
export default NestedContextResolver
|