This is page 47 of 52. Use http://codebase.md/eyaltoledano/claude-task-master?lines=true&page={x} to view the full context. # Directory Structure ``` ├── .changeset │ ├── config.json │ └── README.md ├── .claude │ ├── agents │ │ ├── task-checker.md │ │ ├── task-executor.md │ │ └── task-orchestrator.md │ ├── commands │ │ ├── dedupe.md │ │ └── tm │ │ ├── add-dependency │ │ │ └── add-dependency.md │ │ ├── add-subtask │ │ │ ├── add-subtask.md │ │ │ └── convert-task-to-subtask.md │ │ ├── add-task │ │ │ └── add-task.md │ │ ├── analyze-complexity │ │ │ └── analyze-complexity.md │ │ ├── complexity-report │ │ │ └── complexity-report.md │ │ ├── expand │ │ │ ├── expand-all-tasks.md │ │ │ └── expand-task.md │ │ ├── fix-dependencies │ │ │ └── fix-dependencies.md │ │ ├── generate │ │ │ └── generate-tasks.md │ │ ├── help.md │ │ ├── init │ │ │ ├── init-project-quick.md │ │ │ └── init-project.md │ │ ├── learn.md │ │ ├── list │ │ │ ├── list-tasks-by-status.md │ │ │ ├── list-tasks-with-subtasks.md │ │ │ └── list-tasks.md │ │ ├── models │ │ │ ├── setup-models.md │ │ │ └── view-models.md │ │ ├── next │ │ │ └── next-task.md │ │ ├── parse-prd │ │ │ ├── parse-prd-with-research.md │ │ │ └── parse-prd.md │ │ ├── remove-dependency │ │ │ └── remove-dependency.md │ │ ├── remove-subtask │ │ │ └── remove-subtask.md │ │ ├── remove-subtasks │ │ │ ├── remove-all-subtasks.md │ │ │ └── remove-subtasks.md │ │ ├── remove-task │ │ │ └── remove-task.md │ │ ├── set-status │ │ │ ├── to-cancelled.md │ │ │ ├── to-deferred.md │ │ │ ├── to-done.md │ │ │ ├── to-in-progress.md │ │ │ ├── to-pending.md │ │ │ └── to-review.md │ │ ├── setup │ │ │ ├── install-taskmaster.md │ │ │ └── quick-install-taskmaster.md │ │ ├── show │ │ │ └── show-task.md │ │ ├── status │ │ │ └── project-status.md │ │ ├── sync-readme │ │ │ └── sync-readme.md │ │ ├── tm-main.md │ │ ├── update │ │ │ ├── update-single-task.md │ │ │ ├── update-task.md │ │ │ └── update-tasks-from-id.md │ │ ├── utils │ │ │ └── analyze-project.md │ │ ├── validate-dependencies │ │ │ └── validate-dependencies.md │ │ └── workflows │ │ ├── auto-implement-tasks.md │ │ ├── command-pipeline.md │ │ └── smart-workflow.md │ └── TM_COMMANDS_GUIDE.md ├── .coderabbit.yaml ├── .cursor │ ├── mcp.json │ └── rules │ ├── ai_providers.mdc │ ├── ai_services.mdc │ ├── architecture.mdc │ ├── changeset.mdc │ ├── commands.mdc │ ├── context_gathering.mdc │ ├── cursor_rules.mdc │ ├── dependencies.mdc │ ├── dev_workflow.mdc │ ├── git_workflow.mdc │ ├── glossary.mdc │ ├── mcp.mdc │ ├── new_features.mdc │ ├── self_improve.mdc │ ├── tags.mdc │ ├── taskmaster.mdc │ ├── tasks.mdc │ ├── telemetry.mdc │ ├── test_workflow.mdc │ ├── tests.mdc │ ├── ui.mdc │ └── utilities.mdc ├── .cursorignore ├── .env.example ├── .github │ ├── ISSUE_TEMPLATE │ │ ├── bug_report.md │ │ ├── enhancements---feature-requests.md │ │ └── feedback.md │ ├── PULL_REQUEST_TEMPLATE │ │ ├── bugfix.md │ │ ├── config.yml │ │ ├── feature.md │ │ └── integration.md │ ├── PULL_REQUEST_TEMPLATE.md │ ├── scripts │ │ ├── auto-close-duplicates.mjs │ │ ├── backfill-duplicate-comments.mjs │ │ ├── check-pre-release-mode.mjs │ │ ├── parse-metrics.mjs │ │ ├── release.mjs │ │ ├── tag-extension.mjs │ │ └── utils.mjs │ └── workflows │ ├── auto-close-duplicates.yml │ ├── backfill-duplicate-comments.yml │ ├── ci.yml │ ├── claude-dedupe-issues.yml │ ├── claude-docs-trigger.yml │ ├── claude-docs-updater.yml │ ├── claude-issue-triage.yml │ ├── claude.yml │ ├── extension-ci.yml │ ├── extension-release.yml │ ├── log-issue-events.yml │ ├── pre-release.yml │ ├── release-check.yml │ ├── release.yml │ ├── update-models-md.yml │ └── weekly-metrics-discord.yml ├── .gitignore ├── .kiro │ ├── hooks │ │ ├── tm-code-change-task-tracker.kiro.hook │ │ ├── tm-complexity-analyzer.kiro.hook │ │ ├── tm-daily-standup-assistant.kiro.hook │ │ ├── tm-git-commit-task-linker.kiro.hook │ │ ├── tm-pr-readiness-checker.kiro.hook │ │ ├── tm-task-dependency-auto-progression.kiro.hook │ │ └── tm-test-success-task-completer.kiro.hook │ ├── settings │ │ └── mcp.json │ └── steering │ ├── dev_workflow.md │ ├── kiro_rules.md │ ├── self_improve.md │ ├── taskmaster_hooks_workflow.md │ └── taskmaster.md ├── .manypkg.json ├── .mcp.json ├── .npmignore ├── .nvmrc ├── .taskmaster │ ├── CLAUDE.md │ ├── config.json │ ├── docs │ │ ├── MIGRATION-ROADMAP.md │ │ ├── prd-tm-start.txt │ │ ├── prd.txt │ │ ├── README.md │ │ ├── research │ │ │ ├── 2025-06-14_how-can-i-improve-the-scope-up-and-scope-down-comm.md │ │ │ ├── 2025-06-14_should-i-be-using-any-specific-libraries-for-this.md │ │ │ ├── 2025-06-14_test-save-functionality.md │ │ │ ├── 2025-06-14_test-the-fix-for-duplicate-saves-final-test.md │ │ │ └── 2025-08-01_do-we-need-to-add-new-commands-or-can-we-just-weap.md │ │ ├── task-template-importing-prd.txt │ │ ├── test-prd.txt │ │ └── tm-core-phase-1.txt │ ├── reports │ │ ├── task-complexity-report_cc-kiro-hooks.json │ │ ├── task-complexity-report_test-prd-tag.json │ │ ├── task-complexity-report_tm-core-phase-1.json │ │ ├── task-complexity-report.json │ │ └── tm-core-complexity.json │ ├── state.json │ ├── tasks │ │ ├── task_001_tm-start.txt │ │ ├── task_002_tm-start.txt │ │ ├── task_003_tm-start.txt │ │ ├── task_004_tm-start.txt │ │ ├── task_007_tm-start.txt │ │ └── tasks.json │ └── templates │ └── example_prd.txt ├── .vscode │ ├── extensions.json │ └── settings.json ├── apps │ ├── cli │ │ ├── CHANGELOG.md │ │ ├── package.json │ │ ├── src │ │ │ ├── commands │ │ │ │ ├── auth.command.ts │ │ │ │ ├── context.command.ts │ │ │ │ ├── list.command.ts │ │ │ │ ├── set-status.command.ts │ │ │ │ ├── show.command.ts │ │ │ │ └── start.command.ts │ │ │ ├── index.ts │ │ │ ├── ui │ │ │ │ ├── components │ │ │ │ │ ├── dashboard.component.ts │ │ │ │ │ ├── header.component.ts │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── next-task.component.ts │ │ │ │ │ ├── suggested-steps.component.ts │ │ │ │ │ └── task-detail.component.ts │ │ │ │ └── index.ts │ │ │ └── utils │ │ │ ├── auto-update.ts │ │ │ └── ui.ts │ │ └── tsconfig.json │ ├── docs │ │ ├── archive │ │ │ ├── ai-client-utils-example.mdx │ │ │ ├── ai-development-workflow.mdx │ │ │ ├── command-reference.mdx │ │ │ ├── configuration.mdx │ │ │ ├── cursor-setup.mdx │ │ │ ├── examples.mdx │ │ │ └── Installation.mdx │ │ ├── best-practices │ │ │ ├── advanced-tasks.mdx │ │ │ ├── configuration-advanced.mdx │ │ │ └── index.mdx │ │ ├── capabilities │ │ │ ├── cli-root-commands.mdx │ │ │ ├── index.mdx │ │ │ ├── mcp.mdx │ │ │ └── task-structure.mdx │ │ ├── CHANGELOG.md │ │ ├── docs.json │ │ ├── favicon.svg │ │ ├── getting-started │ │ │ ├── contribute.mdx │ │ │ ├── faq.mdx │ │ │ └── quick-start │ │ │ ├── configuration-quick.mdx │ │ │ ├── execute-quick.mdx │ │ │ ├── installation.mdx │ │ │ ├── moving-forward.mdx │ │ │ ├── prd-quick.mdx │ │ │ ├── quick-start.mdx │ │ │ ├── requirements.mdx │ │ │ ├── rules-quick.mdx │ │ │ └── tasks-quick.mdx │ │ ├── introduction.mdx │ │ ├── licensing.md │ │ ├── logo │ │ │ ├── dark.svg │ │ │ ├── light.svg │ │ │ └── task-master-logo.png │ │ ├── package.json │ │ ├── README.md │ │ ├── style.css │ │ ├── vercel.json │ │ └── whats-new.mdx │ └── extension │ ├── .vscodeignore │ ├── assets │ │ ├── banner.png │ │ ├── icon-dark.svg │ │ ├── icon-light.svg │ │ ├── icon.png │ │ ├── screenshots │ │ │ ├── kanban-board.png │ │ │ └── task-details.png │ │ └── sidebar-icon.svg │ ├── CHANGELOG.md │ ├── components.json │ ├── docs │ │ ├── extension-CI-setup.md │ │ └── extension-development-guide.md │ ├── esbuild.js │ ├── LICENSE │ ├── package.json │ ├── package.mjs │ ├── package.publish.json │ ├── README.md │ ├── src │ │ ├── components │ │ │ ├── ConfigView.tsx │ │ │ ├── constants.ts │ │ │ ├── TaskDetails │ │ │ │ ├── AIActionsSection.tsx │ │ │ │ ├── DetailsSection.tsx │ │ │ │ ├── PriorityBadge.tsx │ │ │ │ ├── SubtasksSection.tsx │ │ │ │ ├── TaskMetadataSidebar.tsx │ │ │ │ └── useTaskDetails.ts │ │ │ ├── TaskDetailsView.tsx │ │ │ ├── TaskMasterLogo.tsx │ │ │ └── ui │ │ │ ├── badge.tsx │ │ │ ├── breadcrumb.tsx │ │ │ ├── button.tsx │ │ │ ├── card.tsx │ │ │ ├── collapsible.tsx │ │ │ ├── CollapsibleSection.tsx │ │ │ ├── dropdown-menu.tsx │ │ │ ├── label.tsx │ │ │ ├── scroll-area.tsx │ │ │ ├── separator.tsx │ │ │ ├── shadcn-io │ │ │ │ └── kanban │ │ │ │ └── index.tsx │ │ │ └── textarea.tsx │ │ ├── extension.ts │ │ ├── index.ts │ │ ├── lib │ │ │ └── utils.ts │ │ ├── services │ │ │ ├── config-service.ts │ │ │ ├── error-handler.ts │ │ │ ├── notification-preferences.ts │ │ │ ├── polling-service.ts │ │ │ ├── polling-strategies.ts │ │ │ ├── sidebar-webview-manager.ts │ │ │ ├── task-repository.ts │ │ │ ├── terminal-manager.ts │ │ │ └── webview-manager.ts │ │ ├── test │ │ │ └── extension.test.ts │ │ ├── utils │ │ │ ├── configManager.ts │ │ │ ├── connectionManager.ts │ │ │ ├── errorHandler.ts │ │ │ ├── event-emitter.ts │ │ │ ├── logger.ts │ │ │ ├── mcpClient.ts │ │ │ ├── notificationPreferences.ts │ │ │ └── task-master-api │ │ │ ├── cache │ │ │ │ └── cache-manager.ts │ │ │ ├── index.ts │ │ │ ├── mcp-client.ts │ │ │ ├── transformers │ │ │ │ └── task-transformer.ts │ │ │ └── types │ │ │ └── index.ts │ │ └── webview │ │ ├── App.tsx │ │ ├── components │ │ │ ├── AppContent.tsx │ │ │ ├── EmptyState.tsx │ │ │ ├── ErrorBoundary.tsx │ │ │ ├── PollingStatus.tsx │ │ │ ├── PriorityBadge.tsx │ │ │ ├── SidebarView.tsx │ │ │ ├── TagDropdown.tsx │ │ │ ├── TaskCard.tsx │ │ │ ├── TaskEditModal.tsx │ │ │ ├── TaskMasterKanban.tsx │ │ │ ├── ToastContainer.tsx │ │ │ └── ToastNotification.tsx │ │ ├── constants │ │ │ └── index.ts │ │ ├── contexts │ │ │ └── VSCodeContext.tsx │ │ ├── hooks │ │ │ ├── useTaskQueries.ts │ │ │ ├── useVSCodeMessages.ts │ │ │ └── useWebviewHeight.ts │ │ ├── index.css │ │ ├── index.tsx │ │ ├── providers │ │ │ └── QueryProvider.tsx │ │ ├── reducers │ │ │ └── appReducer.ts │ │ ├── sidebar.tsx │ │ ├── types │ │ │ └── index.ts │ │ └── utils │ │ ├── logger.ts │ │ └── toast.ts │ └── tsconfig.json ├── assets │ ├── .windsurfrules │ ├── AGENTS.md │ ├── claude │ │ ├── agents │ │ │ ├── task-checker.md │ │ │ ├── task-executor.md │ │ │ └── task-orchestrator.md │ │ ├── commands │ │ │ └── tm │ │ │ ├── add-dependency │ │ │ │ └── add-dependency.md │ │ │ ├── add-subtask │ │ │ │ ├── add-subtask.md │ │ │ │ └── convert-task-to-subtask.md │ │ │ ├── add-task │ │ │ │ └── add-task.md │ │ │ ├── analyze-complexity │ │ │ │ └── analyze-complexity.md │ │ │ ├── clear-subtasks │ │ │ │ ├── clear-all-subtasks.md │ │ │ │ └── clear-subtasks.md │ │ │ ├── complexity-report │ │ │ │ └── complexity-report.md │ │ │ ├── expand │ │ │ │ ├── expand-all-tasks.md │ │ │ │ └── expand-task.md │ │ │ ├── fix-dependencies │ │ │ │ └── fix-dependencies.md │ │ │ ├── generate │ │ │ │ └── generate-tasks.md │ │ │ ├── help.md │ │ │ ├── init │ │ │ │ ├── init-project-quick.md │ │ │ │ └── init-project.md │ │ │ ├── learn.md │ │ │ ├── list │ │ │ │ ├── list-tasks-by-status.md │ │ │ │ ├── list-tasks-with-subtasks.md │ │ │ │ └── list-tasks.md │ │ │ ├── models │ │ │ │ ├── setup-models.md │ │ │ │ └── view-models.md │ │ │ ├── next │ │ │ │ └── next-task.md │ │ │ ├── parse-prd │ │ │ │ ├── parse-prd-with-research.md │ │ │ │ └── parse-prd.md │ │ │ ├── remove-dependency │ │ │ │ └── remove-dependency.md │ │ │ ├── remove-subtask │ │ │ │ └── remove-subtask.md │ │ │ ├── remove-subtasks │ │ │ │ ├── remove-all-subtasks.md │ │ │ │ └── remove-subtasks.md │ │ │ ├── remove-task │ │ │ │ └── remove-task.md │ │ │ ├── set-status │ │ │ │ ├── to-cancelled.md │ │ │ │ ├── to-deferred.md │ │ │ │ ├── to-done.md │ │ │ │ ├── to-in-progress.md │ │ │ │ ├── to-pending.md │ │ │ │ └── to-review.md │ │ │ ├── setup │ │ │ │ ├── install-taskmaster.md │ │ │ │ └── quick-install-taskmaster.md │ │ │ ├── show │ │ │ │ └── show-task.md │ │ │ ├── status │ │ │ │ └── project-status.md │ │ │ ├── sync-readme │ │ │ │ └── sync-readme.md │ │ │ ├── tm-main.md │ │ │ ├── update │ │ │ │ ├── update-single-task.md │ │ │ │ ├── update-task.md │ │ │ │ └── update-tasks-from-id.md │ │ │ ├── utils │ │ │ │ └── analyze-project.md │ │ │ ├── validate-dependencies │ │ │ │ └── validate-dependencies.md │ │ │ └── workflows │ │ │ ├── auto-implement-tasks.md │ │ │ ├── command-pipeline.md │ │ │ └── smart-workflow.md │ │ └── TM_COMMANDS_GUIDE.md │ ├── config.json │ ├── env.example │ ├── example_prd.txt │ ├── gitignore │ ├── kiro-hooks │ │ ├── tm-code-change-task-tracker.kiro.hook │ │ ├── tm-complexity-analyzer.kiro.hook │ │ ├── tm-daily-standup-assistant.kiro.hook │ │ ├── tm-git-commit-task-linker.kiro.hook │ │ ├── tm-pr-readiness-checker.kiro.hook │ │ ├── tm-task-dependency-auto-progression.kiro.hook │ │ └── tm-test-success-task-completer.kiro.hook │ ├── roocode │ │ ├── .roo │ │ │ ├── rules-architect │ │ │ │ └── architect-rules │ │ │ ├── rules-ask │ │ │ │ └── ask-rules │ │ │ ├── rules-code │ │ │ │ └── code-rules │ │ │ ├── rules-debug │ │ │ │ └── debug-rules │ │ │ ├── rules-orchestrator │ │ │ │ └── orchestrator-rules │ │ │ └── rules-test │ │ │ └── test-rules │ │ └── .roomodes │ ├── rules │ │ ├── cursor_rules.mdc │ │ ├── dev_workflow.mdc │ │ ├── self_improve.mdc │ │ ├── taskmaster_hooks_workflow.mdc │ │ └── taskmaster.mdc │ └── scripts_README.md ├── bin │ └── task-master.js ├── biome.json ├── CHANGELOG.md ├── CLAUDE.md ├── context │ ├── chats │ │ ├── add-task-dependencies-1.md │ │ └── max-min-tokens.txt.md │ ├── fastmcp-core.txt │ ├── fastmcp-docs.txt │ ├── MCP_INTEGRATION.md │ ├── mcp-js-sdk-docs.txt │ ├── mcp-protocol-repo.txt │ ├── mcp-protocol-schema-03262025.json │ └── mcp-protocol-spec.txt ├── CONTRIBUTING.md ├── docs │ ├── CLI-COMMANDER-PATTERN.md │ ├── command-reference.md │ ├── configuration.md │ ├── contributor-docs │ │ └── testing-roo-integration.md │ ├── cross-tag-task-movement.md │ ├── examples │ │ └── claude-code-usage.md │ ├── examples.md │ ├── licensing.md │ ├── mcp-provider-guide.md │ ├── mcp-provider.md │ ├── migration-guide.md │ ├── models.md │ ├── providers │ │ └── gemini-cli.md │ ├── README.md │ ├── scripts │ │ └── models-json-to-markdown.js │ ├── task-structure.md │ └── tutorial.md ├── images │ └── logo.png ├── index.js ├── jest.config.js ├── jest.resolver.cjs ├── LICENSE ├── llms-install.md ├── mcp-server │ ├── server.js │ └── src │ ├── core │ │ ├── __tests__ │ │ │ └── context-manager.test.js │ │ ├── context-manager.js │ │ ├── direct-functions │ │ │ ├── add-dependency.js │ │ │ ├── add-subtask.js │ │ │ ├── add-tag.js │ │ │ ├── add-task.js │ │ │ ├── analyze-task-complexity.js │ │ │ ├── cache-stats.js │ │ │ ├── clear-subtasks.js │ │ │ ├── complexity-report.js │ │ │ ├── copy-tag.js │ │ │ ├── create-tag-from-branch.js │ │ │ ├── delete-tag.js │ │ │ ├── expand-all-tasks.js │ │ │ ├── expand-task.js │ │ │ ├── fix-dependencies.js │ │ │ ├── generate-task-files.js │ │ │ ├── initialize-project.js │ │ │ ├── list-tags.js │ │ │ ├── list-tasks.js │ │ │ ├── models.js │ │ │ ├── move-task-cross-tag.js │ │ │ ├── move-task.js │ │ │ ├── next-task.js │ │ │ ├── parse-prd.js │ │ │ ├── remove-dependency.js │ │ │ ├── remove-subtask.js │ │ │ ├── remove-task.js │ │ │ ├── rename-tag.js │ │ │ ├── research.js │ │ │ ├── response-language.js │ │ │ ├── rules.js │ │ │ ├── scope-down.js │ │ │ ├── scope-up.js │ │ │ ├── set-task-status.js │ │ │ ├── show-task.js │ │ │ ├── update-subtask-by-id.js │ │ │ ├── update-task-by-id.js │ │ │ ├── update-tasks.js │ │ │ ├── use-tag.js │ │ │ └── validate-dependencies.js │ │ ├── task-master-core.js │ │ └── utils │ │ ├── env-utils.js │ │ └── path-utils.js │ ├── custom-sdk │ │ ├── errors.js │ │ ├── index.js │ │ ├── json-extractor.js │ │ ├── language-model.js │ │ ├── message-converter.js │ │ └── schema-converter.js │ ├── index.js │ ├── logger.js │ ├── providers │ │ └── mcp-provider.js │ └── tools │ ├── add-dependency.js │ ├── add-subtask.js │ ├── add-tag.js │ ├── add-task.js │ ├── analyze.js │ ├── clear-subtasks.js │ ├── complexity-report.js │ ├── copy-tag.js │ ├── delete-tag.js │ ├── expand-all.js │ ├── expand-task.js │ ├── fix-dependencies.js │ ├── generate.js │ ├── get-operation-status.js │ ├── get-task.js │ ├── get-tasks.js │ ├── index.js │ ├── initialize-project.js │ ├── list-tags.js │ ├── models.js │ ├── move-task.js │ ├── next-task.js │ ├── parse-prd.js │ ├── remove-dependency.js │ ├── remove-subtask.js │ ├── remove-task.js │ ├── rename-tag.js │ ├── research.js │ ├── response-language.js │ ├── rules.js │ ├── scope-down.js │ ├── scope-up.js │ ├── set-task-status.js │ ├── update-subtask.js │ ├── update-task.js │ ├── update.js │ ├── use-tag.js │ ├── utils.js │ └── validate-dependencies.js ├── mcp-test.js ├── output.json ├── package-lock.json ├── package.json ├── packages │ ├── build-config │ │ ├── CHANGELOG.md │ │ ├── package.json │ │ ├── src │ │ │ └── tsdown.base.ts │ │ └── tsconfig.json │ └── tm-core │ ├── .gitignore │ ├── CHANGELOG.md │ ├── docs │ │ └── listTasks-architecture.md │ ├── package.json │ ├── POC-STATUS.md │ ├── README.md │ ├── src │ │ ├── auth │ │ │ ├── auth-manager.test.ts │ │ │ ├── auth-manager.ts │ │ │ ├── config.ts │ │ │ ├── credential-store.test.ts │ │ │ ├── credential-store.ts │ │ │ ├── index.ts │ │ │ ├── oauth-service.ts │ │ │ ├── supabase-session-storage.ts │ │ │ └── types.ts │ │ ├── clients │ │ │ ├── index.ts │ │ │ └── supabase-client.ts │ │ ├── config │ │ │ ├── config-manager.spec.ts │ │ │ ├── config-manager.ts │ │ │ ├── index.ts │ │ │ └── services │ │ │ ├── config-loader.service.spec.ts │ │ │ ├── config-loader.service.ts │ │ │ ├── config-merger.service.spec.ts │ │ │ ├── config-merger.service.ts │ │ │ ├── config-persistence.service.spec.ts │ │ │ ├── config-persistence.service.ts │ │ │ ├── environment-config-provider.service.spec.ts │ │ │ ├── environment-config-provider.service.ts │ │ │ ├── index.ts │ │ │ ├── runtime-state-manager.service.spec.ts │ │ │ └── runtime-state-manager.service.ts │ │ ├── constants │ │ │ └── index.ts │ │ ├── entities │ │ │ └── task.entity.ts │ │ ├── errors │ │ │ ├── index.ts │ │ │ └── task-master-error.ts │ │ ├── executors │ │ │ ├── base-executor.ts │ │ │ ├── claude-executor.ts │ │ │ ├── executor-factory.ts │ │ │ ├── executor-service.ts │ │ │ ├── index.ts │ │ │ └── types.ts │ │ ├── index.ts │ │ ├── interfaces │ │ │ ├── ai-provider.interface.ts │ │ │ ├── configuration.interface.ts │ │ │ ├── index.ts │ │ │ └── storage.interface.ts │ │ ├── logger │ │ │ ├── factory.ts │ │ │ ├── index.ts │ │ │ └── logger.ts │ │ ├── mappers │ │ │ └── TaskMapper.ts │ │ ├── parser │ │ │ └── index.ts │ │ ├── providers │ │ │ ├── ai │ │ │ │ ├── base-provider.ts │ │ │ │ └── index.ts │ │ │ └── index.ts │ │ ├── repositories │ │ │ ├── supabase-task-repository.ts │ │ │ └── task-repository.interface.ts │ │ ├── services │ │ │ ├── index.ts │ │ │ ├── organization.service.ts │ │ │ ├── task-execution-service.ts │ │ │ └── task-service.ts │ │ ├── storage │ │ │ ├── api-storage.ts │ │ │ ├── file-storage │ │ │ │ ├── file-operations.ts │ │ │ │ ├── file-storage.ts │ │ │ │ ├── format-handler.ts │ │ │ │ ├── index.ts │ │ │ │ └── path-resolver.ts │ │ │ ├── index.ts │ │ │ └── storage-factory.ts │ │ ├── subpath-exports.test.ts │ │ ├── task-master-core.ts │ │ ├── types │ │ │ ├── database.types.ts │ │ │ ├── index.ts │ │ │ └── legacy.ts │ │ └── utils │ │ ├── id-generator.ts │ │ └── index.ts │ ├── tests │ │ ├── integration │ │ │ └── list-tasks.test.ts │ │ ├── mocks │ │ │ └── mock-provider.ts │ │ ├── setup.ts │ │ └── unit │ │ ├── base-provider.test.ts │ │ ├── executor.test.ts │ │ └── smoke.test.ts │ ├── tsconfig.json │ └── vitest.config.ts ├── README-task-master.md ├── README.md ├── scripts │ ├── dev.js │ ├── init.js │ ├── modules │ │ ├── ai-services-unified.js │ │ ├── commands.js │ │ ├── config-manager.js │ │ ├── dependency-manager.js │ │ ├── index.js │ │ ├── prompt-manager.js │ │ ├── supported-models.json │ │ ├── sync-readme.js │ │ ├── task-manager │ │ │ ├── add-subtask.js │ │ │ ├── add-task.js │ │ │ ├── analyze-task-complexity.js │ │ │ ├── clear-subtasks.js │ │ │ ├── expand-all-tasks.js │ │ │ ├── expand-task.js │ │ │ ├── find-next-task.js │ │ │ ├── generate-task-files.js │ │ │ ├── is-task-dependent.js │ │ │ ├── list-tasks.js │ │ │ ├── migrate.js │ │ │ ├── models.js │ │ │ ├── move-task.js │ │ │ ├── parse-prd │ │ │ │ ├── index.js │ │ │ │ ├── parse-prd-config.js │ │ │ │ ├── parse-prd-helpers.js │ │ │ │ ├── parse-prd-non-streaming.js │ │ │ │ ├── parse-prd-streaming.js │ │ │ │ └── parse-prd.js │ │ │ ├── remove-subtask.js │ │ │ ├── remove-task.js │ │ │ ├── research.js │ │ │ ├── response-language.js │ │ │ ├── scope-adjustment.js │ │ │ ├── set-task-status.js │ │ │ ├── tag-management.js │ │ │ ├── task-exists.js │ │ │ ├── update-single-task-status.js │ │ │ ├── update-subtask-by-id.js │ │ │ ├── update-task-by-id.js │ │ │ └── update-tasks.js │ │ ├── task-manager.js │ │ ├── ui.js │ │ ├── update-config-tokens.js │ │ ├── utils │ │ │ ├── contextGatherer.js │ │ │ ├── fuzzyTaskSearch.js │ │ │ └── git-utils.js │ │ └── utils.js │ ├── task-complexity-report.json │ ├── test-claude-errors.js │ └── test-claude.js ├── src │ ├── ai-providers │ │ ├── anthropic.js │ │ ├── azure.js │ │ ├── base-provider.js │ │ ├── bedrock.js │ │ ├── claude-code.js │ │ ├── custom-sdk │ │ │ ├── claude-code │ │ │ │ ├── errors.js │ │ │ │ ├── index.js │ │ │ │ ├── json-extractor.js │ │ │ │ ├── language-model.js │ │ │ │ ├── message-converter.js │ │ │ │ └── types.js │ │ │ └── grok-cli │ │ │ ├── errors.js │ │ │ ├── index.js │ │ │ ├── json-extractor.js │ │ │ ├── language-model.js │ │ │ ├── message-converter.js │ │ │ └── types.js │ │ ├── gemini-cli.js │ │ ├── google-vertex.js │ │ ├── google.js │ │ ├── grok-cli.js │ │ ├── groq.js │ │ ├── index.js │ │ ├── ollama.js │ │ ├── openai.js │ │ ├── openrouter.js │ │ ├── perplexity.js │ │ └── xai.js │ ├── constants │ │ ├── commands.js │ │ ├── paths.js │ │ ├── profiles.js │ │ ├── providers.js │ │ ├── rules-actions.js │ │ ├── task-priority.js │ │ └── task-status.js │ ├── profiles │ │ ├── amp.js │ │ ├── base-profile.js │ │ ├── claude.js │ │ ├── cline.js │ │ ├── codex.js │ │ ├── cursor.js │ │ ├── gemini.js │ │ ├── index.js │ │ ├── kilo.js │ │ ├── kiro.js │ │ ├── opencode.js │ │ ├── roo.js │ │ ├── trae.js │ │ ├── vscode.js │ │ ├── windsurf.js │ │ └── zed.js │ ├── progress │ │ ├── base-progress-tracker.js │ │ ├── cli-progress-factory.js │ │ ├── parse-prd-tracker.js │ │ ├── progress-tracker-builder.js │ │ └── tracker-ui.js │ ├── prompts │ │ ├── add-task.json │ │ ├── analyze-complexity.json │ │ ├── expand-task.json │ │ ├── parse-prd.json │ │ ├── README.md │ │ ├── research.json │ │ ├── schemas │ │ │ ├── parameter.schema.json │ │ │ ├── prompt-template.schema.json │ │ │ ├── README.md │ │ │ └── variant.schema.json │ │ ├── update-subtask.json │ │ ├── update-task.json │ │ └── update-tasks.json │ ├── provider-registry │ │ └── index.js │ ├── task-master.js │ ├── ui │ │ ├── confirm.js │ │ ├── indicators.js │ │ └── parse-prd.js │ └── utils │ ├── asset-resolver.js │ ├── create-mcp-config.js │ ├── format.js │ ├── getVersion.js │ ├── logger-utils.js │ ├── manage-gitignore.js │ ├── path-utils.js │ ├── profiles.js │ ├── rule-transformer.js │ ├── stream-parser.js │ └── timeout-manager.js ├── test-clean-tags.js ├── test-config-manager.js ├── test-prd.txt ├── test-tag-functions.js ├── test-version-check-full.js ├── test-version-check.js ├── tests │ ├── e2e │ │ ├── e2e_helpers.sh │ │ ├── parse_llm_output.cjs │ │ ├── run_e2e.sh │ │ ├── run_fallback_verification.sh │ │ └── test_llm_analysis.sh │ ├── fixture │ │ └── test-tasks.json │ ├── fixtures │ │ ├── .taskmasterconfig │ │ ├── sample-claude-response.js │ │ ├── sample-prd.txt │ │ └── sample-tasks.js │ ├── integration │ │ ├── claude-code-optional.test.js │ │ ├── cli │ │ │ ├── commands.test.js │ │ │ ├── complex-cross-tag-scenarios.test.js │ │ │ └── move-cross-tag.test.js │ │ ├── manage-gitignore.test.js │ │ ├── mcp-server │ │ │ └── direct-functions.test.js │ │ ├── move-task-cross-tag.integration.test.js │ │ ├── move-task-simple.integration.test.js │ │ └── profiles │ │ ├── amp-init-functionality.test.js │ │ ├── claude-init-functionality.test.js │ │ ├── cline-init-functionality.test.js │ │ ├── codex-init-functionality.test.js │ │ ├── cursor-init-functionality.test.js │ │ ├── gemini-init-functionality.test.js │ │ ├── opencode-init-functionality.test.js │ │ ├── roo-files-inclusion.test.js │ │ ├── roo-init-functionality.test.js │ │ ├── rules-files-inclusion.test.js │ │ ├── trae-init-functionality.test.js │ │ ├── vscode-init-functionality.test.js │ │ └── windsurf-init-functionality.test.js │ ├── manual │ │ ├── progress │ │ │ ├── parse-prd-analysis.js │ │ │ ├── test-parse-prd.js │ │ │ └── TESTING_GUIDE.md │ │ └── prompts │ │ ├── prompt-test.js │ │ └── README.md │ ├── README.md │ ├── setup.js │ └── unit │ ├── ai-providers │ │ ├── claude-code.test.js │ │ ├── custom-sdk │ │ │ └── claude-code │ │ │ └── language-model.test.js │ │ ├── gemini-cli.test.js │ │ ├── mcp-components.test.js │ │ └── openai.test.js │ ├── ai-services-unified.test.js │ ├── commands.test.js │ ├── config-manager.test.js │ ├── config-manager.test.mjs │ ├── dependency-manager.test.js │ ├── init.test.js │ ├── initialize-project.test.js │ ├── kebab-case-validation.test.js │ ├── manage-gitignore.test.js │ ├── mcp │ │ └── tools │ │ ├── __mocks__ │ │ │ └── move-task.js │ │ ├── add-task.test.js │ │ ├── analyze-complexity.test.js │ │ ├── expand-all.test.js │ │ ├── get-tasks.test.js │ │ ├── initialize-project.test.js │ │ ├── move-task-cross-tag-options.test.js │ │ ├── move-task-cross-tag.test.js │ │ └── remove-task.test.js │ ├── mcp-providers │ │ ├── mcp-components.test.js │ │ └── mcp-provider.test.js │ ├── parse-prd.test.js │ ├── profiles │ │ ├── amp-integration.test.js │ │ ├── claude-integration.test.js │ │ ├── cline-integration.test.js │ │ ├── codex-integration.test.js │ │ ├── cursor-integration.test.js │ │ ├── gemini-integration.test.js │ │ ├── kilo-integration.test.js │ │ ├── kiro-integration.test.js │ │ ├── mcp-config-validation.test.js │ │ ├── opencode-integration.test.js │ │ ├── profile-safety-check.test.js │ │ ├── roo-integration.test.js │ │ ├── rule-transformer-cline.test.js │ │ ├── rule-transformer-cursor.test.js │ │ ├── rule-transformer-gemini.test.js │ │ ├── rule-transformer-kilo.test.js │ │ ├── rule-transformer-kiro.test.js │ │ ├── rule-transformer-opencode.test.js │ │ ├── rule-transformer-roo.test.js │ │ ├── rule-transformer-trae.test.js │ │ ├── rule-transformer-vscode.test.js │ │ ├── rule-transformer-windsurf.test.js │ │ ├── rule-transformer-zed.test.js │ │ ├── rule-transformer.test.js │ │ ├── selective-profile-removal.test.js │ │ ├── subdirectory-support.test.js │ │ ├── trae-integration.test.js │ │ ├── vscode-integration.test.js │ │ ├── windsurf-integration.test.js │ │ └── zed-integration.test.js │ ├── progress │ │ └── base-progress-tracker.test.js │ ├── prompt-manager.test.js │ ├── prompts │ │ └── expand-task-prompt.test.js │ ├── providers │ │ └── provider-registry.test.js │ ├── scripts │ │ └── modules │ │ ├── commands │ │ │ ├── move-cross-tag.test.js │ │ │ └── README.md │ │ ├── dependency-manager │ │ │ ├── circular-dependencies.test.js │ │ │ ├── cross-tag-dependencies.test.js │ │ │ └── fix-dependencies-command.test.js │ │ ├── task-manager │ │ │ ├── add-subtask.test.js │ │ │ ├── add-task.test.js │ │ │ ├── analyze-task-complexity.test.js │ │ │ ├── clear-subtasks.test.js │ │ │ ├── complexity-report-tag-isolation.test.js │ │ │ ├── expand-all-tasks.test.js │ │ │ ├── expand-task.test.js │ │ │ ├── find-next-task.test.js │ │ │ ├── generate-task-files.test.js │ │ │ ├── list-tasks.test.js │ │ │ ├── move-task-cross-tag.test.js │ │ │ ├── move-task.test.js │ │ │ ├── parse-prd.test.js │ │ │ ├── remove-subtask.test.js │ │ │ ├── remove-task.test.js │ │ │ ├── research.test.js │ │ │ ├── scope-adjustment.test.js │ │ │ ├── set-task-status.test.js │ │ │ ├── setup.js │ │ │ ├── update-single-task-status.test.js │ │ │ ├── update-subtask-by-id.test.js │ │ │ ├── update-task-by-id.test.js │ │ │ └── update-tasks.test.js │ │ ├── ui │ │ │ └── cross-tag-error-display.test.js │ │ └── utils-tag-aware-paths.test.js │ ├── task-finder.test.js │ ├── task-manager │ │ ├── clear-subtasks.test.js │ │ ├── move-task.test.js │ │ ├── tag-boundary.test.js │ │ └── tag-management.test.js │ ├── task-master.test.js │ ├── ui │ │ └── indicators.test.js │ ├── ui.test.js │ ├── utils-strip-ansi.test.js │ └── utils.test.js ├── tsconfig.json ├── tsdown.config.ts └── turbo.json ``` # Files -------------------------------------------------------------------------------- /context/chats/add-task-dependencies-1.md: -------------------------------------------------------------------------------- ```markdown 1 | # Task Title Formatting Issue Discussion 2 | 3 | _Exported on 5/22/2025 at 00:05:09 EDT from Cursor (0.50.5)_ 4 | 5 | --- 6 | 7 | **User** 8 | 9 | in add-task, i noticed that with some providers, the title comes out with the id in it. i dont know if this is a parsing issue (@ollama.js) or if it this is an improvement we ought to make to the system prompt in @add-task.js 10 | 11 | --- 12 | 13 | **Cursor** 14 | 15 | Okay, I've looked into this. The issue where the task ID is sometimes included in the generated task title (e.g., "Task #89: Introduce Prioritize Command...") likely stems from the prompt construction in `scripts/modules/task-manager/add-task.js`. 16 | 17 | The current user prompt (around line 208) is: 18 | `Create a comprehensive new task (Task #${newTaskId}) for a software development project based on this description: "${prompt}"` 19 | 20 | The AI might be interpreting `(Task #${newTaskId})` as part of the content it needs to generate, especially for the title. The `ollama.js` provider itself doesn't seem to be modifying the content in a way that would add the ID; it primarily passes the prompt and schema to the Ollama service. 21 | 22 | I'll adjust the user prompt in `scripts/modules/task-manager/add-task.js` to clarify that the task ID is contextual information, not part of the title to be generated. 23 | 24 | I'll change this part of the prompt: 25 | `Create a comprehensive new task (Task #${newTaskId}) for a software development project based on this description: "${prompt}"` 26 | 27 | to something like: 28 | `You are generating the details for Task #${newTaskId}. Based on the user's request: "${prompt}", create a comprehensive new task for a software development project.` 29 | 30 | This rephrasing should guide the AI to use the ID as context rather than including it directly in the `title` field of the generated JSON object. 31 | 32 | Here's the proposed change: 33 | 34 | ```javascript:scripts/modules/task-manager/add-task.js 35 | // ... existing code ... 36 | if (manualTaskData?.testStrategy) 37 | contextFromArgs += `\n- Additional Test Strategy Context: "${manualTaskData.testStrategy}"`; 38 | 39 | // User Prompt 40 | const userPrompt = `You are generating the details for Task #${newTaskId}. Based on the user's request: "${prompt}", create a comprehensive new task for a software development project. 41 | 42 | ${contextTasks} 43 | ${contextFromArgs ? `\nConsider these additional details provided by the user:${contextFromArgs}` : ''} 44 | 45 | Return your answer as a single JSON object matching the schema precisely: 46 | ${taskStructureDesc} 47 | 48 | Make sure the details and test strategy are thorough and specific.`; 49 | 50 | // Start the loading indicator - only for text mode 51 | if (outputFormat === 'text') { 52 | // ... existing code ... 53 | ``` 54 | 55 | This change clarifies the role of `newTaskId` for the AI. Let me know if you'd like to test this or make further adjustments! 56 | 57 | ```javascript 58 | // ... existing code ... 59 | if (manualTaskData?.testStrategy) 60 | contextFromArgs += `\n- Additional Test Strategy Context: "${manualTaskData.testStrategy}"`; 61 | 62 | // User Prompt 63 | const userPrompt = `You are generating the details for Task #${newTaskId}. Based on the user's request: "${prompt}", create a comprehensive new task for a software development project. 64 | 65 | ${contextTasks} 66 | ${contextFromArgs ? `\nConsider these additional details provided by the user:${contextFromArgs}` : ''} 67 | 68 | Return your answer as a single JSON object matching the schema precisely: 69 | ${taskStructureDesc} 70 | 71 | Make sure the details and test strategy are thorough and specific.`; 72 | 73 | // Start the loading indicator - only for text mode 74 | if (outputFormat === 'text') { 75 | // ... existing code ... 76 | ``` 77 | 78 | --- 79 | 80 | **User** 81 | 82 | get the details of task id 88 -- i wonder if we can - in the above place, be smart about passing in the ids, titles, descriptions (but not details) and dependencies of all the other tasks 83 | 84 | i don't want it to take a ton of context, but the goal here is to also fill in the dependency field when creating a task. right now it's not being filled in and i have to update all the tasks for it to be populated. so i want it to be fixed at the source in add-task ideally and i want a lightweight but accurate way to pass in the other tasks and their dependencies, and not passing in the actual details of the task and only the above as i explained might be enough. 85 | 86 | --- 87 | 88 | **Cursor** 89 | 90 | Let me get the details of task ID 88 first: 91 | 92 | Now I'll look at the current implementation of add-task.js to understand how we can improve the context provided to the AI: 93 | 94 | Based on the task details and the current implementation of add-task.js, I'll create an improved version that provides more context about other tasks and their dependency relationships without overwhelming the token limit. Here's my proposed change: 95 | 96 | ```javascript 97 | // ... existing code ... 98 | report('DEBUG: Taking AI task generation path.', 'debug'); 99 | // --- Refactored AI Interaction --- 100 | report(`Generating task data with AI with prompt:\n${prompt}`, 'info'); 101 | 102 | // Create context string for task creation prompt 103 | let contextTasks = ''; 104 | 105 | // Create a dependency map for better understanding of the task relationships 106 | const taskMap = {}; 107 | data.tasks.forEach((t) => { 108 | // For each task, only include id, title, description, and dependencies 109 | taskMap[t.id] = { 110 | id: t.id, 111 | title: t.title, 112 | description: t.description, 113 | dependencies: t.dependencies || [], 114 | status: t.status 115 | }; 116 | }); 117 | 118 | if (numericDependencies.length > 0) { 119 | // If specific dependencies were provided, focus on them 120 | const dependentTasks = data.tasks.filter((t) => 121 | numericDependencies.includes(t.id) 122 | ); 123 | contextTasks = `\nThis task depends on the following tasks:\n${dependentTasks 124 | .map((t) => `- Task ${t.id}: ${t.title} - ${t.description}`) 125 | .join('\n')}`; 126 | 127 | // Add dependency chain information (what these tasks depend on) 128 | const dependencyChains = []; 129 | for (const depTask of dependentTasks) { 130 | if (depTask.dependencies && depTask.dependencies.length > 0) { 131 | const subDeps = depTask.dependencies.map((subDepId) => { 132 | const subDepTask = data.tasks.find((t) => t.id === subDepId); 133 | return subDepTask 134 | ? `Task ${subDepId}: ${subDepTask.title}` 135 | : `Task ${subDepId}`; 136 | }); 137 | dependencyChains.push( 138 | `Task ${depTask.id} depends on: ${subDeps.join(', ')}` 139 | ); 140 | } 141 | } 142 | 143 | if (dependencyChains.length > 0) { 144 | contextTasks += `\n\nDependency chains:\n${dependencyChains.join('\n')}`; 145 | } 146 | } else { 147 | // If no dependencies provided, show recent and related tasks 148 | // Get recent tasks (newest first) 149 | const recentTasks = [...data.tasks].sort((a, b) => b.id - a.id).slice(0, 5); 150 | 151 | // Get tasks that might be related based on simple keyword matching 152 | const keywords = prompt 153 | .toLowerCase() 154 | .split(/\s+/) 155 | .filter( 156 | (word) => 157 | word.length > 4 && 158 | !['the', 'and', 'that', 'with', 'this', 'for', 'from'].includes(word) 159 | ); 160 | 161 | const relatedTasks = 162 | keywords.length > 0 163 | ? data.tasks 164 | .filter( 165 | (t) => 166 | keywords.some( 167 | (keyword) => 168 | t.title.toLowerCase().includes(keyword) || 169 | t.description.toLowerCase().includes(keyword) 170 | ) && !recentTasks.some((rt) => rt.id === t.id) 171 | ) 172 | .slice(0, 3) 173 | : []; 174 | 175 | if (recentTasks.length > 0) { 176 | contextTasks = `\nRecent tasks in the project:\n${recentTasks 177 | .map((t) => `- Task ${t.id}: ${t.title} - ${t.description}`) 178 | .join('\n')}`; 179 | } 180 | 181 | if (relatedTasks.length > 0) { 182 | contextTasks += `\n\nPotentially related tasks based on keywords:\n${relatedTasks 183 | .map((t) => `- Task ${t.id}: ${t.title} - ${t.description}`) 184 | .join('\n')}`; 185 | } 186 | 187 | // Add a concise view of the task dependency structure 188 | contextTasks += '\n\nSummary of task dependencies in the project:'; 189 | const pendingTasks = data.tasks.filter((t) => t.status !== 'done').slice(-10); 190 | for (const task of pendingTasks) { 191 | const depsStr = 192 | task.dependencies && task.dependencies.length > 0 193 | ? task.dependencies.join(', ') 194 | : 'None'; 195 | contextTasks += `\n- Task ${task.id}: depends on [${depsStr}]`; 196 | } 197 | } 198 | 199 | // System Prompt - Enhanced for dependency awareness 200 | const systemPrompt = 201 | "You are a helpful assistant that creates well-structured tasks for a software development project. Generate a single new task based on the user's description, adhering strictly to the provided JSON schema. Pay special attention to dependencies between tasks, ensuring the new task correctly references any tasks it depends on."; 202 | 203 | // Task Structure Description (for user prompt) 204 | const taskStructureDesc = ` 205 | { 206 | "title": "Task title goes here", 207 | "description": "A concise one or two sentence description of what the task involves", 208 | "details": "In-depth implementation details, considerations, and guidance.", 209 | "testStrategy": "Detailed approach for verifying task completion." 210 | }`; 211 | 212 | // Add any manually provided details to the prompt for context 213 | let contextFromArgs = ''; 214 | if (manualTaskData?.title) 215 | contextFromArgs += `\n- Suggested Title: "${manualTaskData.title}"`; 216 | if (manualTaskData?.description) 217 | contextFromArgs += `\n- Suggested Description: "${manualTaskData.description}"`; 218 | if (manualTaskData?.details) 219 | contextFromArgs += `\n- Additional Details Context: "${manualTaskData.details}"`; 220 | if (manualTaskData?.testStrategy) 221 | contextFromArgs += `\n- Additional Test Strategy Context: "${manualTaskData.testStrategy}"`; 222 | 223 | // User Prompt 224 | const userPrompt = `You are generating the details for Task #${newTaskId}. Based on the user's request: "${prompt}", create a comprehensive new task for a software development project. 225 | 226 | ${contextTasks} 227 | ${contextFromArgs ? `\nConsider these additional details provided by the user:${contextFromArgs}` : ''} 228 | 229 | Based on the information about existing tasks and their dependencies, suggest appropriate dependencies for this task if any are needed. The task IDs mentioned above can be referenced in your implementation details. 230 | 231 | Return your answer as a single JSON object matching the schema precisely: 232 | ${taskStructureDesc} 233 | 234 | Make sure the details and test strategy are thorough and specific. Don't include the task ID in the title.`; 235 | // ... existing code ... 236 | ``` 237 | 238 | Now let's test the changes to see if they improve the task creation process, especially around dependency handling: 239 | 240 | --- 241 | 242 | **User** 243 | 244 | this will probably need to be adjusted so from a structured output pov the ai knows to add the info in that field 245 | 246 | --- 247 | 248 | **Cursor** 249 | 250 | You're absolutely right. While our changes improve the context provided to the AI, they don't provide a structured way for the AI to include the dependencies in its output schema. Let's modify the Zod schema to explicitly include a `dependencies` field: 251 | 252 | ```javascript 253 | // Define Zod schema for the expected AI output object 254 | const AiTaskDataSchema = z.object({ 255 | title: z.string().describe('Clear, concise title for the task'), 256 | description: z 257 | .string() 258 | .describe('A one or two sentence description of the task'), 259 | details: z 260 | .string() 261 | .describe('In-depth implementation details, considerations, and guidance'), 262 | testStrategy: z 263 | .string() 264 | .describe('Detailed approach for verifying task completion'), 265 | dependencies: z 266 | .array(z.number()) 267 | .optional() 268 | .describe( 269 | 'Array of task IDs that this task depends on (must be completed before this task can start)' 270 | ) 271 | }); 272 | 273 | // ... existing code ... 274 | 275 | // Task Structure Description (for user prompt) 276 | const taskStructureDesc = ` 277 | { 278 | "title": "Task title goes here", 279 | "description": "A concise one or two sentence description of what the task involves", 280 | "details": "In-depth implementation details, considerations, and guidance.", 281 | "testStrategy": "Detailed approach for verifying task completion.", 282 | "dependencies": [1, 2, 3] // Optional: Array of existing task IDs that this task depends on 283 | }`; 284 | 285 | // ... existing code ... 286 | 287 | // User Prompt 288 | const userPrompt = `You are generating the details for Task #${newTaskId}. Based on the user's request: "${prompt}", create a comprehensive new task for a software development project. 289 | 290 | ${contextTasks} 291 | ${contextFromArgs ? `\nConsider these additional details provided by the user:${contextFromArgs}` : ''} 292 | 293 | Based on the information about existing tasks and their dependencies, include appropriate dependencies in the "dependencies" array if any are needed. Only include task IDs that this new task directly depends on. 294 | 295 | Return your answer as a single JSON object matching the schema precisely: 296 | ${taskStructureDesc} 297 | 298 | Make sure the details and test strategy are thorough and specific. Don't include the task ID in the title.`; 299 | 300 | // ... existing code ... 301 | 302 | // Create the new task object 303 | const newTask = { 304 | id: newTaskId, 305 | title: taskData.title, 306 | description: taskData.description, 307 | details: taskData.details || '', 308 | testStrategy: taskData.testStrategy || '', 309 | status: 'pending', 310 | dependencies: taskData.dependencies?.length 311 | ? taskData.dependencies 312 | : numericDependencies, // Use AI-suggested dependencies if available, fallback to manually specified 313 | priority: effectivePriority, 314 | subtasks: [] // Initialize with empty subtasks array 315 | }; 316 | ``` 317 | 318 | Let's make one more small fix - I notice there's still a reference to `numericDependencies` in the success message output that should be adjusted to use the task's actual dependencies: 319 | 320 | ```javascript 321 | // ... existing code ... 322 | console.log( 323 | boxen( 324 | chalk.white.bold(`Task ${newTaskId} Created Successfully`) + 325 | '\n\n' + 326 | chalk.white(`Title: ${newTask.title}`) + 327 | '\n' + 328 | chalk.white(`Status: ${getStatusWithColor(newTask.status)}`) + 329 | '\n' + 330 | chalk.white( 331 | `Priority: ${chalk[getPriorityColor(newTask.priority)](newTask.priority)}` 332 | ) + 333 | '\n' + 334 | (newTask.dependencies.length > 0 335 | ? chalk.white(`Dependencies: ${newTask.dependencies.join(', ')}`) + 336 | '\n' 337 | : '') + 338 | '\n' + 339 | // ... existing code ... 340 | ``` 341 | 342 | Now let's test our changes to make sure they work properly: 343 | 344 | --- 345 | 346 | **User** 347 | 348 | looks like it worked. i would like -- in the case of the CLI only, to also show some additional stuff in @add-task.js 349 | 350 | we just did a bunch of magic, and it would be too bad not to show it to the user as we do it, without it being too much 351 | 352 | (ignore the failed ollama call) 353 | 354 | i think there could be a line or two that shows the identified dependencies or something. its sexy stuff, let's make sure the user knows about it elegantly. @ui.js 355 | 356 | --- 357 | 358 | **Cursor** 359 | 360 | Let's enhance the CLI experience to elegantly showcase the dependency analysis we're performing. I'll add a small, informative display in add-task.js that shows the intelligent context we're building: 361 | 362 | ```javascript 363 | // ... existing code ... 364 | // Create a dependency map for better understanding of the task relationships 365 | const taskMap = {}; 366 | data.tasks.forEach((t) => { 367 | // For each task, only include id, title, description, and dependencies 368 | taskMap[t.id] = { 369 | id: t.id, 370 | title: t.title, 371 | description: t.description, 372 | dependencies: t.dependencies || [], 373 | status: t.status 374 | }; 375 | }); 376 | 377 | // CLI-only feedback for the dependency analysis 378 | if (outputFormat === 'text') { 379 | console.log( 380 | boxen(chalk.cyan.bold('Task Context Analysis') + '\n', { 381 | padding: { top: 0, bottom: 0, left: 1, right: 1 }, 382 | margin: { top: 0, bottom: 0 }, 383 | borderColor: 'cyan', 384 | borderStyle: 'round' 385 | }) 386 | ); 387 | } 388 | 389 | if (numericDependencies.length > 0) { 390 | // If specific dependencies were provided, focus on them 391 | const dependentTasks = data.tasks.filter((t) => 392 | numericDependencies.includes(t.id) 393 | ); 394 | contextTasks = `\nThis task depends on the following tasks:\n${dependentTasks 395 | .map((t) => `- Task ${t.id}: ${t.title} - ${t.description}`) 396 | .join('\n')}`; 397 | 398 | // Add dependency chain information (what these tasks depend on) 399 | const dependencyChains = []; 400 | for (const depTask of dependentTasks) { 401 | if (depTask.dependencies && depTask.dependencies.length > 0) { 402 | const subDeps = depTask.dependencies.map((subDepId) => { 403 | const subDepTask = data.tasks.find((t) => t.id === subDepId); 404 | return subDepTask 405 | ? `Task ${subDepId}: ${subDepTask.title}` 406 | : `Task ${subDepId}`; 407 | }); 408 | dependencyChains.push( 409 | `Task ${depTask.id} depends on: ${subDeps.join(', ')}` 410 | ); 411 | } 412 | } 413 | 414 | if (dependencyChains.length > 0) { 415 | contextTasks += `\n\nDependency chains:\n${dependencyChains.join('\n')}`; 416 | } 417 | 418 | // Show dependency chains in CLI mode 419 | if (outputFormat === 'text' && dependentTasks.length > 0) { 420 | console.log(chalk.gray(` Explicitly specified dependencies:`)); 421 | dependentTasks.forEach((t) => { 422 | console.log(chalk.yellow(` • Task ${t.id}: ${truncate(t.title, 50)}`)); 423 | }); 424 | 425 | if (dependencyChains.length > 0) { 426 | console.log(chalk.gray(`\n Analyzing dependency chains:`)); 427 | dependencyChains.forEach((chain) => { 428 | console.log(chalk.cyan(` • ${truncate(chain, 60)}`)); 429 | }); 430 | } 431 | console.log(); // Add spacing 432 | } 433 | } else { 434 | // If no dependencies provided, show recent and related tasks 435 | // Get recent tasks (newest first) 436 | const recentTasks = [...data.tasks].sort((a, b) => b.id - a.id).slice(0, 5); 437 | 438 | // Get tasks that might be related based on simple keyword matching 439 | const keywords = prompt 440 | .toLowerCase() 441 | .split(/\s+/) 442 | .filter( 443 | (word) => 444 | word.length > 4 && 445 | !['the', 'and', 'that', 'with', 'this', 'for', 'from'].includes(word) 446 | ); 447 | 448 | const relatedTasks = 449 | keywords.length > 0 450 | ? data.tasks 451 | .filter( 452 | (t) => 453 | keywords.some( 454 | (keyword) => 455 | t.title.toLowerCase().includes(keyword) || 456 | t.description.toLowerCase().includes(keyword) 457 | ) && !recentTasks.some((rt) => rt.id === t.id) 458 | ) 459 | .slice(0, 3) 460 | : []; 461 | 462 | if (recentTasks.length > 0) { 463 | contextTasks = `\nRecent tasks in the project:\n${recentTasks 464 | .map((t) => `- Task ${t.id}: ${t.title} - ${t.description}`) 465 | .join('\n')}`; 466 | } 467 | 468 | if (relatedTasks.length > 0) { 469 | contextTasks += `\n\nPotentially related tasks based on keywords:\n${relatedTasks 470 | .map((t) => `- Task ${t.id}: ${t.title} - ${t.description}`) 471 | .join('\n')}`; 472 | } 473 | 474 | // Add a concise view of the task dependency structure 475 | contextTasks += '\n\nSummary of task dependencies in the project:'; 476 | const pendingTasks = data.tasks.filter((t) => t.status !== 'done').slice(-10); 477 | for (const task of pendingTasks) { 478 | const depsStr = 479 | task.dependencies && task.dependencies.length > 0 480 | ? task.dependencies.join(', ') 481 | : 'None'; 482 | contextTasks += `\n- Task ${task.id}: depends on [${depsStr}]`; 483 | } 484 | 485 | // Show keyword-based analysis in CLI mode 486 | if (outputFormat === 'text') { 487 | if (keywords.length > 0) { 488 | console.log( 489 | chalk.gray(` Keywords extracted for analysis: ${keywords.join(', ')}`) 490 | ); 491 | 492 | if (relatedTasks.length > 0) { 493 | console.log( 494 | chalk.gray(`\n Potentially related tasks by keyword match:`) 495 | ); 496 | relatedTasks.forEach((t) => { 497 | console.log( 498 | chalk.yellow(` • Task ${t.id}: ${truncate(t.title, 50)}`) 499 | ); 500 | }); 501 | } 502 | } 503 | 504 | // Show the recent tasks used for context 505 | if (recentTasks.length > 0) { 506 | console.log(chalk.gray(`\n Using recent tasks for context:`)); 507 | recentTasks.slice(0, 3).forEach((t) => { 508 | console.log(chalk.cyan(` • Task ${t.id}: ${truncate(t.title, 50)}`)); 509 | }); 510 | } 511 | 512 | // Show dependency structure visualization 513 | if (pendingTasks.length > 0) { 514 | const depsToShow = Math.min(3, pendingTasks.length); 515 | console.log( 516 | chalk.gray( 517 | `\n Task dependency patterns analyzed (${depsToShow} example${depsToShow > 1 ? 's' : ''}):` 518 | ) 519 | ); 520 | pendingTasks.slice(0, depsToShow).forEach((task) => { 521 | const depsStr = 522 | task.dependencies && task.dependencies.length > 0 523 | ? chalk.yellow(task.dependencies.join(', ')) 524 | : chalk.gray('None'); 525 | console.log(chalk.blue(` • Task ${task.id} → [${depsStr}]`)); 526 | }); 527 | } 528 | console.log(); // Add spacing 529 | } 530 | } 531 | 532 | // System Prompt - Enhanced for dependency awareness 533 | // ... existing code ... 534 | ``` 535 | 536 | Now let's also add a visual indicator before the AI call to make the transition clearer and make the experience more engaging: 537 | 538 | ```javascript 539 | // ... existing code ... 540 | console.log(); // Add spacing 541 | } 542 | } 543 | 544 | // System Prompt - Enhanced for dependency awareness 545 | const systemPrompt = 546 | "You are a helpful assistant that creates well-structured tasks for a software development project. Generate a single new task based on the user's description, adhering strictly to the provided JSON schema. Pay special attention to dependencies between tasks, ensuring the new task correctly references any tasks it depends on."; 547 | 548 | // Task Structure Description (for user prompt) 549 | const taskStructureDesc = ` 550 | { 551 | "title": "Task title goes here", 552 | "description": "A concise one or two sentence description of what the task involves", 553 | "details": "In-depth implementation details, considerations, and guidance.", 554 | "testStrategy": "Detailed approach for verifying task completion.", 555 | "dependencies": [1, 2, 3] // Optional: Array of existing task IDs that this task depends on 556 | }`; 557 | 558 | // Add any manually provided details to the prompt for context 559 | let contextFromArgs = ''; 560 | if (manualTaskData?.title) 561 | contextFromArgs += `\n- Suggested Title: "${manualTaskData.title}"`; 562 | if (manualTaskData?.description) 563 | contextFromArgs += `\n- Suggested Description: "${manualTaskData.description}"`; 564 | if (manualTaskData?.details) 565 | contextFromArgs += `\n- Additional Details Context: "${manualTaskData.details}"`; 566 | if (manualTaskData?.testStrategy) 567 | contextFromArgs += `\n- Additional Test Strategy Context: "${manualTaskData.testStrategy}"`; 568 | 569 | // User Prompt 570 | const userPrompt = `You are generating the details for Task #${newTaskId}. Based on the user's request: "${prompt}", create a comprehensive new task for a software development project. 571 | 572 | ${contextTasks} 573 | ${contextFromArgs ? `\nConsider these additional details provided by the user:${contextFromArgs}` : ''} 574 | 575 | Based on the information about existing tasks and their dependencies, include appropriate dependencies in the "dependencies" array if any are needed. Only include task IDs that this new task directly depends on. 576 | 577 | Return your answer as a single JSON object matching the schema precisely: 578 | ${taskStructureDesc} 579 | 580 | Make sure the details and test strategy are thorough and specific. Don't include the task ID in the title.`; 581 | 582 | // Start the loading indicator - only for text mode 583 | if (outputFormat === 'text') { 584 | // Add a visual transition to show we're moving to AI generation 585 | console.log(boxen( 586 | chalk.white.bold('AI Task Generation') + 587 | `\n\n${chalk.gray('Analyzing context and generating task details using AI...')}` + 588 | `\n${chalk.cyan('Context size: ')}${chalk.yellow(contextTasks.length.toLocaleString())} characters` + 589 | `\n${chalk.cyan('Dependency detection: ')}${chalk.yellow(numericDependencies.length > 0 ? 'Explicit dependencies' : 'Auto-discovery mode')}`, 590 | { 591 | padding: 1, 592 | borderColor: 'blue', 593 | borderStyle: 'round', 594 | margin: { top: 0, bottom: 1 } 595 | } 596 | )); 597 | 598 | loadingIndicator = startLoadingIndicator( 599 | `Generating new task with ${useResearch ? 'Research' : 'Main'} AI...\n` 600 | ); 601 | } 602 | 603 | try { 604 | // ... existing code ... 605 | ``` 606 | 607 | Finally, let's enhance the success message to highlight the AI's dependency analysis and any dependencies added by the AI: 608 | 609 | ```javascript 610 | // ... existing code ... 611 | truncate(newTask.description, 47) 612 | ]); 613 | 614 | console.log(chalk.green('✅ New task created successfully:')); 615 | console.log(table.toString()); 616 | 617 | // Helper to get priority color 618 | const getPriorityColor = (p) => { 619 | switch (p?.toLowerCase()) { 620 | case 'high': 621 | return 'red'; 622 | case 'low': 623 | return 'gray'; 624 | case 'medium': 625 | default: 626 | return 'yellow'; 627 | } 628 | }; 629 | 630 | // Check if AI added new dependencies that weren't explicitly provided 631 | const aiAddedDeps = newTask.dependencies.filter( 632 | dep => !numericDependencies.includes(dep) 633 | ); 634 | 635 | // Show success message box 636 | console.log( 637 | boxen( 638 | chalk.white.bold(`Task ${newTaskId} Created Successfully`) + 639 | '\n\n' + 640 | chalk.white(`Title: ${newTask.title}`) + 641 | '\n' + 642 | chalk.white(`Status: ${getStatusWithColor(newTask.status)}`) + 643 | '\n' + 644 | chalk.white( 645 | `Priority: ${chalk[getPriorityColor(newTask.priority)](newTask.priority)}` 646 | ) + 647 | '\n' + 648 | (newTask.dependencies.length > 0 649 | ? chalk.white(`Dependencies: ${newTask.dependencies.join(', ')}`) + 650 | (aiAddedDeps.length > 0 651 | ? chalk.gray(` (${aiAddedDeps.length} auto-detected by AI)`) 652 | : '') + 653 | '\n' 654 | : '') + 655 | '\n' + 656 | chalk.white.bold('Next Steps:') + 657 | '\n' + 658 | // ... existing code ... 659 | ``` 660 | 661 | Let's test the changes to see our enhanced CLI experience in action: 662 | 663 | --- 664 | 665 | **User** 666 | 667 | it seems to have worked, but its now the second task that used 1 and 3 as dependencies. across 90 tasks, i find that a bit odd (but not impossible as most tasks are in fact net new) 668 | 669 | let's, for the sake of research, also include the details of the other tasks. let's see what happens with the context size 670 | 671 | --- 672 | 673 | **Cursor** 674 | 675 | I agree it's interesting that the AI consistently selects tasks 1 and 3 as dependencies. It found these tasks through the keyword matching (showing "Task 1: Implement Task Data Structure" and "Task 3: Implement Basic Task Operations"), but we should provide more comprehensive context to help it make better dependency selections. 676 | 677 | Let's enhance the task context by including task details for relevant tasks, not just their titles and descriptions: 678 | 679 | ```javascript 680 | // ... existing code ... 681 | taskMap[t.id] = { 682 | id: t.id, 683 | title: t.title, 684 | description: t.description, 685 | dependencies: t.dependencies || [], 686 | status: t.status 687 | }; 688 | }); 689 | 690 | // CLI-only feedback for the dependency analysis 691 | if (outputFormat === 'text') { 692 | console.log(boxen( 693 | chalk.cyan.bold('Task Context Analysis') + '\n', 694 | { 695 | padding: { top: 0, bottom: 0, left: 1, right: 1 }, 696 | margin: { top: 0, bottom: 0 }, 697 | borderColor: 'cyan', 698 | borderStyle: 'round' 699 | } 700 | )); 701 | } 702 | 703 | if (numericDependencies.length > 0) { 704 | // If specific dependencies were provided, focus on them 705 | const dependentTasks = data.tasks.filter((t) => 706 | numericDependencies.includes(t.id) 707 | ); 708 | contextTasks = `\nThis task depends on the following tasks:\n${dependentTasks 709 | .map((t) => `- Task ${t.id}: ${t.title} - ${t.description}`) 710 | .join('\n')}`; 711 | 712 | // Add more details about each dependency 713 | contextTasks += `\n\nDetailed information about dependencies:`; 714 | for (const depTask of dependentTasks) { 715 | contextTasks += `\n\n------ Task ${depTask.id}: ${depTask.title} ------\n`; 716 | contextTasks += `Description: ${depTask.description}\n`; 717 | contextTasks += `Status: ${depTask.status || 'pending'}\n`; 718 | contextTasks += `Priority: ${depTask.priority || 'medium'}\n`; 719 | // Add implementation details but truncate if too long 720 | if (depTask.details) { 721 | const truncatedDetails = depTask.details.length > 500 722 | ? depTask.details.substring(0, 500) + '... (truncated)' 723 | : depTask.details; 724 | contextTasks += `Implementation Details: ${truncatedDetails}\n`; 725 | } 726 | } 727 | 728 | // Add dependency chain information (what these tasks depend on) 729 | const dependencyChains = []; 730 | for (const depTask of dependentTasks) { 731 | if (depTask.dependencies && depTask.dependencies.length > 0) { 732 | const subDeps = depTask.dependencies.map(subDepId => { 733 | const subDepTask = data.tasks.find(t => t.id === subDepId); 734 | return subDepTask ? `Task ${subDepId}: ${subDepTask.title}` : `Task ${subDepId}`; 735 | }); 736 | dependencyChains.push(`Task ${depTask.id} depends on: ${subDeps.join(', ')}`); 737 | } 738 | } 739 | 740 | if (dependencyChains.length > 0) { 741 | contextTasks += `\n\nDependency chains:\n${dependencyChains.join('\n')}`; 742 | } 743 | 744 | // Show dependency chains in CLI mode 745 | if (outputFormat === 'text' && dependentTasks.length > 0) { 746 | console.log(chalk.gray(` Explicitly specified dependencies:`)); 747 | dependentTasks.forEach(t => { 748 | console.log(chalk.yellow(` • Task ${t.id}: ${truncate(t.title, 50)}`)); 749 | }); 750 | 751 | if (dependencyChains.length > 0) { 752 | console.log(chalk.gray(`\n Analyzing dependency chains:`)); 753 | dependencyChains.forEach(chain => { 754 | console.log(chalk.cyan(` • ${truncate(chain, 60)}`)); 755 | }); 756 | } 757 | console.log(); // Add spacing 758 | } 759 | } else { 760 | // If no dependencies provided, show recent and related tasks 761 | // Get recent tasks (newest first) 762 | const recentTasks = [...data.tasks] 763 | .sort((a, b) => b.id - a.id) 764 | .slice(0, 5); 765 | 766 | // Get tasks that might be related based on simple keyword matching 767 | const keywords = prompt.toLowerCase().split(/\s+/).filter(word => 768 | word.length > 4 && !['the', 'and', 'that', 'with', 'this', 'for', 'from'].includes(word) 769 | ); 770 | 771 | // Get related tasks by keyword matching 772 | const relatedTasks = keywords.length > 0 773 | ? data.tasks.filter(t => 774 | keywords.some(keyword => 775 | t.title.toLowerCase().includes(keyword) || 776 | t.description.toLowerCase().includes(keyword) 777 | ) && 778 | !recentTasks.some(rt => rt.id === t.id) 779 | ).slice(0, 5) // Increased from 3 to 5 780 | : []; 781 | 782 | // Also look for tasks with similar purposes or categories 783 | const purposeCategories = [ 784 | {pattern: /(command|cli|flag)/i, label: "CLI commands"}, 785 | {pattern: /(task|subtask|add)/i, label: "Task management"}, 786 | {pattern: /(dependency|depend)/i, label: "Dependency handling"}, 787 | {pattern: /(AI|model|prompt)/i, label: "AI integration"}, 788 | {pattern: /(UI|display|show)/i, label: "User interface"} 789 | ]; 790 | 791 | const promptCategory = purposeCategories.find(cat => cat.pattern.test(prompt)); 792 | const categoryTasks = promptCategory 793 | ? data.tasks.filter(t => 794 | promptCategory.pattern.test(t.title) || 795 | promptCategory.pattern.test(t.description) || 796 | (t.details && promptCategory.pattern.test(t.details)) 797 | ) 798 | .filter(t => 799 | !recentTasks.some(rt => rt.id === t.id) && 800 | !relatedTasks.some(rt => rt.id === t.id) 801 | ) 802 | .slice(0, 3) 803 | : []; 804 | 805 | // Format basic task overviews 806 | if (recentTasks.length > 0) { 807 | contextTasks = `\nRecent tasks in the project:\n${recentTasks 808 | .map((t) => `- Task ${t.id}: ${t.title} - ${t.description}`) 809 | .join('\n')}`; 810 | } 811 | 812 | if (relatedTasks.length > 0) { 813 | contextTasks += `\n\nPotentially related tasks based on keywords:\n${relatedTasks 814 | .map((t) => `- Task ${t.id}: ${t.title} - ${t.description}`) 815 | .join('\n')}`; 816 | } 817 | 818 | if (categoryTasks.length > 0) { 819 | contextTasks += `\n\nTasks related to ${promptCategory.label}:\n${categoryTasks 820 | .map((t) => `- Task ${t.id}: ${t.title} - ${t.description}`) 821 | .join('\n')}`; 822 | } 823 | 824 | // Add detailed information about the most relevant tasks 825 | const allDetailedTasks = [...relatedTasks, ...categoryTasks.slice(0, 2), ...recentTasks.slice(0, 2)]; 826 | const uniqueDetailedTasks = Array.from(new Map(allDetailedTasks.map(t => [t.id, t])).values()).slice(0, 5); 827 | 828 | if (uniqueDetailedTasks.length > 0) { 829 | contextTasks += `\n\nDetailed information about relevant tasks:`; 830 | for (const task of uniqueDetailedTasks) { 831 | contextTasks += `\n\n------ Task ${task.id}: ${task.title} ------\n`; 832 | contextTasks += `Description: ${task.description}\n`; 833 | contextTasks += `Status: ${task.status || 'pending'}\n`; 834 | contextTasks += `Priority: ${task.priority || 'medium'}\n`; 835 | if (task.dependencies && task.dependencies.length > 0) { 836 | contextTasks += `Dependencies: ${task.dependencies.join(', ')}\n`; 837 | } 838 | // Add implementation details but truncate if too long 839 | if (task.details) { 840 | const truncatedDetails = task.details.length > 400 841 | ? task.details.substring(0, 400) + '... (truncated)' 842 | : task.details; 843 | contextTasks += `Implementation Details: ${truncatedDetails}\n`; 844 | } 845 | } 846 | } 847 | 848 | // Add a concise view of the task dependency structure 849 | contextTasks += '\n\nSummary of task dependencies in the project:'; 850 | 851 | // Focus on pending tasks with the most similar purposes or categories 852 | // This helps identify patterns in how similar tasks are set up 853 | const relevantPendingTasks = promptCategory 854 | ? data.tasks 855 | .filter(t => t.status !== 'done' && (promptCategory.pattern.test(t.title) || promptCategory.pattern.test(t.description))) 856 | .slice(-10) 857 | : data.tasks.filter(t => t.status !== 'done').slice(-10); 858 | 859 | for (const task of relevantPendingTasks) { 860 | const depsStr = task.dependencies && task.dependencies.length > 0 861 | ? task.dependencies.join(', ') 862 | : 'None'; 863 | contextTasks += `\n- Task ${task.id}: depends on [${depsStr}]`; 864 | } 865 | 866 | // Additional analysis of common patterns 867 | const commandTasks = data.tasks.filter(t => /command|cli/i.test(t.title) || /command|cli/i.test(t.description)); 868 | if (commandTasks.length > 0 && /command|cli/i.test(prompt)) { 869 | contextTasks += '\n\nCommon patterns for command implementation tasks:'; 870 | const commandDeps = commandTasks 871 | .filter(t => t.dependencies && t.dependencies.length > 0) 872 | .map(t => t.dependencies) 873 | .flat(); 874 | 875 | // Count frequency of each dependency 876 | const depCounts = {}; 877 | commandDeps.forEach(dep => { 878 | depCounts[dep] = (depCounts[dep] || 0) + 1; 879 | }); 880 | 881 | // Get most common dependencies for command tasks 882 | const commonDeps = Object.entries(depCounts) 883 | .sort((a, b) => b[1] - a[1]) 884 | .slice(0, 3); 885 | 886 | if (commonDeps.length > 0) { 887 | contextTasks += '\nMost common dependencies for similar tasks:'; 888 | commonDeps.forEach(([depId, count]) => { 889 | const depTask = data.tasks.find(t => t.id === parseInt(depId)); 890 | if (depTask) { 891 | contextTasks += `\n- Task ${depId} (used by ${count} similar tasks): ${depTask.title}`; 892 | } 893 | }); 894 | } 895 | } 896 | 897 | // Show keyword-based analysis in CLI mode 898 | if (outputFormat === 'text') { 899 | if (keywords.length > 0) { 900 | console.log(chalk.gray(` Keywords extracted for analysis: ${keywords.join(', ')}`)); 901 | 902 | if (relatedTasks.length > 0) { 903 | console.log(chalk.gray(`\n Potentially related tasks by keyword match:`)); 904 | relatedTasks.forEach(t => { 905 | console.log(chalk.yellow(` • Task ${t.id}: ${truncate(t.title, 50)}`)); 906 | }); 907 | } 908 | } 909 | 910 | if (promptCategory && categoryTasks.length > 0) { 911 | console.log(chalk.gray(`\n Tasks related to ${promptCategory.label}:`)); 912 | categoryTasks.forEach(t => { 913 | console.log(chalk.magenta(` • Task ${t.id}: ${truncate(t.title, 50)}`)); 914 | }); 915 | } 916 | 917 | // Show the recent tasks used for context 918 | if (recentTasks.length > 0) { 919 | console.log(chalk.gray(`\n Using recent tasks for context:`)); 920 | recentTasks.slice(0, 3).forEach(t => { 921 | console.log(chalk.cyan(` • Task ${t.id}: ${truncate(t.title, 50)}`)); 922 | }); 923 | } 924 | 925 | // Show dependency structure visualization 926 | if (relevantPendingTasks.length > 0) { 927 | const depsToShow = Math.min(3, relevantPendingTasks.length); 928 | console.log(chalk.gray(`\n Task dependency patterns analyzed (${depsToShow} example${depsToShow > 1 ? 's' : ''}):`)); 929 | relevantPendingTasks.slice(0, depsToShow).forEach(task => { 930 | const depsStr = task.dependencies && task.dependencies.length > 0 931 | ? chalk.yellow(task.dependencies.join(', ')) 932 | : chalk.gray('None'); 933 | console.log(chalk.blue(` • Task ${task.id} → [${depsStr}]`)); 934 | }); 935 | } 936 | 937 | // Add information about which tasks will be provided in detail 938 | if (uniqueDetailedTasks.length > 0) { 939 | console.log(chalk.gray(`\n Providing detailed context for ${uniqueDetailedTasks.length} most relevant tasks:`)); 940 | uniqueDetailedTasks.forEach(t => { 941 | console.log(chalk.green(` • Task ${t.id}: ${truncate(t.title, 40)}`)); 942 | }); 943 | } 944 | 945 | console.log(); // Add spacing 946 | } 947 | } 948 | 949 | // System Prompt - Enhanced for dependency awareness 950 | // ... existing code ... 951 | ``` 952 | 953 | Now let's modify the task generation display to include context size information and make it more transparent about what's being sent to the AI: 954 | 955 | ```javascript 956 | // ... existing code ... 957 | // Add a visual transition to show we're moving to AI generation 958 | console.log(boxen( 959 | chalk.white.bold('AI Task Generation') + 960 | `\n\n${chalk.gray('Analyzing context and generating task details using AI...')}` + 961 | `\n${chalk.cyan('Context size: ')}${chalk.yellow(contextTasks.length.toLocaleString())} characters` + 962 | `\n${chalk.cyan('Dependency detection: ')}${chalk.yellow(numericDependencies.length > 0 ? 'Explicit dependencies' : 'Auto-discovery mode')}` + 963 | `\n${chalk.cyan('Detailed tasks: ')}${chalk.yellow( 964 | numericDependencies.length > 0 965 | ? dependentTasks.length 966 | : (uniqueDetailedTasks ? uniqueDetailedTasks.length : 0) 967 | )}` + 968 | (promptCategory 969 | ? `\n${chalk.cyan('Task category: ')}${chalk.yellow(promptCategory.label)}` 970 | : '') + 971 | `\n${chalk.cyan('Dependency analysis depth: ')}${chalk.yellow('Full chain analysis')}`, 972 | { 973 | padding: 1, 974 | borderColor: 'blue', 975 | borderStyle: 'round', 976 | margin: { top: 0, bottom: 1 } 977 | } 978 | )); 979 | 980 | loadingIndicator = startLoadingIndicator( 981 | `Generating new task with ${useResearch ? 'Research' : 'Main'} AI...\n` 982 | ); 983 | } 984 | 985 | try { 986 | // ... existing code ... 987 | ``` 988 | 989 | Now, let's update the system prompt to include specific guidance for the AI on how to make better dependency choices: 990 | 991 | ```javascript 992 | // ... existing code ... 993 | // System Prompt - Enhanced for dependency awareness 994 | const systemPrompt = 995 | "You are a helpful assistant that creates well-structured tasks for a software development project. Generate a single new task based on the user's description, adhering strictly to the provided JSON schema. Pay special attention to dependencies between tasks, ensuring the new task correctly references any tasks it depends on.\n\n" + 996 | 'When determining dependencies for a new task, follow these principles:\n' + 997 | '1. Select dependencies based on logical requirements - what must be completed before this task can begin.\n' + 998 | '2. Prioritize task dependencies that are semantically related to the functionality being built.\n' + 999 | '3. Avoid defaulting to early tasks (like tasks #1-3) unless truly necessary foundation work.\n' + 1000 | '4. Consider implementation details of candidate dependent tasks, not just titles.\n' + 1001 | '5. Include the most specific dependencies rather than their parents when appropriate.\n' + 1002 | '6. Focus on technical dependencies rather than organizational ones.'; 1003 | 1004 | // Task Structure Description (for user prompt) 1005 | // ... existing code ... 1006 | ``` 1007 | 1008 | Let's test the enhanced context and dependency analysis: 1009 | 1010 | --- 1011 | 1012 | **User** 1013 | 1014 | error 1015 | 1016 | --- 1017 | 1018 | **Cursor** 1019 | 1020 | I see the error - we're trying to use `uniqueDetailedTasks` in our display, but it's only defined in one code branch. Let's fix that: 1021 | 1022 | ```javascript 1023 | // ... existing code ... 1024 | // CLI-only feedback for the dependency analysis 1025 | if (outputFormat === 'text') { 1026 | console.log(boxen( 1027 | chalk.cyan.bold('Task Context Analysis') + '\n', 1028 | { 1029 | padding: { top: 0, bottom: 0, left: 1, right: 1 }, 1030 | margin: { top: 0, bottom: 0 }, 1031 | borderColor: 'cyan', 1032 | borderStyle: 'round' 1033 | } 1034 | )); 1035 | } 1036 | 1037 | // Initialize variables that will be used in either branch 1038 | let dependentTasks = []; 1039 | let uniqueDetailedTasks = []; 1040 | let promptCategory = null; 1041 | 1042 | if (numericDependencies.length > 0) { 1043 | // If specific dependencies were provided, focus on them 1044 | dependentTasks = data.tasks.filter((t) => 1045 | numericDependencies.includes(t.id) 1046 | ); 1047 | 1048 | // These are our detailed tasks when explicit dependencies are provided 1049 | uniqueDetailedTasks = dependentTasks; 1050 | 1051 | contextTasks = `\nThis task depends on the following tasks:\n${dependentTasks 1052 | .map((t) => `- Task ${t.id}: ${t.title} - ${t.description}`) 1053 | .join('\n')}`; 1054 | // ... existing code ... 1055 | 1056 | // Add a visual transition to show we're moving to AI generation 1057 | console.log(boxen( 1058 | chalk.white.bold('AI Task Generation') + 1059 | `\n\n${chalk.gray('Analyzing context and generating task details using AI...')}` + 1060 | `\n${chalk.cyan('Context size: ')}${chalk.yellow(contextTasks.length.toLocaleString())} characters` + 1061 | `\n${chalk.cyan('Dependency detection: ')}${chalk.yellow(numericDependencies.length > 0 ? 'Explicit dependencies' : 'Auto-discovery mode')}` + 1062 | `\n${chalk.cyan('Detailed tasks: ')}${chalk.yellow(uniqueDetailedTasks.length)}` + 1063 | (promptCategory 1064 | ? `\n${chalk.cyan('Task category: ')}${chalk.yellow(promptCategory.label)}` 1065 | : '') + 1066 | `\n${chalk.cyan('Dependency analysis depth: ')}${chalk.yellow('Full chain analysis')}`, 1067 | // ... existing code ... 1068 | ``` 1069 | 1070 | Let's also fix the variable that's still defined inside the else branch instead of using our initialization: 1071 | 1072 | ```javascript 1073 | // ... existing code ... 1074 | const purposeCategories = [ 1075 | {pattern: /(command|cli|flag)/i, label: "CLI commands"}, 1076 | {pattern: /(task|subtask|add)/i, label: "Task management"}, 1077 | {pattern: /(dependency|depend)/i, label: "Dependency handling"}, 1078 | {pattern: /(AI|model|prompt)/i, label: "AI integration"}, 1079 | {pattern: /(UI|display|show)/i, label: "User interface"} 1080 | ]; 1081 | 1082 | promptCategory = purposeCategories.find(cat => cat.pattern.test(prompt)); 1083 | const categoryTasks = promptCategory 1084 | ? data.tasks.filter(t => 1085 | promptCategory.pattern.test(t.title) || 1086 | promptCategory.pattern.test(t.description) || 1087 | (t.details && promptCategory.pattern.test(t.details)) 1088 | ) 1089 | // ... existing code ... 1090 | ``` 1091 | 1092 | Let's test our fix: 1093 | 1094 | --- 1095 | 1096 | **User** 1097 | 1098 | despite ALL that, we still got 1 and 3 -- does that imply our previous implemenation was fine? 1099 | 1100 | we didnt use that many input tokens so im guessing no other tasks were added as dependencies. idk, maybe the issue is the way the keywords/search is working. it should be more fuzzy/smarter or rely more on the LLM even though we definitely would prefer to do as much as we can here to prepare the same information in smaller/condensed/curated format before passing it 1101 | 1102 | but in the end what really matters is to properly capture dependencies. it's possible we dont actually need to -- you can get the get-tasks tool taht you have access to get ALL tasks and make that determination for yourself so you can do a spot check 1103 | 1104 | --- 1105 | 1106 | **Cursor** 1107 | 1108 | You're right - despite our enhanced context and guidance, the AI still defaulted to those foundational tasks (1 and 3). It's particularly interesting that the output shows "Detailed tasks: 0" even though we were providing detailed information for 5 tasks. 1109 | 1110 | This suggests a few things: 1111 | 1112 | 1. There might still be an issue in how we're tracking `uniqueDetailedTasks` in the code. 1113 | 1114 | 2. The model might have a bias toward those early tasks since they are genuinely foundational (Task 1: "Implement Task Data Structure" and Task 3: "Implement Basic Task Operations"). 1115 | 1116 | 3. Our keyword matching might not be catching the truly relevant semantic connections between tasks. 1117 | 1118 | You've made an excellent point about letting the AI have more direct access to tasks. Here are two approaches we could take: 1119 | 1120 | 1. **AI-assisted pre-processing**: We could use an AI call to identify potential dependencies before the main task creation, specifically to analyze relevance. 1121 | 1122 | 2. **Direct access approach**: As you suggested, we could rely on the AI's ability to access all tasks directly through tools like `get_tasks`. This approach leverages the model's semantic understanding while giving it full access to the data. 1123 | 1124 | Would you like me to implement the fix for the "Detailed tasks: 0" issue, or would you prefer to move toward the direct access approach where the AI uses tools to gather its own context? 1125 | 1126 | --- 1127 | 1128 | **User** 1129 | 1130 | first, do a get-tasks to get that context 1131 | 1132 | --- 1133 | 1134 | **Cursor** 1135 | 1136 | Let me get all the tasks to better understand the context: 1137 | 1138 | --- 1139 | 1140 | **User** 1141 | 1142 | no. use the mcp tool get_tasks 1143 | 1144 | --- 1145 | 1146 | **Cursor** 1147 | 1148 | Let me get the tasks using the MCP tool: 1149 | 1150 | Now, let me get the task details for task ID 88 as you requested: 1151 | 1152 | Looking at the details of task #88 and the issue you mentioned, I'll now examine the current dependency handling in add-task.js: 1153 | 1154 | Let me examine more of the file to understand how dependencies are handled in the final part: 1155 | 1156 | Based on my analysis of the code and Task #88's requirements, let me identify how we can enhance the add-task functionality to better consider all task dependencies. Here's what I've found: 1157 | 1158 | 1. **Current Implementation**: 1159 | 1160 | - The add-task feature mainly considers explicitly provided dependencies (via CLI flags) or AI-suggested dependencies 1161 | - It provides some context to the AI about dependency chains when explicit dependencies are provided 1162 | - It does surface information about tasks with similar keywords, categories, or recent tasks when no explicit dependencies are provided 1163 | - It has logic to validate dependencies and remove invalid ones 1164 | 1165 | 2. **Areas for Improvement**: 1166 | - The current implementation doesn't recursively analyze the dependency structure beyond one level 1167 | - When determining new task dependencies, it doesn't analyze how dependencies of dependencies might affect the new task 1168 | - It could provide more comprehensive dependency chain information to the AI model 1169 | - The system could better detect and suggest indirect dependencies automatically 1170 | 1171 | Let me implement these improvements to enhance the add-task functionality: 1172 | 1173 | ```javascript 1174 | // ... existing code ... 1175 | 1176 | // Create a consistent logFn object regardless of context 1177 | const logFn = isMCP 1178 | ? mcpLog // Use MCP logger if provided 1179 | : { 1180 | // Create a wrapper around consoleLog for CLI 1181 | info: (...args) => consoleLog('info', ...args), 1182 | warn: (...args) => consoleLog('warn', ...args), 1183 | error: (...args) => consoleLog('error', ...args), 1184 | debug: (...args) => consoleLog('debug', ...args), 1185 | success: (...args) => consoleLog('success', ...args) 1186 | }; 1187 | 1188 | const effectivePriority = priority || getDefaultPriority(projectRoot); 1189 | 1190 | logFn.info( 1191 | `Adding new task with prompt: "${prompt}", Priority: ${effectivePriority}, Dependencies: ${dependencies.join(', ') || 'None'}, Research: ${useResearch}, ProjectRoot: ${projectRoot}` 1192 | ); 1193 | 1194 | let loadingIndicator = null; 1195 | let aiServiceResponse = null; // To store the full response from AI service 1196 | 1197 | // Create custom reporter that checks for MCP log 1198 | const report = (message, level = 'info') => { 1199 | if (mcpLog) { 1200 | mcpLog[level](message); 1201 | } else if (outputFormat === 'text') { 1202 | consoleLog(level, message); 1203 | } 1204 | }; 1205 | 1206 | /** 1207 | * Recursively builds a dependency graph for a given task 1208 | * @param {Array} tasks - All tasks from tasks.json 1209 | * @param {number} taskId - ID of the task to analyze 1210 | * @param {Set} visited - Set of already visited task IDs 1211 | * @param {Map} depthMap - Map of task ID to its depth in the graph 1212 | * @param {number} depth - Current depth in the recursion 1213 | * @return {Object} Dependency graph data 1214 | */ 1215 | function buildDependencyGraph(tasks, taskId, visited = new Set(), depthMap = new Map(), depth = 0) { 1216 | // Skip if we've already visited this task or it doesn't exist 1217 | if (visited.has(taskId)) { 1218 | return null; 1219 | } 1220 | 1221 | // Find the task 1222 | const task = tasks.find(t => t.id === taskId); 1223 | if (!task) { 1224 | return null; 1225 | } 1226 | 1227 | // Mark as visited 1228 | visited.add(taskId); 1229 | 1230 | // Update depth if this is a deeper path to this task 1231 | if (!depthMap.has(taskId) || depth < depthMap.get(taskId)) { 1232 | depthMap.set(taskId, depth); 1233 | } 1234 | 1235 | // Process dependencies 1236 | const dependencyData = []; 1237 | if (task.dependencies && task.dependencies.length > 0) { 1238 | for (const depId of task.dependencies) { 1239 | const depData = buildDependencyGraph(tasks, depId, visited, depthMap, depth + 1); 1240 | if (depData) { 1241 | dependencyData.push(depData); 1242 | } 1243 | } 1244 | } 1245 | 1246 | return { 1247 | id: task.id, 1248 | title: task.title, 1249 | description: task.description, 1250 | status: task.status, 1251 | dependencies: dependencyData 1252 | }; 1253 | } 1254 | 1255 | try { 1256 | // Read the existing tasks 1257 | const data = readJSON(tasksPath); 1258 | if (!data || !data.tasks) { 1259 | report('Invalid or missing tasks.json.', 'error'); 1260 | throw new Error('Invalid or missing tasks.json.'); 1261 | } 1262 | 1263 | // Find the highest task ID to determine the next ID 1264 | const highestId = 1265 | data.tasks.length > 0 ? Math.max(...data.tasks.map((t) => t.id)) : 0; 1266 | const newTaskId = highestId + 1; 1267 | 1268 | // Only show UI box for CLI mode 1269 | if (outputFormat === 'text') { 1270 | console.log( 1271 | boxen(chalk.white.bold(`Creating New Task #${newTaskId}`), { 1272 | padding: 1, 1273 | borderColor: 'blue', 1274 | borderStyle: 'round', 1275 | margin: { top: 1, bottom: 1 } 1276 | }) 1277 | ); 1278 | } 1279 | 1280 | // Validate dependencies before proceeding 1281 | const invalidDeps = dependencies.filter((depId) => { 1282 | // Ensure depId is parsed as a number for comparison 1283 | const numDepId = parseInt(depId, 10); 1284 | return isNaN(numDepId) || !data.tasks.some((t) => t.id === numDepId); 1285 | }); 1286 | 1287 | if (invalidDeps.length > 0) { 1288 | report( 1289 | `The following dependencies do not exist or are invalid: ${invalidDeps.join(', ')}`, 1290 | 'warn' 1291 | ); 1292 | report('Removing invalid dependencies...', 'info'); 1293 | dependencies = dependencies.filter( 1294 | (depId) => !invalidDeps.includes(depId) 1295 | ); 1296 | } 1297 | // Ensure dependencies are numbers 1298 | const numericDependencies = dependencies.map((dep) => parseInt(dep, 10)); 1299 | 1300 | // Build dependency graphs for explicitly specified dependencies 1301 | const dependencyGraphs = []; 1302 | const allRelatedTaskIds = new Set(); 1303 | const depthMap = new Map(); 1304 | 1305 | // First pass: build a complete dependency graph for each specified dependency 1306 | for (const depId of numericDependencies) { 1307 | const graph = buildDependencyGraph(data.tasks, depId, new Set(), depthMap); 1308 | if (graph) { 1309 | dependencyGraphs.push(graph); 1310 | } 1311 | } 1312 | 1313 | // Second pass: build a set of all related task IDs for flat analysis 1314 | for (const [taskId, depth] of depthMap.entries()) { 1315 | allRelatedTaskIds.add(taskId); 1316 | } 1317 | 1318 | let taskData; 1319 | 1320 | // Check if manual task data is provided 1321 | if (manualTaskData) { 1322 | report('Using manually provided task data', 'info'); 1323 | taskData = manualTaskData; 1324 | report('DEBUG: Taking MANUAL task data path.', 'debug'); 1325 | 1326 | // Basic validation for manual data 1327 | if ( 1328 | !taskData.title || 1329 | typeof taskData.title !== 'string' || 1330 | !taskData.description || 1331 | typeof taskData.description !== 'string' 1332 | ) { 1333 | throw new Error( 1334 | 'Manual task data must include at least a title and description.' 1335 | ); 1336 | } 1337 | } else { 1338 | report('DEBUG: Taking AI task generation path.', 'debug'); 1339 | // --- Refactored AI Interaction --- 1340 | report(`Generating task data with AI with prompt:\n${prompt}`, 'info'); 1341 | 1342 | // Create context string for task creation prompt 1343 | let contextTasks = ''; 1344 | 1345 | // Create a dependency map for better understanding of the task relationships 1346 | const taskMap = {}; 1347 | data.tasks.forEach(t => { 1348 | // For each task, only include id, title, description, and dependencies 1349 | taskMap[t.id] = { 1350 | id: t.id, 1351 | title: t.title, 1352 | description: t.description, 1353 | dependencies: t.dependencies || [], 1354 | status: t.status 1355 | }; 1356 | }); 1357 | 1358 | // CLI-only feedback for the dependency analysis 1359 | if (outputFormat === 'text') { 1360 | console.log(boxen( 1361 | chalk.cyan.bold('Task Context Analysis') + '\n', 1362 | { 1363 | padding: { top: 0, bottom: 0, left: 1, right: 1 }, 1364 | margin: { top: 0, bottom: 0 }, 1365 | borderColor: 'cyan', 1366 | borderStyle: 'round' 1367 | } 1368 | )); 1369 | } 1370 | 1371 | // Initialize variables that will be used in either branch 1372 | let dependentTasks = []; 1373 | let uniqueDetailedTasks = []; 1374 | let promptCategory = null; 1375 | 1376 | if (numericDependencies.length > 0) { 1377 | // If specific dependencies were provided, focus on them 1378 | // Get all tasks that were found in the dependency graph 1379 | dependentTasks = Array.from(allRelatedTaskIds).map(id => 1380 | data.tasks.find(t => t.id === id) 1381 | ).filter(Boolean); 1382 | 1383 | // Sort by depth in the dependency chain 1384 | dependentTasks.sort((a, b) => { 1385 | const depthA = depthMap.get(a.id) || 0; 1386 | const depthB = depthMap.get(b.id) || 0; 1387 | return depthA - depthB; // Lowest depth (root dependencies) first 1388 | }); 1389 | 1390 | // Limit the number of detailed tasks to avoid context explosion 1391 | uniqueDetailedTasks = dependentTasks.slice(0, 8); 1392 | 1393 | contextTasks = `\nThis task relates to a dependency structure with ${dependentTasks.length} related tasks in the chain.\n\nDirect dependencies:`; 1394 | const directDeps = data.tasks.filter(t => numericDependencies.includes(t.id)); 1395 | contextTasks += `\n${directDeps.map(t => `- Task ${t.id}: ${t.title} - ${t.description}`).join('\n')}`; 1396 | 1397 | // Add an overview of indirect dependencies if present 1398 | const indirectDeps = dependentTasks.filter(t => !numericDependencies.includes(t.id)); 1399 | if (indirectDeps.length > 0) { 1400 | contextTasks += `\n\nIndirect dependencies (dependencies of dependencies):`; 1401 | contextTasks += `\n${indirectDeps.slice(0, 5).map(t => `- Task ${t.id}: ${t.title} - ${t.description}`).join('\n')}`; 1402 | if (indirectDeps.length > 5) { 1403 | contextTasks += `\n- ... and ${indirectDeps.length - 5} more indirect dependencies`; 1404 | } 1405 | } 1406 | 1407 | // Add more details about each dependency, prioritizing direct dependencies 1408 | contextTasks += `\n\nDetailed information about dependencies:`; 1409 | for (const depTask of uniqueDetailedTasks) { 1410 | const depthInfo = depthMap.get(depTask.id) ? ` (depth: ${depthMap.get(depTask.id)})` : ''; 1411 | const isDirect = numericDependencies.includes(depTask.id) ? " [DIRECT DEPENDENCY]" : ""; 1412 | 1413 | contextTasks += `\n\n------ Task ${depTask.id}${isDirect}${depthInfo}: ${depTask.title} ------\n`; 1414 | contextTasks += `Description: ${depTask.description}\n`; 1415 | contextTasks += `Status: ${depTask.status || 'pending'}\n`; 1416 | contextTasks += `Priority: ${depTask.priority || 'medium'}\n`; 1417 | 1418 | // List its dependencies 1419 | if (depTask.dependencies && depTask.dependencies.length > 0) { 1420 | const depDeps = depTask.dependencies.map(dId => { 1421 | const depDepTask = data.tasks.find(t => t.id === dId); 1422 | return depDepTask ? `Task ${dId}: ${depDepTask.title}` : `Task ${dId}`; 1423 | }); 1424 | contextTasks += `Dependencies: ${depDeps.join(', ')}\n`; 1425 | } else { 1426 | contextTasks += `Dependencies: None\n`; 1427 | } 1428 | 1429 | // Add implementation details but truncate if too long 1430 | if (depTask.details) { 1431 | const truncatedDetails = depTask.details.length > 400 1432 | ? depTask.details.substring(0, 400) + '... (truncated)' 1433 | : depTask.details; 1434 | contextTasks += `Implementation Details: ${truncatedDetails}\n`; 1435 | } 1436 | } 1437 | 1438 | // Add dependency chain visualization 1439 | if (dependencyGraphs.length > 0) { 1440 | contextTasks += '\n\nDependency Chain Visualization:'; 1441 | 1442 | // Helper function to format dependency chain as text 1443 | function formatDependencyChain(node, prefix = '', isLast = true, depth = 0) { 1444 | if (depth > 3) return ''; // Limit depth to avoid excessive nesting 1445 | 1446 | const connector = isLast ? '└── ' : '├── '; 1447 | const childPrefix = isLast ? ' ' : '│ '; 1448 | 1449 | let result = `\n${prefix}${connector}Task ${node.id}: ${node.title}`; 1450 | 1451 | if (node.dependencies && node.dependencies.length > 0) { 1452 | for (let i = 0; i < node.dependencies.length; i++) { 1453 | const isLastChild = i === node.dependencies.length - 1; 1454 | result += formatDependencyChain( 1455 | node.dependencies[i], 1456 | prefix + childPrefix, 1457 | isLastChild, 1458 | depth + 1 1459 | ); 1460 | } 1461 | } 1462 | 1463 | return result; 1464 | } 1465 | 1466 | // Format each dependency graph 1467 | for (const graph of dependencyGraphs) { 1468 | contextTasks += formatDependencyChain(graph); 1469 | } 1470 | } 1471 | 1472 | // Show dependency analysis in CLI mode 1473 | if (outputFormat === 'text') { 1474 | if (directDeps.length > 0) { 1475 | console.log(chalk.gray(` Explicitly specified dependencies:`)); 1476 | directDeps.forEach(t => { 1477 | console.log(chalk.yellow(` • Task ${t.id}: ${truncate(t.title, 50)}`)); 1478 | }); 1479 | } 1480 | 1481 | if (indirectDeps.length > 0) { 1482 | console.log(chalk.gray(`\n Indirect dependencies (${indirectDeps.length} total):`)); 1483 | indirectDeps.slice(0, 3).forEach(t => { 1484 | const depth = depthMap.get(t.id) || 0; 1485 | console.log(chalk.cyan(` • Task ${t.id} [depth ${depth}]: ${truncate(t.title, 45)}`)); 1486 | }); 1487 | if (indirectDeps.length > 3) { 1488 | console.log(chalk.cyan(` • ... and ${indirectDeps.length - 3} more indirect dependencies`)); 1489 | } 1490 | } 1491 | 1492 | // Visualize the dependency chain 1493 | if (dependencyGraphs.length > 0) { 1494 | console.log(chalk.gray(`\n Dependency chain visualization:`)); 1495 | 1496 | // Convert dependency graph to ASCII art for terminal 1497 | function visualizeDependencyGraph(node, prefix = '', isLast = true, depth = 0) { 1498 | if (depth > 2) return; // Limit depth for display 1499 | 1500 | const connector = isLast ? '└── ' : '├── '; 1501 | const childPrefix = isLast ? ' ' : '│ '; 1502 | 1503 | console.log(chalk.blue(` ${prefix}${connector}Task ${node.id}: ${truncate(node.title, 40)}`)); 1504 | 1505 | if (node.dependencies && node.dependencies.length > 0) { 1506 | for (let i = 0; i < node.dependencies.length; i++) { 1507 | const isLastChild = i === node.dependencies.length - 1; 1508 | visualizeDependencyGraph( 1509 | node.dependencies[i], 1510 | prefix + childPrefix, 1511 | isLastChild, 1512 | depth + 1 1513 | ); 1514 | } 1515 | } 1516 | } 1517 | 1518 | // Visualize each dependency graph 1519 | for (const graph of dependencyGraphs) { 1520 | visualizeDependencyGraph(graph); 1521 | } 1522 | } 1523 | 1524 | console.log(); // Add spacing 1525 | } 1526 | } else { 1527 | // ... existing code ... 1528 | } 1529 | 1530 | // ... existing code ... 1531 | 1532 | // Create the new task object 1533 | const newTask = { 1534 | id: newTaskId, 1535 | title: taskData.title, 1536 | description: taskData.description, 1537 | details: taskData.details || '', 1538 | testStrategy: taskData.testStrategy || '', 1539 | status: 'pending', 1540 | dependencies: taskData.dependencies?.length ? taskData.dependencies : numericDependencies, // Use AI-suggested dependencies if available, fallback to manually specified 1541 | priority: effectivePriority, 1542 | subtasks: [] // Initialize with empty subtasks array 1543 | }; 1544 | 1545 | // Additional check: validate all dependencies in the AI response 1546 | if (taskData.dependencies?.length) { 1547 | const allValidDeps = taskData.dependencies.every(depId => { 1548 | const numDepId = parseInt(depId, 10); 1549 | return !isNaN(numDepId) && data.tasks.some(t => t.id === numDepId); 1550 | }); 1551 | 1552 | if (!allValidDeps) { 1553 | report('AI suggested invalid dependencies. Filtering them out...', 'warn'); 1554 | newTask.dependencies = taskData.dependencies.filter(depId => { 1555 | const numDepId = parseInt(depId, 10); 1556 | return !isNaN(numDepId) && data.tasks.some(t => t.id === numDepId); 1557 | }); 1558 | } 1559 | } 1560 | 1561 | // Add the task to the tasks array 1562 | data.tasks.push(newTask); 1563 | 1564 | // ... existing code ... 1565 | ``` 1566 | 1567 | Now, let's update the system prompt to better guide the AI in making accurate dependency recommendations using the enhanced dependency information we're providing: 1568 | 1569 | ```javascript 1570 | // ... existing code ... 1571 | 1572 | // System Prompt - Enhanced for dependency awareness 1573 | const systemPrompt = 1574 | "You are a helpful assistant that creates well-structured tasks for a software development project. Generate a single new task based on the user's description, adhering strictly to the provided JSON schema. Pay special attention to dependencies between tasks, ensuring the new task correctly references any tasks it depends on.\n\n" + 1575 | 'When determining dependencies for a new task, follow these principles:\n' + 1576 | '1. Select dependencies based on logical requirements - what must be completed before this task can begin.\n' + 1577 | '2. Prioritize task dependencies that are semantically related to the functionality being built.\n' + 1578 | '3. Avoid defaulting to early tasks (like tasks #1-3) unless truly necessary foundation work.\n' + 1579 | '4. Consider implementation details of candidate dependent tasks, not just titles.\n' + 1580 | '5. Include the most specific dependencies rather than their parents when appropriate.\n' + 1581 | '6. Focus on technical dependencies rather than organizational ones.'; 1582 | 1583 | // ... existing code to ... 1584 | 1585 | // System Prompt - Enhanced for comprehensive dependency awareness 1586 | const systemPrompt = 1587 | "You are a helpful assistant that creates well-structured tasks for a software development project. Generate a single new task based on the user's description, adhering strictly to the provided JSON schema. Pay special attention to dependencies between tasks, ensuring the new task correctly references any tasks it depends on.\n\n" + 1588 | 'When determining dependencies for a new task, follow these principles:\n' + 1589 | '1. Select dependencies based on logical requirements - what must be completed before this task can begin.\n' + 1590 | '2. Analyze the entire dependency chain to find the most specific and direct dependencies.\n' + 1591 | '3. Consider both direct and indirect (transitive) dependencies - a task may depend on another task that depends on yet another task.\n' + 1592 | '4. When possible, reference the most specific or leaf-node tasks in a dependency chain rather than their parents.\n' + 1593 | '5. Prioritize task dependencies that are semantically related to the functionality being built.\n' + 1594 | '6. Consider the depth of the dependency chain - tasks deeper in the chain might be more specific.\n' + 1595 | '7. Respect the existing dependency structure in the project to maintain consistency.\n' + 1596 | '8. Avoid defaulting to early foundational tasks (like tasks #1-3) unless absolutely necessary.\n' + 1597 | '9. Consider implementation details of candidate dependent tasks, not just their titles.\n' + 1598 | '10. Balance between too many dependencies (overly constrained) and too few (missing prerequisite work).\n' + 1599 | "11. Pay attention to tasks marked as 'done' vs 'pending' when considering dependencies.\n" + 1600 | '12. Base dependency decisions on technical requirements rather than organizational preferences.'; 1601 | 1602 | // ... existing code ... 1603 | ``` 1604 | 1605 | Now, let's update the user prompt to utilize the enhanced dependency information more effectively: 1606 | 1607 | ```javascript 1608 | // ... existing code ... 1609 | 1610 | // User Prompt 1611 | const userPrompt = `You are generating the details for Task #${newTaskId}. Based on the user's request: "${prompt}", create a comprehensive new task for a software development project. 1612 | 1613 | ${contextTasks} 1614 | ${contextFromArgs ? `\nConsider these additional details provided by the user:${contextFromArgs}` : ''} 1615 | 1616 | Based on the information about existing tasks and their dependencies, include appropriate dependencies in the "dependencies" array if any are needed. Only include task IDs that this new task directly depends on. 1617 | 1618 | Return your answer as a single JSON object matching the schema precisely: 1619 | ${taskStructureDesc} 1620 | 1621 | Make sure the details and test strategy are thorough and specific. Don't include the task ID in the title.`; 1622 | 1623 | // ... existing code to ... 1624 | 1625 | // User Prompt - Enhanced for better dependency analysis 1626 | const userPrompt = `You are generating the details for Task #${newTaskId}. Based on the user's request: "${prompt}", create a comprehensive new task for a software development project. 1627 | 1628 | ${contextTasks} 1629 | ${contextFromArgs ? `\nConsider these additional details provided by the user:${contextFromArgs}` : ''} 1630 | 1631 | Based on the detailed information about existing tasks and their dependency relationships, carefully consider which dependencies this new task should have: 1632 | 1633 | 1. ANALYZE: Review the entire dependency structure provided above, including both direct and indirect dependencies. 1634 | 2. IDENTIFY: Determine which specific existing tasks must be completed before this new task can begin. 1635 | 3. CONSIDER: Think about both technical requirements and logical task ordering. 1636 | 4. DECIDE: Select only the most direct, specific dependencies - avoid including a parent task if you're already including its child task. 1637 | 5. VALIDATE: Ensure all selected dependencies are necessary and sufficient for this task to begin. 1638 | 1639 | Include these carefully selected task IDs in the "dependencies" array of your response. If there are no logical dependencies, return an empty array []. 1640 | 1641 | Return your answer as a single JSON object matching the schema precisely: 1642 | ${taskStructureDesc} 1643 | 1644 | Make sure the details and test strategy are thorough and specific. Don't include the task ID in the title.`; 1645 | 1646 | // ... existing code ... 1647 | ``` 1648 | 1649 | Let's also enhance the CLI output to display dependency information for the newly created task: 1650 | 1651 | ```javascript 1652 | // ... existing code ... 1653 | 1654 | // Check if AI added new dependencies that weren't explicitly provided 1655 | const aiAddedDeps = newTask.dependencies.filter( 1656 | (dep) => !numericDependencies.includes(dep) 1657 | ); 1658 | 1659 | // Show success message box 1660 | console.log( 1661 | boxen( 1662 | chalk.white.bold(`Task ${newTaskId} Created Successfully`) + 1663 | '\n\n' + 1664 | chalk.white(`Title: ${newTask.title}`) + 1665 | '\n' + 1666 | chalk.white(`Status: ${getStatusWithColor(newTask.status)}`) + 1667 | '\n' + 1668 | chalk.white( 1669 | `Priority: ${chalk[getPriorityColor(newTask.priority)](newTask.priority)}` 1670 | ) + 1671 | '\n' + 1672 | (newTask.dependencies.length > 0 1673 | ? chalk.white(`Dependencies: ${newTask.dependencies.join(', ')}`) + 1674 | (aiAddedDeps.length > 0 1675 | ? chalk.gray(` (${aiAddedDeps.length} auto-detected by AI)`) 1676 | : '') + 1677 | '\n' 1678 | : '') + 1679 | '\n' + 1680 | chalk.white.bold('Next Steps:') + 1681 | '\n' + 1682 | chalk.cyan( 1683 | `1. Run ${chalk.yellow(`task-master show ${newTaskId}`)} to see complete task details` 1684 | ) + 1685 | '\n' + 1686 | chalk.cyan( 1687 | `2. Run ${chalk.yellow(`task-master set-status --id=${newTaskId} --status=in-progress`)} to start working on it` 1688 | ) + 1689 | '\n' + 1690 | chalk.cyan( 1691 | `3. Run ${chalk.yellow(`task-master expand --id=${newTaskId}`)} to break it down into subtasks` 1692 | ), 1693 | { padding: 1, borderColor: 'green', borderStyle: 'round' } 1694 | ) 1695 | ); 1696 | 1697 | // ... existing code to ... 1698 | 1699 | // Check if AI added new dependencies that weren't explicitly provided 1700 | const aiAddedDeps = newTask.dependencies.filter( 1701 | (dep) => !numericDependencies.includes(dep) 1702 | ); 1703 | 1704 | // Check if AI removed any dependencies that were explicitly provided 1705 | const aiRemovedDeps = numericDependencies.filter( 1706 | (dep) => !newTask.dependencies.includes(dep) 1707 | ); 1708 | 1709 | // Get task titles for dependencies to display 1710 | const depTitles = {}; 1711 | newTask.dependencies.forEach((dep) => { 1712 | const depTask = data.tasks.find((t) => t.id === dep); 1713 | if (depTask) { 1714 | depTitles[dep] = truncate(depTask.title, 30); 1715 | } 1716 | }); 1717 | 1718 | // Prepare dependency display string 1719 | let dependencyDisplay = ''; 1720 | if (newTask.dependencies.length > 0) { 1721 | dependencyDisplay = chalk.white('Dependencies:') + '\n'; 1722 | newTask.dependencies.forEach((dep) => { 1723 | const isAiAdded = aiAddedDeps.includes(dep); 1724 | const depType = isAiAdded ? chalk.yellow(' (AI suggested)') : ''; 1725 | dependencyDisplay += 1726 | chalk.white(` - ${dep}: ${depTitles[dep] || 'Unknown task'}${depType}`) + 1727 | '\n'; 1728 | }); 1729 | } else { 1730 | dependencyDisplay = chalk.white('Dependencies: None') + '\n'; 1731 | } 1732 | 1733 | // Add info about removed dependencies if any 1734 | if (aiRemovedDeps.length > 0) { 1735 | dependencyDisplay += 1736 | chalk.gray('\nUser-specified dependencies that were not used:') + '\n'; 1737 | aiRemovedDeps.forEach((dep) => { 1738 | const depTask = data.tasks.find((t) => t.id === dep); 1739 | const title = depTask ? truncate(depTask.title, 30) : 'Unknown task'; 1740 | dependencyDisplay += chalk.gray(` - ${dep}: ${title}`) + '\n'; 1741 | }); 1742 | } 1743 | 1744 | // Add dependency analysis summary 1745 | let dependencyAnalysis = ''; 1746 | if (aiAddedDeps.length > 0 || aiRemovedDeps.length > 0) { 1747 | dependencyAnalysis = '\n' + chalk.white.bold('Dependency Analysis:') + '\n'; 1748 | if (aiAddedDeps.length > 0) { 1749 | dependencyAnalysis += 1750 | chalk.green( 1751 | `AI identified ${aiAddedDeps.length} additional dependencies` 1752 | ) + '\n'; 1753 | } 1754 | if (aiRemovedDeps.length > 0) { 1755 | dependencyAnalysis += 1756 | chalk.yellow( 1757 | `AI excluded ${aiRemovedDeps.length} user-provided dependencies` 1758 | ) + '\n'; 1759 | } 1760 | } 1761 | 1762 | // Show success message box 1763 | console.log( 1764 | boxen( 1765 | chalk.white.bold(`Task ${newTaskId} Created Successfully`) + 1766 | '\n\n' + 1767 | chalk.white(`Title: ${newTask.title}`) + 1768 | '\n' + 1769 | chalk.white(`Status: ${getStatusWithColor(newTask.status)}`) + 1770 | '\n' + 1771 | chalk.white( 1772 | `Priority: ${chalk[getPriorityColor(newTask.priority)](newTask.priority)}` 1773 | ) + 1774 | '\n\n' + 1775 | dependencyDisplay + 1776 | dependencyAnalysis + 1777 | '\n' + 1778 | chalk.white.bold('Next Steps:') + 1779 | '\n' + 1780 | chalk.cyan( 1781 | `1. Run ${chalk.yellow(`task-master show ${newTaskId}`)} to see complete task details` 1782 | ) + 1783 | '\n' + 1784 | chalk.cyan( 1785 | `2. Run ${chalk.yellow(`task-master set-status --id=${newTaskId} --status=in-progress`)} to start working on it` 1786 | ) + 1787 | '\n' + 1788 | chalk.cyan( 1789 | `3. Run ${chalk.yellow(`task-master expand --id=${newTaskId}`)} to break it down into subtasks` 1790 | ), 1791 | { padding: 1, borderColor: 'green', borderStyle: 'round' } 1792 | ) 1793 | ); 1794 | 1795 | // ... existing code ... 1796 | ``` 1797 | 1798 | Let's test our changes to see how they improve the task dependency handling: 1799 | ```