centaurus-cli 3.1.2 → 3.1.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (142) hide show
  1. package/dist/cli-adapter.js +689 -155
  2. package/dist/cli-adapter.js.map +1 -1
  3. package/dist/config/defaultConfig.js +1 -4
  4. package/dist/config/defaultConfig.js.map +1 -1
  5. package/dist/config/models.js +6 -0
  6. package/dist/config/models.js.map +1 -1
  7. package/dist/config/slash-commands.js +66 -2
  8. package/dist/config/slash-commands.js.map +1 -1
  9. package/dist/config/types.js +4 -4
  10. package/dist/config/types.js.map +1 -1
  11. package/dist/index.js +36 -0
  12. package/dist/index.js.map +1 -1
  13. package/dist/services/ai-context-injector.js +109 -0
  14. package/dist/services/ai-context-injector.js.map +1 -1
  15. package/dist/services/ai-service-client.js +3 -2
  16. package/dist/services/ai-service-client.js.map +1 -1
  17. package/dist/services/api-client.js.map +1 -1
  18. package/dist/services/background-task-manager.js +59 -0
  19. package/dist/services/background-task-manager.js.map +1 -1
  20. package/dist/services/local-chat-storage.js +2 -0
  21. package/dist/services/local-chat-storage.js.map +1 -1
  22. package/dist/services/skill-storage.js +141 -0
  23. package/dist/services/skill-storage.js.map +1 -0
  24. package/dist/services/sub-agent-manager.js +49 -8
  25. package/dist/services/sub-agent-manager.js.map +1 -1
  26. package/dist/services/warpify-detector.js +17 -5
  27. package/dist/services/warpify-detector.js.map +1 -1
  28. package/dist/tools/background-command.js +5 -2
  29. package/dist/tools/background-command.js.map +1 -1
  30. package/dist/tools/command.js +367 -109
  31. package/dist/tools/command.js.map +1 -1
  32. package/dist/tools/file-ops.js +23 -6
  33. package/dist/tools/file-ops.js.map +1 -1
  34. package/dist/tools/plan-mode.js +184 -336
  35. package/dist/tools/plan-mode.js.map +1 -1
  36. package/dist/tools/sub-agent.js +24 -5
  37. package/dist/tools/sub-agent.js.map +1 -1
  38. package/dist/tools/todo-list.js +157 -0
  39. package/dist/tools/todo-list.js.map +1 -0
  40. package/dist/types/skill.js +30 -0
  41. package/dist/types/skill.js.map +1 -0
  42. package/dist/ui/components/App.js +956 -162
  43. package/dist/ui/components/App.js.map +1 -1
  44. package/dist/ui/components/AuthScreen.js +3 -1
  45. package/dist/ui/components/AuthScreen.js.map +1 -1
  46. package/dist/ui/components/AuthWelcomeScreen.js +3 -1
  47. package/dist/ui/components/AuthWelcomeScreen.js.map +1 -1
  48. package/dist/ui/components/CodeBlock.js +3 -1
  49. package/dist/ui/components/CodeBlock.js.map +1 -1
  50. package/dist/ui/components/CompactShellPreview.js +44 -0
  51. package/dist/ui/components/CompactShellPreview.js.map +1 -0
  52. package/dist/ui/components/ConfigViewer.js +3 -1
  53. package/dist/ui/components/ConfigViewer.js.map +1 -1
  54. package/dist/ui/components/ConfirmPrompt.js +3 -1
  55. package/dist/ui/components/ConfirmPrompt.js.map +1 -1
  56. package/dist/ui/components/ConnectionStatusMessage.js +3 -1
  57. package/dist/ui/components/ConnectionStatusMessage.js.map +1 -1
  58. package/dist/ui/components/DetailedPlanReviewScreen.js +84 -74
  59. package/dist/ui/components/DetailedPlanReviewScreen.js.map +1 -1
  60. package/dist/ui/components/DiffViewer.js +6 -3
  61. package/dist/ui/components/DiffViewer.js.map +1 -1
  62. package/dist/ui/components/FileCreationPreview.js.map +1 -1
  63. package/dist/ui/components/FileTagAutocomplete.js +4 -2
  64. package/dist/ui/components/FileTagAutocomplete.js.map +1 -1
  65. package/dist/ui/components/InputBox.js +243 -40
  66. package/dist/ui/components/InputBox.js.map +1 -1
  67. package/dist/ui/components/InteractiveShell.js +5 -3
  68. package/dist/ui/components/InteractiveShell.js.map +1 -1
  69. package/dist/ui/components/KeyboardHelp.js +4 -1
  70. package/dist/ui/components/KeyboardHelp.js.map +1 -1
  71. package/dist/ui/components/LoadingIndicator.js +3 -1
  72. package/dist/ui/components/LoadingIndicator.js.map +1 -1
  73. package/dist/ui/components/MCPAddScreen.js +63 -13
  74. package/dist/ui/components/MCPAddScreen.js.map +1 -1
  75. package/dist/ui/components/MarkdownRenderer.js +3 -1
  76. package/dist/ui/components/MarkdownRenderer.js.map +1 -1
  77. package/dist/ui/components/MessageDisplay.js +9 -7
  78. package/dist/ui/components/MessageDisplay.js.map +1 -1
  79. package/dist/ui/components/ModelPicker.js +170 -0
  80. package/dist/ui/components/ModelPicker.js.map +1 -0
  81. package/dist/ui/components/MonitorModeAIPanel.js +3 -1
  82. package/dist/ui/components/MonitorModeAIPanel.js.map +1 -1
  83. package/dist/ui/components/PlanAcceptedMessage.js +12 -6
  84. package/dist/ui/components/PlanAcceptedMessage.js.map +1 -1
  85. package/dist/ui/components/PlanQuestionMessage.js +37 -0
  86. package/dist/ui/components/PlanQuestionMessage.js.map +1 -0
  87. package/dist/ui/components/PlanQuestionScreen.js +138 -0
  88. package/dist/ui/components/PlanQuestionScreen.js.map +1 -0
  89. package/dist/ui/components/PlanReviewScreen.js +7 -9
  90. package/dist/ui/components/PlanReviewScreen.js.map +1 -1
  91. package/dist/ui/components/RulesEditorScreen.js +65 -28
  92. package/dist/ui/components/RulesEditorScreen.js.map +1 -1
  93. package/dist/ui/components/SelectPrompt.js +3 -1
  94. package/dist/ui/components/SelectPrompt.js.map +1 -1
  95. package/dist/ui/components/SkillCreatorScreen.js +217 -0
  96. package/dist/ui/components/SkillCreatorScreen.js.map +1 -0
  97. package/dist/ui/components/SlashCommandAutocomplete.js +4 -2
  98. package/dist/ui/components/SlashCommandAutocomplete.js.map +1 -1
  99. package/dist/ui/components/StatusBar.js +4 -2
  100. package/dist/ui/components/StatusBar.js.map +1 -1
  101. package/dist/ui/components/StreamingMessageDisplay.js +5 -3
  102. package/dist/ui/components/StreamingMessageDisplay.js.map +1 -1
  103. package/dist/ui/components/SubAgentListScreen.js +65 -0
  104. package/dist/ui/components/SubAgentListScreen.js.map +1 -0
  105. package/dist/ui/components/SubAgentViewScreen.js +123 -0
  106. package/dist/ui/components/SubAgentViewScreen.js.map +1 -0
  107. package/dist/ui/components/TaskCompletedMessage.js +40 -8
  108. package/dist/ui/components/TaskCompletedMessage.js.map +1 -1
  109. package/dist/ui/components/TaskProgressIndicator.js +6 -4
  110. package/dist/ui/components/TaskProgressIndicator.js.map +1 -1
  111. package/dist/ui/components/TextEditor.js +297 -0
  112. package/dist/ui/components/TextEditor.js.map +1 -0
  113. package/dist/ui/components/TodoListMessage.js +59 -0
  114. package/dist/ui/components/TodoListMessage.js.map +1 -0
  115. package/dist/ui/components/ToolExecutionMessage.js +134 -84
  116. package/dist/ui/components/ToolExecutionMessage.js.map +1 -1
  117. package/dist/ui/components/ToolExecutionStatus.js +3 -1
  118. package/dist/ui/components/ToolExecutionStatus.js.map +1 -1
  119. package/dist/ui/components/WelcomeBanner.js +33 -33
  120. package/dist/ui/components/WelcomeBanner.js.map +1 -1
  121. package/dist/ui/components/WorkflowCreatorScreen.js +5 -3
  122. package/dist/ui/components/WorkflowCreatorScreen.js.map +1 -1
  123. package/dist/ui/theme.js +97 -0
  124. package/dist/ui/theme.js.map +1 -0
  125. package/dist/ui/utils/chat-history-limit.js +247 -0
  126. package/dist/ui/utils/chat-history-limit.js.map +1 -0
  127. package/dist/utils/chat-formatter.js +22 -9
  128. package/dist/utils/chat-formatter.js.map +1 -1
  129. package/dist/utils/git-stats.js +7 -5
  130. package/dist/utils/git-stats.js.map +1 -1
  131. package/dist/utils/input-classifier.js +11 -1
  132. package/dist/utils/input-classifier.js.map +1 -1
  133. package/dist/utils/output-truncation.js +175 -0
  134. package/dist/utils/output-truncation.js.map +1 -0
  135. package/dist/utils/rule-reference-resolver.js +3 -3
  136. package/dist/utils/rule-reference-resolver.js.map +1 -1
  137. package/dist/utils/tunnel-commands-manager.js +134 -0
  138. package/dist/utils/tunnel-commands-manager.js.map +1 -0
  139. package/package.json +91 -90
  140. package/postinstall.js +4 -11
  141. package/dist/ui/components/MultiLineInput.js +0 -255
  142. package/dist/ui/components/MultiLineInput.js.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/ui/components/DetailedPlanReviewScreen.tsx"],"sourcesContent":["/**\r\n * DetailedPlanReviewScreen Component\r\n * \r\n * Enhanced plan approval screen with two visual boxes:\r\n * 1. Task Summary Box - Shows hierarchical task list with subtasks\r\n * 2. Approval Box - Yes/No controls\r\n */\r\n\r\nimport React, { useState, useEffect } from 'react';\r\nimport { Box, Text, useInput, useStdout } from 'ink';\r\nimport { Plan, PlanStep, PlanSubtask } from '../../tools/plan-mode.js';\r\n\r\ninterface DetailedPlanReviewScreenProps {\r\n plan: Plan;\r\n onApprove: () => void;\r\n onEdit: () => void;\r\n}\r\n\r\nexport const DetailedPlanReviewScreen: React.FC<DetailedPlanReviewScreenProps> = ({\r\n plan,\r\n onApprove,\r\n onEdit\r\n}) => {\r\n const { stdout } = useStdout();\r\n const terminalHeight = stdout?.rows || 24;\r\n\r\n // Calculate available height for task list (leave room for header, approval box, etc.)\r\n const headerHeight = 6; // Header box + margins\r\n const approvalBoxHeight = 5; // Approval box + margins\r\n const designSummaryHeight = plan.designSummary ? Math.min(8, plan.designSummary.split('\\n').length + 2) : 0;\r\n const availableTaskHeight = Math.max(8, terminalHeight - headerHeight - approvalBoxHeight - designSummaryHeight - 4);\r\n\r\n // Scroll state for task list\r\n const [scrollOffset, setScrollOffset] = useState(0);\r\n\r\n // Calculate total task list height\r\n const taskListItems: Array<{ type: 'task' | 'subtask'; content: string; status: string }> = [];\r\n plan.steps.forEach((step, taskIndex) => {\r\n const statusIcon = step.status === 'completed' ? '[x]' : '[ ]';\r\n taskListItems.push({\r\n type: 'task',\r\n content: `${taskIndex + 1}. ${step.description}`,\r\n status: statusIcon\r\n });\r\n\r\n step.subtasks?.forEach((subtask, subIndex) => {\r\n const subStatusIcon = subtask.status === 'completed' ? '[x]' : '[ ]';\r\n taskListItems.push({\r\n type: 'subtask',\r\n content: ` ${taskIndex + 1}.${subIndex + 1}. ${subtask.description}`,\r\n status: subStatusIcon\r\n });\r\n });\r\n });\r\n\r\n const maxScroll = Math.max(0, taskListItems.length - availableTaskHeight);\r\n\r\n // Handle keyboard input\r\n useInput((input, key) => {\r\n if (key.return || input.toLowerCase() === 'y') {\r\n onApprove();\r\n } else if (input.toLowerCase() === 'n') {\r\n onEdit();\r\n } else if (key.upArrow) {\r\n setScrollOffset(prev => Math.max(0, prev - 1));\r\n } else if (key.downArrow) {\r\n setScrollOffset(prev => Math.min(maxScroll, prev + 1));\r\n }\r\n });\r\n\r\n // Get visible task items\r\n const visibleItems = taskListItems.slice(scrollOffset, scrollOffset + availableTaskHeight);\r\n const showScrollUp = scrollOffset > 0;\r\n const showScrollDown = scrollOffset < maxScroll;\r\n\r\n // Count totals\r\n const totalTasks = plan.steps.length;\r\n const totalSubtasks = plan.steps.reduce((acc, step) => acc + (step.subtasks?.length || 0), 0);\r\n const totalItems = totalSubtasks > 0 ? totalSubtasks : totalTasks;\r\n\r\n return (\r\n <Box flexDirection=\"column\" paddingX={1} paddingY={0}>\r\n {/* Header */}\r\n <Box\r\n borderStyle=\"double\"\r\n borderColor=\"#ffaa00\"\r\n paddingX={2}\r\n paddingY={0}\r\n marginBottom={1}\r\n >\r\n <Text color=\"#ffaa00\" bold>📋 PLAN REVIEW: </Text>\r\n <Text color=\"#00ccff\" bold>{plan.title}</Text>\r\n </Box>\r\n\r\n {/* Design Summary (collapsible/truncated if too long) */}\r\n {plan.designSummary && (\r\n <Box\r\n flexDirection=\"column\"\r\n borderStyle=\"round\"\r\n borderColor=\"#4a4a4a\"\r\n paddingX={1}\r\n paddingY={0}\r\n marginBottom={1}\r\n >\r\n <Text color=\"#666666\" dimColor>📖 Design Summary:</Text>\r\n <Box marginLeft={1}>\r\n <Text color=\"#888888\" wrap=\"truncate-end\">\r\n {plan.designSummary.length > 300\r\n ? plan.designSummary.substring(0, 300) + '...'\r\n : plan.designSummary}\r\n </Text>\r\n </Box>\r\n </Box>\r\n )}\r\n\r\n {/* Summary */}\r\n {plan.summary && (\r\n <Box marginBottom={1} marginLeft={1}>\r\n <Text color=\"#888888\">{plan.summary}</Text>\r\n </Box>\r\n )}\r\n\r\n {/* Task Summary Box */}\r\n <Box\r\n flexDirection=\"column\"\r\n borderStyle=\"round\"\r\n borderColor=\"#00ccff\"\r\n paddingX={1}\r\n paddingY={0}\r\n marginBottom={1}\r\n >\r\n {/* Tasks Header */}\r\n <Box>\r\n <Text color=\"#00ccff\" bold>📝 Tasks</Text>\r\n <Text color=\"#666666\"> ({totalItems} items in {totalTasks} phases)</Text>\r\n </Box>\r\n\r\n {/* Scroll indicator (up) */}\r\n {showScrollUp && (\r\n <Box justifyContent=\"center\">\r\n <Text color=\"#666666\">↑ scroll up (↑ key)</Text>\r\n </Box>\r\n )}\r\n\r\n {/* Task List */}\r\n <Box flexDirection=\"column\" marginY={0}>\r\n {visibleItems.map((item, index) => {\r\n const isTask = item.type === 'task';\r\n return (\r\n <Box key={scrollOffset + index}>\r\n <Text color={isTask ? '#cccccc' : '#999999'} wrap=\"wrap\">\r\n {item.status} {item.content}\r\n </Text>\r\n </Box>\r\n );\r\n })}\r\n </Box>\r\n\r\n {/* Scroll indicator (down) */}\r\n {showScrollDown && (\r\n <Box justifyContent=\"center\">\r\n <Text color=\"#666666\">↓ scroll down (↓ key)</Text>\r\n </Box>\r\n )}\r\n </Box>\r\n\r\n {/* Approval Box */}\r\n <Box\r\n flexDirection=\"column\"\r\n borderStyle=\"round\"\r\n borderColor=\"#00cc66\"\r\n paddingX={2}\r\n paddingY={0}\r\n >\r\n <Text color=\"#00cc66\" bold>Approve Plan?</Text>\r\n <Box marginTop={0}>\r\n <Box marginRight={4}>\r\n <Text color=\"#888888\">Press </Text>\r\n <Text color=\"#00cc66\" bold>Y</Text>\r\n <Text color=\"#888888\"> or </Text>\r\n <Text color=\"#00cc66\" bold>Enter</Text>\r\n <Text color=\"#888888\"> to approve</Text>\r\n </Box>\r\n <Box>\r\n <Text color=\"#888888\">Press </Text>\r\n <Text color=\"#ff6666\" bold>N</Text>\r\n <Text color=\"#888888\"> to reject</Text>\r\n </Box>\r\n </Box>\r\n </Box>\r\n </Box>\r\n );\r\n};\r\n\r\nexport default DetailedPlanReviewScreen;\r\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../../src/ui/components/DetailedPlanReviewScreen.tsx"],"sourcesContent":["/**\r\n * DetailedPlanReviewScreen Component\r\n * \r\n * Full-screen overlay that shows the plan document + steps + approval bar.\r\n * The outer container is pinned to the terminal height so it never overflows\r\n * and causes Ink to re-render the chat history above.\r\n *\r\n * Layout budget (all heights are exact row counts):\r\n * header: 3 (border top + content + border bottom, double-style)\r\n * steps: variable (border 2 + header 1 + N step lines + optional overflow line)\r\n * approval: 4 (border 2 + 2 content lines)\r\n * margins: 3 (1 below header, 1 below doc/note, 1 below steps)\r\n * padY: 0\r\n * ─────────\r\n * doc gets whatever rows remain. If < 5 rows → hide doc section.\r\n */\r\n\r\nimport React, { useState } from 'react';\r\nimport { Box, Text, useInput, useStdout } from 'ink';\r\nimport { Plan } from '../../tools/plan-mode.js';\r\nimport { useTheme } from '../theme.js';\r\nimport { MarkdownRenderer } from './MarkdownRenderer.js';\r\n\r\ninterface DetailedPlanReviewScreenProps {\r\n plan: Plan;\r\n onApprove: () => void;\r\n onEdit: () => void;\r\n}\r\n\r\nexport const DetailedPlanReviewScreen: React.FC<DetailedPlanReviewScreenProps> = ({\r\n plan,\r\n onApprove,\r\n onEdit\r\n}) => {\r\n const theme = useTheme();\r\n const { stdout } = useStdout();\r\n const terminalHeight = stdout?.rows || 24;\r\n const terminalWidth = stdout?.columns || 80;\r\n\r\n // ── Exact row-budget calculation ────────────────────────────\r\n // Safety buffer: reserve 5 extra rows so content never pushes Ink into\r\n // re-rendering the chat history above this screen.\r\n const SAFETY_BUFFER = 5;\r\n\r\n // Header box: double border = 2 rows for border + 1 row content = 3 rows\r\n const HEADER_ROWS = 3;\r\n\r\n // Steps box: round border = 2 rows + 1 header line + N step lines + optional overflow\r\n const visibleSteps = Math.min(plan.implementationSteps.length, 10);\r\n const hasOverflow = plan.implementationSteps.length > 10;\r\n const STEPS_ROWS = 2 + 1 + visibleSteps + (hasOverflow ? 1 : 0); // border + header + steps + overflow\r\n\r\n // Approval box: round border = 2 rows + 2 content lines = 4\r\n const APPROVAL_ROWS = 4;\r\n\r\n // Margins: 1 after header, 1 after doc/note, 1 after steps\r\n const MARGINS = 3;\r\n\r\n // Total fixed rows (without doc section) + safety buffer\r\n const fixedRows = HEADER_ROWS + STEPS_ROWS + APPROVAL_ROWS + MARGINS + SAFETY_BUFFER;\r\n\r\n // Rows available for the document box (including its own border of 2)\r\n const rawDocBudget = terminalHeight - fixedRows;\r\n\r\n // Doc box overhead: 2 rows for border\r\n const DOC_BOX_OVERHEAD = 2;\r\n const docContentBudget = rawDocBudget - DOC_BOX_OVERHEAD;\r\n\r\n // Show the document section only if we can display at least 5 lines of content\r\n const showDocument = docContentBudget >= 5;\r\n const availableDocHeight = showDocument ? docContentBudget : 0;\r\n\r\n // ── Scroll state ────────────────────────────────────────────\r\n const [scrollOffset, setScrollOffset] = useState(0);\r\n const docLines = plan.document.split('\\n');\r\n const maxScroll = Math.max(0, docLines.length - availableDocHeight);\r\n\r\n useInput((input, key) => {\r\n if (key.return || input.toLowerCase() === 'y') {\r\n onApprove();\r\n } else if (input.toLowerCase() === 'n') {\r\n onEdit();\r\n } else if (key.upArrow) {\r\n setScrollOffset(prev => Math.max(0, prev - 3));\r\n } else if (key.downArrow) {\r\n setScrollOffset(prev => Math.min(maxScroll, prev + 3));\r\n } else if (key.pageDown) {\r\n setScrollOffset(prev => Math.min(maxScroll, prev + availableDocHeight));\r\n } else if (key.pageUp) {\r\n setScrollOffset(prev => Math.max(0, prev - availableDocHeight));\r\n }\r\n });\r\n\r\n const visibleDocContent = docLines.slice(scrollOffset, scrollOffset + availableDocHeight).join('\\n');\r\n const showScrollUp = scrollOffset > 0;\r\n const showScrollDown = scrollOffset < maxScroll;\r\n\r\n // ── Render ──────────────────────────────────────────────────\r\n return (\r\n <Box\r\n flexDirection=\"column\"\r\n paddingX={1}\r\n paddingY={0}\r\n height={terminalHeight}\r\n overflow=\"hidden\"\r\n >\r\n {/* Header */}\r\n <Box\r\n borderStyle=\"double\"\r\n borderColor=\"#ffaa00\"\r\n paddingX={2}\r\n paddingY={0}\r\n marginBottom={1}\r\n >\r\n <Text color=\"#ffaa00\" bold>PLAN REVIEW: </Text>\r\n <Text color={theme.accent} bold>{plan.title}</Text>\r\n </Box>\r\n\r\n {/* Plan Document (scrollable markdown) */}\r\n {showDocument && (\r\n <Box\r\n flexDirection=\"column\"\r\n borderStyle=\"round\"\r\n borderColor=\"#4a4a4a\"\r\n paddingX={1}\r\n paddingY={0}\r\n marginBottom={1}\r\n height={availableDocHeight + DOC_BOX_OVERHEAD}\r\n overflow=\"hidden\"\r\n >\r\n {showScrollUp && (\r\n <Box justifyContent=\"center\">\r\n <Text color=\"#666666\">--- scroll up (arrow keys) ---</Text>\r\n </Box>\r\n )}\r\n\r\n <Box flexDirection=\"column\" height={availableDocHeight}>\r\n <MarkdownRenderer content={visibleDocContent} maxWidth={terminalWidth - 6} />\r\n </Box>\r\n\r\n {showScrollDown && (\r\n <Box justifyContent=\"center\">\r\n <Text color=\"#666666\">--- scroll down (arrow keys) ---</Text>\r\n </Box>\r\n )}\r\n </Box>\r\n )}\r\n\r\n {/* Note when doc is hidden */}\r\n {!showDocument && (\r\n <Box marginBottom={1} marginLeft={1}>\r\n <Text color=\"#666666\" dimColor>Plan document hidden (terminal too small) - resize to view</Text>\r\n </Box>\r\n )}\r\n\r\n {/* Implementation Steps */}\r\n <Box\r\n flexDirection=\"column\"\r\n borderStyle=\"round\"\r\n borderColor={theme.accent}\r\n paddingX={1}\r\n paddingY={0}\r\n marginBottom={1}\r\n >\r\n <Text color={theme.accent} bold>Implementation Steps ({plan.implementationSteps.length} steps)</Text>\r\n <Box flexDirection=\"column\" marginTop={0}>\r\n {plan.implementationSteps.slice(0, 10).map((step) => (\r\n <Box key={step.id}>\r\n <Text color=\"#999999\" wrap=\"truncate-end\">\r\n {\" \"}{step.description.length > terminalWidth - 8\r\n ? step.description.substring(0, terminalWidth - 11) + '...'\r\n : step.description}\r\n </Text>\r\n </Box>\r\n ))}\r\n {hasOverflow && (\r\n <Text color=\"#666666\" dimColor> ... and {plan.implementationSteps.length - 10} more steps</Text>\r\n )}\r\n </Box>\r\n </Box>\r\n\r\n {/* Approval Bar */}\r\n <Box\r\n flexDirection=\"column\"\r\n borderStyle=\"round\"\r\n borderColor=\"#00cc66\"\r\n paddingX={2}\r\n paddingY={0}\r\n >\r\n <Text color=\"#00cc66\" bold>Implement this plan?</Text>\r\n <Box marginTop={0}>\r\n <Box marginRight={4}>\r\n <Text color=\"#888888\">Press </Text>\r\n <Text color=\"#00cc66\" bold>Y</Text>\r\n <Text color=\"#888888\"> or </Text>\r\n <Text color=\"#00cc66\" bold>Enter</Text>\r\n <Text color=\"#888888\"> to implement</Text>\r\n </Box>\r\n <Box>\r\n <Text color=\"#888888\">Press </Text>\r\n <Text color=\"#ff6666\" bold>N</Text>\r\n <Text color=\"#888888\"> to cancel</Text>\r\n </Box>\r\n </Box>\r\n </Box>\r\n </Box>\r\n );\r\n};\r\n\r\nexport default DetailedPlanReviewScreen;\r\n"],"mappings":"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","names":[]}
@@ -39,14 +39,17 @@ const DiffViewer = ({ diff, filePath, fullDiff }) => {
39
39
  lineNum = currentLineNum++;
40
40
  }
41
41
  let style = { color: "white", backgroundColor: void 0 };
42
- if (type === "added") style = { backgroundColor: void 0, color: "green" };
43
- if (type === "deleted") style = { backgroundColor: void 0, color: "red" };
42
+ if (type === "added") style = { color: "#e6e6e6", backgroundColor: "#1e4d2b" };
43
+ if (type === "deleted") style = { color: "#e6e6e6", backgroundColor: "#5c1e1e" };
44
+ const prefix = type === "added" ? "+" : type === "deleted" ? "-" : " ";
44
45
  const lineNumStr = lineNum ? lineNum.toString().padStart(4, " ") : " ";
45
46
  const cleanText = line.startsWith("+") || line.startsWith("-") || line.startsWith(" ") ? line.slice(1) : line;
46
47
  const wrapped = wrapText(cleanText || " ", maxContentWidth, 0);
47
48
  wrapped.forEach((wLine, idx) => {
49
+ const linePrefix = idx === 0 ? prefix : " ";
50
+ const paddedText = `${linePrefix} ${wLine}`.padEnd(maxContentWidth + 2);
48
51
  processedLines.push({
49
- text: wLine,
52
+ text: paddedText,
50
53
  ...style,
51
54
  lineNumStr: idx === 0 ? lineNumStr : " "
52
55
  });
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/ui/components/DiffViewer.tsx"],"sourcesContent":["import React, { useState } from 'react';\r\nimport { Box, Text, useInput } from 'ink';\r\nimport { wrapText } from '../../utils/markdown-parser.js';\r\n\r\ninterface DiffViewerProps {\r\n diff: string;\r\n filePath: string;\r\n fullDiff?: string;\r\n}\r\n\r\n// Maximum number of lines to show before truncating in diff view\r\n// Using 10 lines to match FileCreationPreview\r\nconst MAX_PREVIEW_LINES = 10;\r\n// Maximum number of lines to show in full view before truncating\r\nconst MAX_FULL_VIEW_LINES = 1000;\r\n\r\nexport const DiffViewer: React.FC<DiffViewerProps> = ({ diff, filePath, fullDiff }) => {\r\n const [showFull, setShowFull] = useState(false);\r\n\r\n useInput((input, key) => {\r\n if (input === 'o' && key.ctrl) {\r\n setShowFull(prev => !prev);\r\n }\r\n });\r\n\r\n // Process content into displayable lines (wrapped and styled)\r\n const renderDiffContent = (content: string, maxLines: number) => {\r\n const lines = content.split('\\n');\r\n const processedLines: { text: string; color: string; backgroundColor?: string; lineNumStr: string }[] = [];\r\n\r\n // Parse diff logic\r\n let currentLineNum = 1;\r\n\r\n // Calculate max content width\r\n // Terminal width - borders (2) - padding (2) - line number (5 with space)\r\n const terminalWidth = process.stdout.columns || 80;\r\n const maxContentWidth = Math.max(40, terminalWidth - 11);\r\n\r\n for (const line of lines) {\r\n const trimmed = line.trim();\r\n\r\n // Handle diff headers and hunk headers\r\n if (line.startsWith('@@')) {\r\n const match = line.match(/@@ \\-\\d+(?:,\\d+)? \\+(\\d+)(?:,\\d+)? @@/);\r\n if (match && match[1]) {\r\n currentLineNum = parseInt(match[1], 10);\r\n }\r\n // In full view or if this is relevant context, we generally want to show it\r\n // But for compactness in preview, sometimes hunks are skipped if we implemented smart slicing\r\n // Here we just render everything linearly\r\n }\r\n\r\n // Skip generic diff metadata if it's not useful code context\r\n if (line.startsWith('---') || line.startsWith('+++')) continue;\r\n if (line.startsWith('Index:')) continue;\r\n if (trimmed.startsWith('===')) continue;\r\n\r\n let type: 'added' | 'deleted' | 'context' = 'context';\r\n let lineNum: number | undefined = undefined;\r\n\r\n if (line.startsWith('+')) {\r\n type = 'added';\r\n lineNum = currentLineNum++;\r\n } else if (line.startsWith('-')) {\r\n type = 'deleted';\r\n // No line num increment for deleted lines in new file version\r\n } else {\r\n type = 'context';\r\n lineNum = currentLineNum++;\r\n }\r\n\r\n // Determine style\r\n let style = { color: 'white', backgroundColor: undefined as string | undefined };\r\n if (type === 'added') style = { backgroundColor: undefined, color: 'green' }; // Clean look: colored text\r\n if (type === 'deleted') style = { backgroundColor: undefined, color: 'red' };\r\n\r\n // Format line number\r\n const lineNumStr = lineNum ? lineNum.toString().padStart(4, ' ') : ' ';\r\n const cleanText = (line.startsWith('+') || line.startsWith('-') || line.startsWith(' ')) ? line.slice(1) : line;\r\n\r\n // Wrap text\r\n const wrapped = wrapText(cleanText || ' ', maxContentWidth, 0);\r\n\r\n wrapped.forEach((wLine, idx) => {\r\n processedLines.push({\r\n text: wLine,\r\n ...style,\r\n lineNumStr: idx === 0 ? lineNumStr : ' '\r\n });\r\n });\r\n }\r\n\r\n // Determine truncation\r\n const totalLines = processedLines.length;\r\n const shouldTruncate = totalLines > maxLines;\r\n const displayLines = shouldTruncate ? processedLines.slice(0, maxLines) : processedLines;\r\n const hiddenLines = shouldTruncate ? totalLines - maxLines : 0;\r\n\r\n // Stats for summary\r\n const addedCount = (content.match(/^\\+/gm) || []).length;\r\n const deletedCount = (content.match(/^\\-/gm) || []).length;\r\n const addedText = addedCount === 1 ? '1 line added' : `${addedCount} lines added`;\r\n const deletedText = deletedCount === 1 ? '1 line deleted' : `${deletedCount} lines deleted`;\r\n\r\n return (\r\n <>\r\n {/* Code changes */}\r\n {displayLines.map((line, idx) => (\r\n <Box key={idx} flexDirection=\"row\">\r\n <Text color=\"gray\">{line.lineNumStr} </Text>\r\n <Text color={line.color} backgroundColor={line.backgroundColor}>{line.text}</Text>\r\n </Box>\r\n ))}\r\n\r\n {/* Truncation notice */}\r\n {shouldTruncate && (\r\n <Box marginTop={1}>\r\n <Text color=\"#ffaa00\" dimColor>\r\n ... {hiddenLines} more {hiddenLines === 1 ? 'line' : 'lines'} not shown ...\r\n </Text>\r\n </Box>\r\n )}\r\n\r\n {/* Bottom separator line */}\r\n <Box marginTop={1} marginBottom={1}>\r\n <Text color=\"#666666\">{'─'.repeat(terminalWidth - 4)}</Text>\r\n </Box>\r\n\r\n {/* Summary */}\r\n <Box>\r\n <Text color=\"green\">{addedText}</Text>\r\n <Text color=\"#666666\">, </Text>\r\n <Text color=\"red\">{deletedText}</Text>\r\n </Box>\r\n </>\r\n );\r\n };\r\n\r\n // Determine which content to show\r\n // If showFull is true AND fullDiff is available, show fullDiff\r\n // If showFull is true but no fullDiff, show expanded regular diff\r\n // Otherwise show limited regular diff\r\n const contentToShow = (showFull && fullDiff) ? fullDiff : diff;\r\n const limit = showFull ? MAX_FULL_VIEW_LINES : MAX_PREVIEW_LINES;\r\n\r\n return (\r\n <Box flexDirection=\"column\" borderStyle=\"round\" borderColor=\"#ffaa00\" paddingX={1}>\r\n {/* File path header */}\r\n <Box justifyContent=\"space-between\">\r\n <Text color=\"#ffffff\" bold>Diff Preview: {filePath || 'Untitled'}</Text>\r\n <Box>\r\n <Text color=\"#666666\" dimColor>\r\n {showFull ? 'Ctrl+O: Collapse' : 'Ctrl+O: Full File'}\r\n </Text>\r\n </Box>\r\n </Box>\r\n\r\n {/* Separator line */}\r\n <Box marginTop={1} marginBottom={1}>\r\n <Text color=\"#666666\">{'─'.repeat((process.stdout.columns || 80) - 4)}</Text>\r\n </Box>\r\n\r\n {renderDiffContent(contentToShow, limit)}\r\n </Box>\r\n );\r\n};\r\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../../src/ui/components/DiffViewer.tsx"],"sourcesContent":["import React, { useState } from 'react';\r\nimport { Box, Text, useInput } from 'ink';\r\nimport { wrapText } from '../../utils/markdown-parser.js';\r\n\r\ninterface DiffViewerProps {\r\n diff: string;\r\n filePath: string;\r\n fullDiff?: string;\r\n}\r\n\r\n// Maximum number of lines to show before truncating in diff view\r\n// Using 10 lines to match FileCreationPreview\r\nconst MAX_PREVIEW_LINES = 10;\r\n// Maximum number of lines to show in full view\r\nconst MAX_FULL_VIEW_LINES = 1000;\r\n\r\nexport const DiffViewer: React.FC<DiffViewerProps> = ({ diff, filePath, fullDiff }) => {\r\n const [showFull, setShowFull] = useState(false);\r\n\r\n useInput((input, key) => {\r\n if (input === 'o' && key.ctrl) {\r\n setShowFull(prev => !prev);\r\n }\r\n });\r\n\r\n // Process content into displayable lines (wrapped and styled)\r\n const renderDiffContent = (content: string, maxLines: number) => {\r\n const lines = content.split('\\n');\r\n const processedLines: { text: string; color: string; backgroundColor?: string; lineNumStr: string }[] = [];\r\n\r\n // Parse diff logic\r\n let currentLineNum = 1;\r\n\r\n // Calculate max content width\r\n // Terminal width - borders (2) - padding (2) - line number (5 with space)\r\n const terminalWidth = process.stdout.columns || 80;\r\n const maxContentWidth = Math.max(40, terminalWidth - 11);\r\n\r\n for (const line of lines) {\r\n const trimmed = line.trim();\r\n\r\n // Handle diff headers and hunk headers\r\n if (line.startsWith('@@')) {\r\n const match = line.match(/@@ \\-\\d+(?:,\\d+)? \\+(\\d+)(?:,\\d+)? @@/);\r\n if (match && match[1]) {\r\n currentLineNum = parseInt(match[1], 10);\r\n }\r\n // In full view or if this is relevant context, we generally want to show it\r\n // But for compactness in preview, sometimes hunks are skipped if we implemented smart slicing\r\n // Here we just render everything linearly\r\n }\r\n\r\n // Skip generic diff metadata if it's not useful code context\r\n if (line.startsWith('---') || line.startsWith('+++')) continue;\r\n if (line.startsWith('Index:')) continue;\r\n if (trimmed.startsWith('===')) continue;\r\n\r\n let type: 'added' | 'deleted' | 'context' = 'context';\r\n let lineNum: number | undefined = undefined;\r\n\r\n if (line.startsWith('+')) {\r\n type = 'added';\r\n lineNum = currentLineNum++;\r\n } else if (line.startsWith('-')) {\r\n type = 'deleted';\r\n // No line num increment for deleted lines in new file version\r\n } else {\r\n type = 'context';\r\n lineNum = currentLineNum++;\r\n }\r\n\r\n // Determine style — full-line highlight like the edit tool UI\r\n let style = { color: 'white', backgroundColor: undefined as string | undefined };\r\n if (type === 'added') style = { color: '#e6e6e6', backgroundColor: '#1e4d2b' };\r\n if (type === 'deleted') style = { color: '#e6e6e6', backgroundColor: '#5c1e1e' };\r\n\r\n // Format line number\r\n const prefix = type === 'added' ? '+' : type === 'deleted' ? '-' : ' ';\r\n const lineNumStr = lineNum ? lineNum.toString().padStart(4, ' ') : ' ';\r\n const cleanText = (line.startsWith('+') || line.startsWith('-') || line.startsWith(' ')) ? line.slice(1) : line;\r\n\r\n // Wrap text\r\n const wrapped = wrapText(cleanText || ' ', maxContentWidth, 0);\r\n\r\n wrapped.forEach((wLine, idx) => {\r\n const linePrefix = idx === 0 ? prefix : ' ';\r\n // Pad the text to fill the available width so background color spans the whole line\r\n const paddedText = `${linePrefix} ${wLine}`.padEnd(maxContentWidth + 2);\r\n processedLines.push({\r\n text: paddedText,\r\n ...style,\r\n lineNumStr: idx === 0 ? lineNumStr : ' '\r\n });\r\n });\r\n }\r\n\r\n // Determine truncation\r\n const totalLines = processedLines.length;\r\n const shouldTruncate = totalLines > maxLines;\r\n const displayLines = shouldTruncate ? processedLines.slice(0, maxLines) : processedLines;\r\n const hiddenLines = shouldTruncate ? totalLines - maxLines : 0;\r\n\r\n // Stats for summary\r\n const addedCount = (content.match(/^\\+/gm) || []).length;\r\n const deletedCount = (content.match(/^\\-/gm) || []).length;\r\n const addedText = addedCount === 1 ? '1 line added' : `${addedCount} lines added`;\r\n const deletedText = deletedCount === 1 ? '1 line deleted' : `${deletedCount} lines deleted`;\r\n\r\n return (\r\n <>\r\n {/* Code changes */}\r\n {displayLines.map((line, idx) => (\r\n <Box key={idx} flexDirection=\"row\">\r\n <Text color=\"gray\">{line.lineNumStr} </Text>\r\n <Text color={line.color} backgroundColor={line.backgroundColor}>{line.text}</Text>\r\n </Box>\r\n ))}\r\n\r\n {/* Truncation notice */}\r\n {shouldTruncate && (\r\n <Box marginTop={1}>\r\n <Text color=\"#ffaa00\" dimColor>\r\n ... {hiddenLines} more {hiddenLines === 1 ? 'line' : 'lines'} not shown ...\r\n </Text>\r\n </Box>\r\n )}\r\n\r\n {/* Bottom separator line */}\r\n <Box marginTop={1} marginBottom={1}>\r\n <Text color=\"#666666\">{'─'.repeat(terminalWidth - 4)}</Text>\r\n </Box>\r\n\r\n {/* Summary */}\r\n <Box>\r\n <Text color=\"green\">{addedText}</Text>\r\n <Text color=\"#666666\">, </Text>\r\n <Text color=\"red\">{deletedText}</Text>\r\n </Box>\r\n </>\r\n );\r\n };\r\n\r\n // Determine which content to show\r\n // If showFull is true AND fullDiff is available, show fullDiff\r\n // If showFull is true but no fullDiff, show expanded regular diff\r\n // Otherwise show limited regular diff\r\n const contentToShow = (showFull && fullDiff) ? fullDiff : diff;\r\n const limit = showFull ? MAX_FULL_VIEW_LINES : MAX_PREVIEW_LINES;\r\n\r\n return (\r\n <Box flexDirection=\"column\" borderStyle=\"round\" borderColor=\"#ffaa00\" paddingX={1}>\r\n {/* File path header */}\r\n <Box justifyContent=\"space-between\">\r\n <Text color=\"#ffffff\" bold>Diff Preview: {filePath || 'Untitled'}</Text>\r\n <Box>\r\n <Text color=\"#666666\" dimColor>\r\n {showFull ? 'Ctrl+O: Collapse' : 'Ctrl+O: Full File'}\r\n </Text>\r\n </Box>\r\n </Box>\r\n\r\n {/* Separator line */}\r\n <Box marginTop={1} marginBottom={1}>\r\n <Text color=\"#666666\">{'─'.repeat((process.stdout.columns || 80) - 4)}</Text>\r\n </Box>\r\n\r\n {renderDiffContent(contentToShow, limit)}\r\n </Box>\r\n );\r\n};\r\n"],"mappings":"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","names":[]}
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/ui/components/FileCreationPreview.tsx"],"sourcesContent":["import React, { useState } from 'react';\r\nimport { Box, Text, useInput } from 'ink';\r\nimport { wrapText } from '../../utils/markdown-parser.js';\r\n\r\ninterface FileCreationPreviewProps {\r\n content: string;\r\n filePath?: string;\r\n}\r\n\r\n// Maximum number of lines to show before truncating in preview\r\n// Using 10 lines as a reasonable default for preview\r\nconst MAX_PREVIEW_LINES = 10;\r\n// Maximum number of lines to show in full view before truncating\r\nconst MAX_FULL_VIEW_LINES = 1000;\r\n\r\nexport const FileCreationPreview: React.FC<FileCreationPreviewProps> = ({ content, filePath }) => {\r\n const [showFull, setShowFull] = useState(false);\r\n\r\n useInput((input, key) => {\r\n if (input === 'o' && key.ctrl) {\r\n setShowFull(prev => !prev);\r\n }\r\n });\r\n\r\n const renderContent = (text: string, maxLines: number) => {\r\n const lines = text.split('\\n');\r\n const totalLines = lines.length;\r\n const shouldTruncate = totalLines > maxLines;\r\n const displayLines = shouldTruncate ? lines.slice(0, maxLines) : lines;\r\n const hiddenLines = shouldTruncate ? totalLines - maxLines : 0;\r\n\r\n // Calculate available width for content\r\n // Terminal width - borders (2) - padding (2) - line number (5 with space)\r\n const terminalWidth = process.stdout.columns || 80;\r\n const maxContentWidth = Math.max(40, terminalWidth - 11);\r\n\r\n return (\r\n <>\r\n {displayLines.map((line, idx) => {\r\n // Format line number: fixed width 4 chars\r\n const lineNumStr = (idx + 1).toString().padStart(4, ' ');\r\n\r\n // Use wrapText utility to wrap long lines properly\r\n const wrappedLines = wrapText(line || ' ', maxContentWidth, 0);\r\n\r\n return wrappedLines.map((wrappedLine, lineIdx) => (\r\n <Box key={`${idx}-${lineIdx}`} flexDirection=\"column\">\r\n <Box flexDirection=\"row\">\r\n <Text color=\"gray\">\r\n {lineIdx === 0 ? lineNumStr : ' '}\r\n {' '}\r\n </Text>\r\n <Text color=\"white\">{wrappedLine}</Text>\r\n </Box>\r\n </Box>\r\n ));\r\n }).flat()}\r\n\r\n {/* Truncation notice */}\r\n {shouldTruncate && (\r\n <Box marginTop={1}>\r\n <Text color=\"#00cc66\" dimColor>\r\n ... {hiddenLines} more {hiddenLines === 1 ? 'line' : 'lines'} not shown ...\r\n </Text>\r\n </Box>\r\n )}\r\n\r\n {/* Bottom separator line */}\r\n <Box marginTop={1} marginBottom={1}>\r\n <Text color=\"#666666\">{'─'.repeat(80)}</Text>\r\n </Box>\r\n\r\n {/* Summary */}\r\n <Box>\r\n <Text color=\"#00cc66\">{totalLines} lines to be created</Text>\r\n </Box>\r\n </>\r\n );\r\n };\r\n\r\n return (\r\n <Box flexDirection=\"column\" borderStyle=\"round\" borderColor=\"#00cc66\" paddingX={1}>\r\n {/* File path header */}\r\n <Box justifyContent=\"space-between\">\r\n <Text color=\"#ffffff\" bold>New File Preview: {filePath || 'Untitled'}</Text>\r\n <Text color=\"#666666\" dimColor>\r\n {showFull ? 'Press Ctrl+O to collapse' : 'Press Ctrl+O for Full File'}\r\n </Text>\r\n </Box>\r\n\r\n {/* Separator line */}\r\n <Box marginTop={1} marginBottom={1}>\r\n <Text color=\"#666666\">{'─'.repeat(80)}</Text>\r\n </Box>\r\n\r\n {renderContent(content, showFull ? MAX_FULL_VIEW_LINES : MAX_PREVIEW_LINES)}\r\n </Box>\r\n );\r\n};\r\n"],"mappings":"AAAA,OAAO,SAAS,gBAAgB;AAChC,SAAS,KAAK,MAAM,gBAAgB;AACpC,SAAS,gBAAgB;AASzB,MAAM,oBAAoB;AAE1B,MAAM,sBAAsB;AAErB,MAAM,sBAA0D,CAAC,EAAE,SAAS,SAAS,MAAM;AAC9F,QAAM,CAAC,UAAU,WAAW,IAAI,SAAS,KAAK;AAE9C,WAAS,CAAC,OAAO,QAAQ;AACrB,QAAI,UAAU,OAAO,IAAI,MAAM;AAC3B,kBAAY,UAAQ,CAAC,IAAI;AAAA,IAC7B;AAAA,EACJ,CAAC;AAED,QAAM,gBAAgB,CAAC,MAAc,aAAqB;AACtD,UAAM,QAAQ,KAAK,MAAM,IAAI;AAC7B,UAAM,aAAa,MAAM;AACzB,UAAM,iBAAiB,aAAa;AACpC,UAAM,eAAe,iBAAiB,MAAM,MAAM,GAAG,QAAQ,IAAI;AACjE,UAAM,cAAc,iBAAiB,aAAa,WAAW;AAI7D,UAAM,gBAAgB,QAAQ,OAAO,WAAW;AAChD,UAAM,kBAAkB,KAAK,IAAI,IAAI,gBAAgB,EAAE;AAEvD,WACI,0DACK,aAAa,IAAI,CAAC,MAAM,QAAQ;AAE7B,YAAM,cAAc,MAAM,GAAG,SAAS,EAAE,SAAS,GAAG,GAAG;AAGvD,YAAM,eAAe,SAAS,QAAQ,KAAK,iBAAiB,CAAC;AAE7D,aAAO,aAAa,IAAI,CAAC,aAAa,YAClC,oCAAC,OAAI,KAAK,GAAG,GAAG,IAAI,OAAO,IAAI,eAAc,YACzC,oCAAC,OAAI,eAAc,SACf,oCAAC,QAAK,OAAM,UACP,YAAY,IAAI,aAAa,QAC7B,GACL,GACA,oCAAC,QAAK,OAAM,WAAS,WAAY,CACrC,CACJ,CACH;AAAA,IACL,CAAC,EAAE,KAAK,GAGP,kBACG,oCAAC,OAAI,WAAW,KACZ,oCAAC,QAAK,OAAM,WAAU,UAAQ,QAAC,QACtB,aAAY,UAAO,gBAAgB,IAAI,SAAS,SAAQ,gBACjE,CACJ,GAIJ,oCAAC,OAAI,WAAW,GAAG,cAAc,KAC7B,oCAAC,QAAK,OAAM,aAAW,SAAI,OAAO,EAAE,CAAE,CAC1C,GAGA,oCAAC,WACG,oCAAC,QAAK,OAAM,aAAW,YAAW,sBAAoB,CAC1D,CACJ;AAAA,EAER;AAEA,SACI,oCAAC,OAAI,eAAc,UAAS,aAAY,SAAQ,aAAY,WAAU,UAAU,KAE5E,oCAAC,OAAI,gBAAe,mBAChB,oCAAC,QAAK,OAAM,WAAU,MAAI,QAAC,sBAAmB,YAAY,UAAW,GACrE,oCAAC,QAAK,OAAM,WAAU,UAAQ,QACzB,WAAW,6BAA6B,4BAC7C,CACJ,GAGA,oCAAC,OAAI,WAAW,GAAG,cAAc,KAC7B,oCAAC,QAAK,OAAM,aAAW,SAAI,OAAO,EAAE,CAAE,CAC1C,GAEC,cAAc,SAAS,WAAW,sBAAsB,iBAAiB,CAC9E;AAER;","names":[]}
1
+ {"version":3,"sources":["../../../src/ui/components/FileCreationPreview.tsx"],"sourcesContent":["import React, { useState } from 'react';\r\nimport { Box, Text, useInput } from 'ink';\r\nimport { wrapText } from '../../utils/markdown-parser.js';\r\n\r\ninterface FileCreationPreviewProps {\r\n content: string;\r\n filePath?: string;\r\n}\r\n\r\n// Maximum number of lines to show before truncating in preview\r\nconst MAX_PREVIEW_LINES = 10;\r\n// Maximum number of lines to show in full view\r\nconst MAX_FULL_VIEW_LINES = 1000;\r\n\r\nexport const FileCreationPreview: React.FC<FileCreationPreviewProps> = ({ content, filePath }) => {\r\n const [showFull, setShowFull] = useState(false);\r\n\r\n useInput((input, key) => {\r\n if (input === 'o' && key.ctrl) {\r\n setShowFull(prev => !prev);\r\n }\r\n });\r\n\r\n const renderContent = (text: string, maxLines: number) => {\r\n const lines = text.split('\\n');\r\n const totalLines = lines.length;\r\n const shouldTruncate = totalLines > maxLines;\r\n const displayLines = shouldTruncate ? lines.slice(0, maxLines) : lines;\r\n const hiddenLines = shouldTruncate ? totalLines - maxLines : 0;\r\n\r\n // Calculate available width for content\r\n // Terminal width - borders (2) - padding (2) - line number (5 with space)\r\n const terminalWidth = process.stdout.columns || 80;\r\n const maxContentWidth = Math.max(40, terminalWidth - 11);\r\n\r\n return (\r\n <>\r\n {displayLines.map((line, idx) => {\r\n // Format line number: fixed width 4 chars\r\n const lineNumStr = (idx + 1).toString().padStart(4, ' ');\r\n\r\n // Use wrapText utility to wrap long lines properly\r\n const wrappedLines = wrapText(line || ' ', maxContentWidth, 0);\r\n\r\n return wrappedLines.map((wrappedLine, lineIdx) => (\r\n <Box key={`${idx}-${lineIdx}`} flexDirection=\"column\">\r\n <Box flexDirection=\"row\">\r\n <Text color=\"gray\">\r\n {lineIdx === 0 ? lineNumStr : ' '}\r\n {' '}\r\n </Text>\r\n <Text color=\"white\">{wrappedLine}</Text>\r\n </Box>\r\n </Box>\r\n ));\r\n }).flat()}\r\n\r\n {/* Truncation notice */}\r\n {shouldTruncate && (\r\n <Box marginTop={1}>\r\n <Text color=\"#00cc66\" dimColor>\r\n ... {hiddenLines} more {hiddenLines === 1 ? 'line' : 'lines'} not shown ...\r\n </Text>\r\n </Box>\r\n )}\r\n\r\n {/* Bottom separator line */}\r\n <Box marginTop={1} marginBottom={1}>\r\n <Text color=\"#666666\">{'─'.repeat(80)}</Text>\r\n </Box>\r\n\r\n {/* Summary */}\r\n <Box>\r\n <Text color=\"#00cc66\">{totalLines} lines to be created</Text>\r\n </Box>\r\n </>\r\n );\r\n };\r\n\r\n return (\r\n <Box flexDirection=\"column\" borderStyle=\"round\" borderColor=\"#00cc66\" paddingX={1}>\r\n {/* File path header */}\r\n <Box justifyContent=\"space-between\">\r\n <Text color=\"#ffffff\" bold>New File Preview: {filePath || 'Untitled'}</Text>\r\n <Text color=\"#666666\" dimColor>\r\n {showFull ? 'Press Ctrl+O to collapse' : 'Press Ctrl+O for Full File'}\r\n </Text>\r\n </Box>\r\n\r\n {/* Separator line */}\r\n <Box marginTop={1} marginBottom={1}>\r\n <Text color=\"#666666\">{'─'.repeat(80)}</Text>\r\n </Box>\r\n\r\n {renderContent(content, showFull ? MAX_FULL_VIEW_LINES : MAX_PREVIEW_LINES)}\r\n </Box>\r\n );\r\n};\r\n"],"mappings":"AAAA,OAAO,SAAS,gBAAgB;AAChC,SAAS,KAAK,MAAM,gBAAgB;AACpC,SAAS,gBAAgB;AAQzB,MAAM,oBAAoB;AAE1B,MAAM,sBAAsB;AAErB,MAAM,sBAA0D,CAAC,EAAE,SAAS,SAAS,MAAM;AAC9F,QAAM,CAAC,UAAU,WAAW,IAAI,SAAS,KAAK;AAE9C,WAAS,CAAC,OAAO,QAAQ;AACrB,QAAI,UAAU,OAAO,IAAI,MAAM;AAC3B,kBAAY,UAAQ,CAAC,IAAI;AAAA,IAC7B;AAAA,EACJ,CAAC;AAED,QAAM,gBAAgB,CAAC,MAAc,aAAqB;AACtD,UAAM,QAAQ,KAAK,MAAM,IAAI;AAC7B,UAAM,aAAa,MAAM;AACzB,UAAM,iBAAiB,aAAa;AACpC,UAAM,eAAe,iBAAiB,MAAM,MAAM,GAAG,QAAQ,IAAI;AACjE,UAAM,cAAc,iBAAiB,aAAa,WAAW;AAI7D,UAAM,gBAAgB,QAAQ,OAAO,WAAW;AAChD,UAAM,kBAAkB,KAAK,IAAI,IAAI,gBAAgB,EAAE;AAEvD,WACI,0DACK,aAAa,IAAI,CAAC,MAAM,QAAQ;AAE7B,YAAM,cAAc,MAAM,GAAG,SAAS,EAAE,SAAS,GAAG,GAAG;AAGvD,YAAM,eAAe,SAAS,QAAQ,KAAK,iBAAiB,CAAC;AAE7D,aAAO,aAAa,IAAI,CAAC,aAAa,YAClC,oCAAC,OAAI,KAAK,GAAG,GAAG,IAAI,OAAO,IAAI,eAAc,YACzC,oCAAC,OAAI,eAAc,SACf,oCAAC,QAAK,OAAM,UACP,YAAY,IAAI,aAAa,QAC7B,GACL,GACA,oCAAC,QAAK,OAAM,WAAS,WAAY,CACrC,CACJ,CACH;AAAA,IACL,CAAC,EAAE,KAAK,GAGP,kBACG,oCAAC,OAAI,WAAW,KACZ,oCAAC,QAAK,OAAM,WAAU,UAAQ,QAAC,QACtB,aAAY,UAAO,gBAAgB,IAAI,SAAS,SAAQ,gBACjE,CACJ,GAIJ,oCAAC,OAAI,WAAW,GAAG,cAAc,KAC7B,oCAAC,QAAK,OAAM,aAAW,SAAI,OAAO,EAAE,CAAE,CAC1C,GAGA,oCAAC,WACG,oCAAC,QAAK,OAAM,aAAW,YAAW,sBAAoB,CAC1D,CACJ;AAAA,EAER;AAEA,SACI,oCAAC,OAAI,eAAc,UAAS,aAAY,SAAQ,aAAY,WAAU,UAAU,KAE5E,oCAAC,OAAI,gBAAe,mBAChB,oCAAC,QAAK,OAAM,WAAU,MAAI,QAAC,sBAAmB,YAAY,UAAW,GACrE,oCAAC,QAAK,OAAM,WAAU,UAAQ,QACzB,WAAW,6BAA6B,4BAC7C,CACJ,GAGA,oCAAC,OAAI,WAAW,GAAG,cAAc,KAC7B,oCAAC,QAAK,OAAM,aAAW,SAAI,OAAO,EAAE,CAAE,CAC1C,GAEC,cAAc,SAAS,WAAW,sBAAsB,iBAAiB,CAC9E;AAER;","names":[]}
@@ -1,10 +1,12 @@
1
1
  import React from "react";
2
2
  import { Box, Text } from "ink";
3
+ import { useTheme } from "../theme.js";
3
4
  const MAX_VISIBLE = 6;
4
5
  const FileTagAutocomplete = ({
5
6
  files,
6
7
  selectedIndex
7
8
  }) => {
9
+ const theme = useTheme();
8
10
  if (files.length === 0) return null;
9
11
  const total = files.length;
10
12
  const scrollOffset = Math.max(0, Math.min(selectedIndex - MAX_VISIBLE + 1, total - MAX_VISIBLE));
@@ -14,7 +16,7 @@ const FileTagAutocomplete = ({
14
16
  {
15
17
  flexDirection: "column",
16
18
  borderStyle: "round",
17
- borderColor: "#00ccff",
19
+ borderColor: theme.accent,
18
20
  paddingX: 1,
19
21
  marginLeft: 1,
20
22
  marginTop: 0
@@ -36,7 +38,7 @@ const FileTagAutocomplete = ({
36
38
  /* @__PURE__ */ React.createElement(
37
39
  Text,
38
40
  {
39
- color: isSelected ? "#00ccff" : "#aaaaaa",
41
+ color: isSelected ? theme.accent : "#aaaaaa",
40
42
  bold: isSelected,
41
43
  inverse: isSelected
42
44
  },
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/ui/components/FileTagAutocomplete.tsx"],"sourcesContent":["import React from 'react';\r\nimport { Box, Text } from 'ink';\r\n\r\ninterface FileTagAutocompleteProps {\r\n files: Array<{ name: string; kind: 'file' | 'directory' | 'rule-namespace' | 'rule'; description?: string }>;\r\n selectedIndex: number;\r\n}\r\n\r\nconst MAX_VISIBLE = 6;\r\n\r\nexport const FileTagAutocomplete: React.FC<FileTagAutocompleteProps> = ({\r\n files,\r\n selectedIndex\r\n}) => {\r\n if (files.length === 0) return null;\r\n\r\n const total = files.length;\r\n\r\n // Scroll the window to keep the selected item visible\r\n const scrollOffset = Math.max(0, Math.min(selectedIndex - MAX_VISIBLE + 1, total - MAX_VISIBLE));\r\n const visibleFiles = files.slice(scrollOffset, scrollOffset + MAX_VISIBLE);\r\n\r\n return (\r\n <Box\r\n flexDirection=\"column\"\r\n borderStyle=\"round\"\r\n borderColor=\"#00ccff\"\r\n paddingX={1}\r\n marginLeft={1}\r\n marginTop={0}\r\n >\r\n <Box marginBottom={0}>\r\n <Text color=\"#666666\" dimColor>\r\n References matching @...\r\n {total > MAX_VISIBLE ? ` (${selectedIndex + 1}/${total})` : ''}\r\n </Text>\r\n </Box>\r\n {scrollOffset > 0 && (\r\n <Box paddingX={1}>\r\n <Text color=\"#555555\">↑ {scrollOffset} more</Text>\r\n </Box>\r\n )}\r\n {visibleFiles.map((file, visIdx) => {\r\n const actualIndex = scrollOffset + visIdx;\r\n const isSelected = actualIndex === selectedIndex;\r\n const icon = file.kind === 'directory'\r\n ? '📁'\r\n : file.kind === 'rule'\r\n ? '📜'\r\n : file.kind === 'rule-namespace'\r\n ? '⌘'\r\n : '📄';\r\n const suffix = file.kind === 'directory' ? '/' : '';\r\n\r\n return (\r\n <Box\r\n key={file.name}\r\n flexDirection=\"column\"\r\n paddingX={1}\r\n >\r\n <Text\r\n color={isSelected ? '#00ccff' : '#aaaaaa'}\r\n bold={isSelected}\r\n inverse={isSelected}\r\n >\r\n {icon} {file.name}{suffix}\r\n </Text>\r\n {file.description && (\r\n <Text color=\"#666666\" dimColor>\r\n {file.description}\r\n </Text>\r\n )}\r\n </Box>\r\n );\r\n })}\r\n {scrollOffset + MAX_VISIBLE < total && (\r\n <Box paddingX={1}>\r\n <Text color=\"#555555\">↓ {total - scrollOffset - MAX_VISIBLE} more</Text>\r\n </Box>\r\n )}\r\n </Box>\r\n );\r\n};\r\n"],"mappings":"AAAA,OAAO,WAAW;AAClB,SAAS,KAAK,YAAY;AAO1B,MAAM,cAAc;AAEb,MAAM,sBAA0D,CAAC;AAAA,EACpE;AAAA,EACA;AACJ,MAAM;AACF,MAAI,MAAM,WAAW,EAAG,QAAO;AAE/B,QAAM,QAAQ,MAAM;AAGpB,QAAM,eAAe,KAAK,IAAI,GAAG,KAAK,IAAI,gBAAgB,cAAc,GAAG,QAAQ,WAAW,CAAC;AAC/F,QAAM,eAAe,MAAM,MAAM,cAAc,eAAe,WAAW;AAEzE,SACI;AAAA,IAAC;AAAA;AAAA,MACG,eAAc;AAAA,MACd,aAAY;AAAA,MACZ,aAAY;AAAA,MACZ,UAAU;AAAA,MACV,YAAY;AAAA,MACZ,WAAW;AAAA;AAAA,IAEX,oCAAC,OAAI,cAAc,KACf,oCAAC,QAAK,OAAM,WAAU,UAAQ,QAAC,4BAE1B,QAAQ,cAAc,KAAK,gBAAgB,CAAC,IAAI,KAAK,MAAM,EAChE,CACJ;AAAA,IACC,eAAe,KACZ,oCAAC,OAAI,UAAU,KACX,oCAAC,QAAK,OAAM,aAAU,WAAG,cAAa,OAAK,CAC/C;AAAA,IAEH,aAAa,IAAI,CAAC,MAAM,WAAW;AAChC,YAAM,cAAc,eAAe;AACnC,YAAM,aAAa,gBAAgB;AACnC,YAAM,OAAO,KAAK,SAAS,cACrB,cACA,KAAK,SAAS,SACV,cACA,KAAK,SAAS,mBACV,WACA;AACd,YAAM,SAAS,KAAK,SAAS,cAAc,MAAM;AAEjD,aACI;AAAA,QAAC;AAAA;AAAA,UACG,KAAK,KAAK;AAAA,UACV,eAAc;AAAA,UACd,UAAU;AAAA;AAAA,QAEV;AAAA,UAAC;AAAA;AAAA,YACG,OAAO,aAAa,YAAY;AAAA,YAChC,MAAM;AAAA,YACN,SAAS;AAAA;AAAA,UAER;AAAA,UAAK;AAAA,UAAE,KAAK;AAAA,UAAM;AAAA,QACvB;AAAA,QACC,KAAK,eACF,oCAAC,QAAK,OAAM,WAAU,UAAQ,QACzB,KAAK,WACV;AAAA,MAER;AAAA,IAER,CAAC;AAAA,IACA,eAAe,cAAc,SAC1B,oCAAC,OAAI,UAAU,KACX,oCAAC,QAAK,OAAM,aAAU,WAAG,QAAQ,eAAe,aAAY,OAAK,CACrE;AAAA,EAER;AAER;","names":[]}
1
+ {"version":3,"sources":["../../../src/ui/components/FileTagAutocomplete.tsx"],"sourcesContent":["import React from 'react';\r\nimport { Box, Text } from 'ink';\r\nimport { useTheme } from '../theme.js';\r\n\r\ninterface FileTagAutocompleteProps {\r\n files: Array<{ name: string; kind: 'file' | 'directory' | 'rule-namespace' | 'rule'; description?: string }>;\r\n selectedIndex: number;\r\n}\r\n\r\nconst MAX_VISIBLE = 6;\r\n\r\nexport const FileTagAutocomplete: React.FC<FileTagAutocompleteProps> = ({\r\n files,\r\n selectedIndex\r\n}) => {\r\n const theme = useTheme();\r\n if (files.length === 0) return null;\r\n\r\n const total = files.length;\r\n\r\n // Scroll the window to keep the selected item visible\r\n const scrollOffset = Math.max(0, Math.min(selectedIndex - MAX_VISIBLE + 1, total - MAX_VISIBLE));\r\n const visibleFiles = files.slice(scrollOffset, scrollOffset + MAX_VISIBLE);\r\n\r\n return (\r\n <Box\r\n flexDirection=\"column\"\r\n borderStyle=\"round\"\r\n borderColor={theme.accent}\r\n paddingX={1}\r\n marginLeft={1}\r\n marginTop={0}\r\n >\r\n <Box marginBottom={0}>\r\n <Text color=\"#666666\" dimColor>\r\n References matching @...\r\n {total > MAX_VISIBLE ? ` (${selectedIndex + 1}/${total})` : ''}\r\n </Text>\r\n </Box>\r\n {scrollOffset > 0 && (\r\n <Box paddingX={1}>\r\n <Text color=\"#555555\">↑ {scrollOffset} more</Text>\r\n </Box>\r\n )}\r\n {visibleFiles.map((file, visIdx) => {\r\n const actualIndex = scrollOffset + visIdx;\r\n const isSelected = actualIndex === selectedIndex;\r\n const icon = file.kind === 'directory'\r\n ? '📁'\r\n : file.kind === 'rule'\r\n ? '📜'\r\n : file.kind === 'rule-namespace'\r\n ? '⌘'\r\n : '📄';\r\n const suffix = file.kind === 'directory' ? '/' : '';\r\n\r\n return (\r\n <Box\r\n key={file.name}\r\n flexDirection=\"column\"\r\n paddingX={1}\r\n >\r\n <Text\r\n color={isSelected ? theme.accent : '#aaaaaa'}\r\n bold={isSelected}\r\n inverse={isSelected}\r\n >\r\n {icon} {file.name}{suffix}\r\n </Text>\r\n {file.description && (\r\n <Text color=\"#666666\" dimColor>\r\n {file.description}\r\n </Text>\r\n )}\r\n </Box>\r\n );\r\n })}\r\n {scrollOffset + MAX_VISIBLE < total && (\r\n <Box paddingX={1}>\r\n <Text color=\"#555555\">↓ {total - scrollOffset - MAX_VISIBLE} more</Text>\r\n </Box>\r\n )}\r\n </Box>\r\n );\r\n};\r\n"],"mappings":"AAAA,OAAO,WAAW;AAClB,SAAS,KAAK,YAAY;AAC1B,SAAS,gBAAgB;AAOzB,MAAM,cAAc;AAEb,MAAM,sBAA0D,CAAC;AAAA,EACpE;AAAA,EACA;AACJ,MAAM;AACF,QAAM,QAAQ,SAAS;AACvB,MAAI,MAAM,WAAW,EAAG,QAAO;AAE/B,QAAM,QAAQ,MAAM;AAGpB,QAAM,eAAe,KAAK,IAAI,GAAG,KAAK,IAAI,gBAAgB,cAAc,GAAG,QAAQ,WAAW,CAAC;AAC/F,QAAM,eAAe,MAAM,MAAM,cAAc,eAAe,WAAW;AAEzE,SACI;AAAA,IAAC;AAAA;AAAA,MACG,eAAc;AAAA,MACd,aAAY;AAAA,MACZ,aAAa,MAAM;AAAA,MACnB,UAAU;AAAA,MACV,YAAY;AAAA,MACZ,WAAW;AAAA;AAAA,IAEX,oCAAC,OAAI,cAAc,KACf,oCAAC,QAAK,OAAM,WAAU,UAAQ,QAAC,4BAE1B,QAAQ,cAAc,KAAK,gBAAgB,CAAC,IAAI,KAAK,MAAM,EAChE,CACJ;AAAA,IACC,eAAe,KACZ,oCAAC,OAAI,UAAU,KACX,oCAAC,QAAK,OAAM,aAAU,WAAG,cAAa,OAAK,CAC/C;AAAA,IAEH,aAAa,IAAI,CAAC,MAAM,WAAW;AAChC,YAAM,cAAc,eAAe;AACnC,YAAM,aAAa,gBAAgB;AACnC,YAAM,OAAO,KAAK,SAAS,cACrB,cACA,KAAK,SAAS,SACV,cACA,KAAK,SAAS,mBACV,WACA;AACd,YAAM,SAAS,KAAK,SAAS,cAAc,MAAM;AAEjD,aACI;AAAA,QAAC;AAAA;AAAA,UACG,KAAK,KAAK;AAAA,UACV,eAAc;AAAA,UACd,UAAU;AAAA;AAAA,QAEV;AAAA,UAAC;AAAA;AAAA,YACG,OAAO,aAAa,MAAM,SAAS;AAAA,YACnC,MAAM;AAAA,YACN,SAAS;AAAA;AAAA,UAER;AAAA,UAAK;AAAA,UAAE,KAAK;AAAA,UAAM;AAAA,QACvB;AAAA,QACC,KAAK,eACF,oCAAC,QAAK,OAAM,WAAU,UAAQ,QACzB,KAAK,WACV;AAAA,MAER;AAAA,IAER,CAAC;AAAA,IACA,eAAe,cAAc,SAC1B,oCAAC,OAAI,UAAU,KACX,oCAAC,QAAK,OAAM,aAAU,WAAG,QAAQ,eAAe,aAAY,OAAK,CACrE;AAAA,EAER;AAER;","names":[]}