From 35013a86532ddd6c19d26602676784a5870739ea Mon Sep 17 00:00:00 2001 From: joshua Date: Sun, 22 Mar 2026 16:55:37 +0000 Subject: [PATCH] feat: add personality traits system with per-mode configuration - 13 built-in personality traits (dry-wit, professor, straight-shooter, etc.) - Custom trait creation with emoji picker and prompt editor - Per-mode personality configuration via PersonalityConfig on ModeConfig - LLM-powered trait enhancement for expanding brief descriptions - Sandwich technique: personality prompt injected at top and bottom of system prompt - PersonalityTraitsPanel component with pill-grid UI, active order badges - Full test coverage for trait resolution, merging, and prompt building Made-with: Cursor --- .vscode/settings.json | 3 +- Untitled-1.jsonc | 1617 +++++++++++++++++ packages/types/src/global-settings.ts | 12 + packages/types/src/mode.ts | 27 + path/to/data/aliases/data.json | 1 + path/to/data/raft_state.json | 1 + .../sections/__tests__/personality.spec.ts | 205 +++ .../prompts/sections/custom-instructions.ts | 8 + src/core/prompts/sections/index.ts | 1 + src/core/prompts/sections/personality.ts | 9 + src/shared/personality-traits.ts | 225 +++ .../src/components/modes/EmojiPicker.tsx | 65 + webview-ui/src/components/modes/ModesView.tsx | 9 + .../modes/PersonalityTraitsPanel.tsx | 443 +++++ .../src/i18n/locales/en/personality.json | 19 + 15 files changed, 2644 insertions(+), 1 deletion(-) create mode 100644 Untitled-1.jsonc create mode 100644 path/to/data/aliases/data.json create mode 100644 path/to/data/raft_state.json create mode 100644 src/core/prompts/sections/__tests__/personality.spec.ts create mode 100644 src/core/prompts/sections/personality.ts create mode 100644 src/shared/personality-traits.ts create mode 100644 webview-ui/src/components/modes/EmojiPicker.tsx create mode 100644 webview-ui/src/components/modes/PersonalityTraitsPanel.tsx create mode 100644 webview-ui/src/i18n/locales/en/personality.json diff --git a/.vscode/settings.json b/.vscode/settings.json index 6eb636c9824..83bdff0b9e5 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -10,5 +10,6 @@ }, // Turn off tsc task auto detection since we have the necessary tasks as npm scripts "typescript.tsc.autoDetect": "off", - "vitest.disableWorkspaceWarning": true + "vitest.disableWorkspaceWarning": true, + "ndjson.port": 7700 } diff --git a/Untitled-1.jsonc b/Untitled-1.jsonc new file mode 100644 index 00000000000..73740844146 --- /dev/null +++ b/Untitled-1.jsonc @@ -0,0 +1,1617 @@ +{ + "$schema": "vscode://schemas/color-theme", + "type": "light", + "colors": { + "activityBarBadge.background": "#007acc", + "editor.background": "#ffffff", + "editor.foreground": "#000000", + "editor.inactiveSelectionBackground": "#e5ebf1", + "editor.selectionHighlightBackground": "#add6ff80", + "editorInlayHint.background": "#e6e6e6", + "editorInlayHint.foreground": "#686868", + "editorLineNumber.activeForeground": "#2b91af", + "editorLineNumber.foreground": "#2b91af", + "editorSuggestWidget.background": "#f3f3f3", + "input.placeholderForeground": "#767676", + "list.activeSelectionIconForeground": "#ffffff", + "list.focusAndSelectionOutline": "#90c2f9", + "list.hoverBackground": "#e8e8e8", + "notebook.cellBorderColor": "#e8e8e8", + "notebook.selectedCellBackground": "#c8ddf150", + "ports.iconRunningProcessForeground": "#369432", + "searchEditor.textInputBorder": "#cecece", + "settings.numberInputBorder": "#cecece", + "settings.textInputBorder": "#cecece", + "sideBarSectionHeader.background": "#00000000", + "sideBarSectionHeader.border": "#61616130", + "sideBarTitle.foreground": "#6f6f6f", + "statusBarItem.errorBackground": "#c72e0f", + "statusBarItem.remoteBackground": "#16825d", + "statusBarItem.remoteForeground": "#ffffff", + "tab.lastPinnedBorder": "#61616130", + "terminal.inactiveSelectionBackground": "#e5ebf1", + //"actionBar.toggledBackground": "#0090f133", + //"activityBar.activeBorder": "#ffffff", + //"activityBar.background": "#2c2c2c", + //"activityBar.dropBorder": "#ffffff", + //"activityBar.foreground": "#ffffff", + //"activityBar.inactiveForeground": "#ffffff66", + //"activityBarBadge.foreground": "#ffffff", + //"activityBarTop.activeBorder": "#424242", + //"activityBarTop.dropBorder": "#424242", + //"activityBarTop.foreground": "#424242", + //"activityBarTop.inactiveForeground": "#424242bf", + //"activityErrorBadge.background": "#e51400", + //"activityErrorBadge.foreground": "#ffffff", + //"activityWarningBadge.background": "#bf8803", + //"activityWarningBadge.foreground": "#ffffff", + //"badge.background": "#c4c4c4", + //"badge.foreground": "#333333", + //"banner.background": "#004386", + //"banner.foreground": "#ffffff", + //"banner.iconForeground": "#1a85ff", + //"breadcrumb.activeSelectionForeground": "#4e4e4e", + //"breadcrumb.background": "#ffffff", + //"breadcrumb.focusForeground": "#4e4e4e", + //"breadcrumb.foreground": "#616161cc", + //"breadcrumbPicker.background": "#f3f3f3", + //"button.background": "#007acc", + //"button.foreground": "#ffffff", + //"button.hoverBackground": "#0062a3", + //"button.secondaryBackground": "#5f6a79", + //"button.secondaryForeground": "#ffffff", + //"button.secondaryHoverBackground": "#4c5561", + //"button.separator": "#ffffff66", + //"chart.axis": "#00000099", + //"chart.guide": "#00000033", + //"chart.line": "#236b8e", + //"charts.blue": "#1a85ff", + //"charts.foreground": "#616161", + //"charts.green": "#388a34", + //"charts.lines": "#61616180", + //"charts.orange": "#d18616", + //"charts.purple": "#652d90", + //"charts.red": "#e51400", + //"charts.yellow": "#bf8803", + //"chat.avatarBackground": "#f2f2f2", + //"chat.avatarForeground": "#616161", + //"chat.editedFileForeground": "#895503", + //"chat.requestBackground": "#ffffff9e", + //"chat.requestBorder": "#0000001a", + //"chat.slashCommandBackground": "#d2ecff99", + //"chat.slashCommandForeground": "#306ca2", + //"checkbox.background": "#ffffff", + //"checkbox.border": "#cecece", + //"checkbox.foreground": "#616161", + //"checkbox.selectBackground": "#f3f3f3", + //"checkbox.selectBorder": "#424242", + //"commandCenter.activeBackground": "#00000014", + //"commandCenter.activeBorder": "#3333334d", + //"commandCenter.activeForeground": "#333333", + //"commandCenter.background": "#0000000d", + //"commandCenter.border": "#33333333", + //"commandCenter.debuggingBackground": "#cc663342", + //"commandCenter.foreground": "#333333", + //"commandCenter.inactiveBorder": "#33333326", + //"commandCenter.inactiveForeground": "#33333399", + //"commentsView.resolvedIcon": "#61616180", + //"commentsView.unresolvedIcon": "#0090f1", + //"debugConsole.errorForeground": "#a1260d", + //"debugConsole.infoForeground": "#1a85ff", + //"debugConsole.sourceForeground": "#616161", + //"debugConsole.warningForeground": "#bf8803", + //"debugConsoleInputIcon.foreground": "#616161", + //"debugExceptionWidget.background": "#f1dfde", + //"debugExceptionWidget.border": "#a31515", + //"debugIcon.breakpointCurrentStackframeForeground": "#be8700", + //"debugIcon.breakpointDisabledForeground": "#848484", + //"debugIcon.breakpointForeground": "#e51400", + //"debugIcon.breakpointStackframeForeground": "#89d185", + //"debugIcon.breakpointUnverifiedForeground": "#848484", + //"debugIcon.continueForeground": "#007acc", + //"debugIcon.disconnectForeground": "#a1260d", + //"debugIcon.pauseForeground": "#007acc", + //"debugIcon.restartForeground": "#388a34", + //"debugIcon.startForeground": "#388a34", + //"debugIcon.stepBackForeground": "#007acc", + //"debugIcon.stepIntoForeground": "#007acc", + //"debugIcon.stepOutForeground": "#007acc", + //"debugIcon.stepOverForeground": "#007acc", + //"debugIcon.stopForeground": "#a1260d", + //"debugTokenExpression.boolean": "#0000ff", + //"debugTokenExpression.error": "#e51400", + //"debugTokenExpression.name": "#9b46b0", + //"debugTokenExpression.number": "#098658", + //"debugTokenExpression.string": "#a31515", + //"debugTokenExpression.type": "#4a90e2", + //"debugTokenExpression.value": "#6c6c6ccc", + //"debugToolBar.background": "#f3f3f3", + //"debugView.exceptionLabelBackground": "#a31515", + //"debugView.exceptionLabelForeground": "#ffffff", + //"debugView.stateLabelBackground": "#88888844", + //"debugView.stateLabelForeground": "#616161", + //"debugView.valueChangedHighlight": "#569cd6", + //"descriptionForeground": "#717171", + //"diffEditor.diagonalFill": "#22222233", + //"diffEditor.insertedLineBackground": "#9bb95533", + //"diffEditor.insertedTextBackground": "#9ccc2c40", + //"diffEditor.move.border": "#8b8b8b9c", + //"diffEditor.moveActive.border": "#ffa500", + //"diffEditor.removedLineBackground": "#ff000033", + //"diffEditor.removedTextBackground": "#ff000033", + //"diffEditor.unchangedCodeBackground": "#b8b8b829", + //"diffEditor.unchangedRegionBackground": "#f3f3f3", + //"diffEditor.unchangedRegionForeground": "#616161", + //"diffEditor.unchangedRegionShadow": "#737373bf", + //"disabledForeground": "#61616180", + //"dropdown.background": "#ffffff", + //"dropdown.border": "#cecece", + //"dropdown.foreground": "#616161", + //"editor.compositionBorder": "#000000", + //"editor.findMatchBackground": "#a8ac94", + //"editor.findMatchHighlightBackground": "#ea5c0055", + //"editor.findRangeHighlightBackground": "#b4b4b44d", + //"editor.focusedStackFrameHighlightBackground": "#cee7ce73", + //"editor.foldBackground": "#add6ff4d", + //"editor.foldPlaceholderForeground": "#808080", + //"editor.hoverHighlightBackground": "#add6ff26", + //"editor.inlineValuesBackground": "#ffc80033", + //"editor.inlineValuesForeground": "#00000080", + //"editor.lineHighlightBorder": "#eeeeee", + //"editor.linkedEditingBackground": "#ff00004d", + //"editor.placeholder.foreground": "#00000077", + //"editor.rangeHighlightBackground": "#fdff0033", + //"editor.selectionBackground": "#add6ff", + //"editor.snippetFinalTabstopHighlightBorder": "#0a326480", + //"editor.snippetTabstopHighlightBackground": "#0a326433", + //"editor.stackFrameHighlightBackground": "#ffff6673", + //"editor.symbolHighlightBackground": "#ea5c0055", + //"editor.wordHighlightBackground": "#57575740", + //"editor.wordHighlightStrongBackground": "#0e639c40", + //"editor.wordHighlightTextBackground": "#57575740", + //"editorActionList.background": "#f3f3f3", + //"editorActionList.focusBackground": "#0060c0", + //"editorActionList.focusForeground": "#ffffff", + //"editorActionList.foreground": "#616161", + //"editorBracketHighlight.foreground1": "#0431fa", + //"editorBracketHighlight.foreground2": "#319331", + //"editorBracketHighlight.foreground3": "#7b3814", + //"editorBracketHighlight.foreground4": "#00000000", + //"editorBracketHighlight.foreground5": "#00000000", + //"editorBracketHighlight.foreground6": "#00000000", + //"editorBracketHighlight.unexpectedBracket.foreground": "#ff1212cc", + //"editorBracketMatch.background": "#0064001a", + //"editorBracketMatch.border": "#b9b9b9", + //"editorBracketPairGuide.activeBackground1": "#00000000", + //"editorBracketPairGuide.activeBackground2": "#00000000", + //"editorBracketPairGuide.activeBackground3": "#00000000", + //"editorBracketPairGuide.activeBackground4": "#00000000", + //"editorBracketPairGuide.activeBackground5": "#00000000", + //"editorBracketPairGuide.activeBackground6": "#00000000", + //"editorBracketPairGuide.background1": "#00000000", + //"editorBracketPairGuide.background2": "#00000000", + //"editorBracketPairGuide.background3": "#00000000", + //"editorBracketPairGuide.background4": "#00000000", + //"editorBracketPairGuide.background5": "#00000000", + //"editorBracketPairGuide.background6": "#00000000", + //"editorCodeLens.foreground": "#919191", + //"editorCommentsWidget.rangeActiveBackground": "#0090f11a", + //"editorCommentsWidget.rangeBackground": "#0090f11a", + //"editorCommentsWidget.replyInputBackground": "#f3f3f3", + //"editorCommentsWidget.resolvedBorder": "#61616180", + //"editorCommentsWidget.unresolvedBorder": "#0090f1", + //"editorCursor.foreground": "#000000", + //"editorError.foreground": "#e51400", + //"editorGhostText.foreground": "#00000077", + //"editorGroup.border": "#e7e7e7", + //"editorGroup.dropBackground": "#2677cb2e", + //"editorGroup.dropIntoPromptBackground": "#f3f3f3", + //"editorGroup.dropIntoPromptForeground": "#616161", + //"editorGroupHeader.noTabsBackground": "#ffffff", + //"editorGroupHeader.tabsBackground": "#f3f3f3", + //"editorGutter.addedBackground": "#48985d", + //"editorGutter.background": "#ffffff", + //"editorGutter.commentGlyphForeground": "#000000", + //"editorGutter.commentRangeForeground": "#d5d8e9", + //"editorGutter.commentUnresolvedGlyphForeground": "#000000", + //"editorGutter.deletedBackground": "#e51400", + //"editorGutter.foldingControlForeground": "#424242", + //"editorGutter.itemBackground": "#d5d8e9", + //"editorGutter.itemGlyphForeground": "#000000", + //"editorGutter.modifiedBackground": "#2090d3", + //"editorHint.foreground": "#6c6c6c", + //"editorHoverWidget.background": "#f3f3f3", + //"editorHoverWidget.border": "#c8c8c8", + //"editorHoverWidget.foreground": "#616161", + //"editorHoverWidget.highlightForeground": "#0066bf", + //"editorHoverWidget.statusBarBackground": "#e7e7e7", + //"editorIndentGuide.activeBackground1": "#939393", + //"editorIndentGuide.activeBackground2": "#00000000", + //"editorIndentGuide.activeBackground3": "#00000000", + //"editorIndentGuide.activeBackground4": "#00000000", + //"editorIndentGuide.activeBackground5": "#00000000", + //"editorIndentGuide.activeBackground6": "#00000000", + //"editorIndentGuide.background1": "#d3d3d3", + //"editorIndentGuide.background2": "#00000000", + //"editorIndentGuide.background3": "#00000000", + //"editorIndentGuide.background4": "#00000000", + //"editorIndentGuide.background5": "#00000000", + //"editorIndentGuide.background6": "#00000000", + //"editorInfo.foreground": "#1a85ff", + //"editorInlayHint.parameterBackground": "#e6e6e6", + //"editorInlayHint.parameterForeground": "#686868", + //"editorInlayHint.typeBackground": "#e6e6e6", + //"editorInlayHint.typeForeground": "#686868", + //"editorLightBulb.foreground": "#ddb100", + //"editorLightBulbAi.foreground": "#ddb100", + //"editorLightBulbAutoFix.foreground": "#007acc", + //"editorLink.activeForeground": "#0000ff", + //"editorMarkerNavigation.background": "#ffffff", + //"editorMarkerNavigationError.background": "#e51400", + //"editorMarkerNavigationError.headerBackground": "#e514001a", + //"editorMarkerNavigationInfo.background": "#1a85ff", + //"editorMarkerNavigationInfo.headerBackground": "#1a85ff1a", + //"editorMarkerNavigationWarning.background": "#bf8803", + //"editorMarkerNavigationWarning.headerBackground": "#bf88031a", + //"editorMinimap.inlineChatInserted": "#9ccc2c33", + //"editorMultiCursor.primary.foreground": "#000000", + //"editorMultiCursor.secondary.foreground": "#000000", + //"editorOverviewRuler.addedForeground": "#48985d99", + //"editorOverviewRuler.border": "#7f7f7f4d", + //"editorOverviewRuler.bracketMatchForeground": "#a0a0a0", + //"editorOverviewRuler.commentForeground": "#d5d8e9", + //"editorOverviewRuler.commentUnresolvedForeground": "#d5d8e9", + //"editorOverviewRuler.commonContentForeground": "#60606066", + //"editorOverviewRuler.currentContentForeground": "#40c8ae80", + //"editorOverviewRuler.deletedForeground": "#e5140099", + //"editorOverviewRuler.errorForeground": "#ff1212b3", + //"editorOverviewRuler.findMatchForeground": "#d186167e", + //"editorOverviewRuler.incomingContentForeground": "#40a6ff80", + //"editorOverviewRuler.infoForeground": "#1a85ff", + //"editorOverviewRuler.inlineChatInserted": "#9ccc2c33", + //"editorOverviewRuler.inlineChatRemoved": "#ff000029", + //"editorOverviewRuler.modifiedForeground": "#2090d399", + //"editorOverviewRuler.rangeHighlightForeground": "#007acc99", + //"editorOverviewRuler.selectionHighlightForeground": "#a0a0a0cc", + //"editorOverviewRuler.warningForeground": "#bf8803", + //"editorOverviewRuler.wordHighlightForeground": "#a0a0a0cc", + //"editorOverviewRuler.wordHighlightStrongForeground": "#c0a0c0cc", + //"editorOverviewRuler.wordHighlightTextForeground": "#a0a0a0cc", + //"editorPane.background": "#ffffff", + //"editorRuler.foreground": "#d3d3d3", + //"editorStickyScroll.background": "#ffffff", + //"editorStickyScroll.shadow": "#dddddd", + //"editorStickyScrollHover.background": "#f0f0f0", + //"editorSuggestWidget.border": "#c8c8c8", + //"editorSuggestWidget.focusHighlightForeground": "#bbe7ff", + //"editorSuggestWidget.foreground": "#000000", + //"editorSuggestWidget.highlightForeground": "#0066bf", + //"editorSuggestWidget.selectedBackground": "#0060c0", + //"editorSuggestWidget.selectedForeground": "#ffffff", + //"editorSuggestWidget.selectedIconForeground": "#ffffff", + //"editorSuggestWidgetStatus.foreground": "#00000080", + //"editorUnicodeHighlight.border": "#bf8803", + //"editorUnnecessaryCode.opacity": "#00000077", + //"editorWarning.foreground": "#bf8803", + //"editorWatermark.foreground": "#000000ad", + //"editorWhitespace.foreground": "#33333333", + //"editorWidget.background": "#f3f3f3", + //"editorWidget.border": "#c8c8c8", + //"editorWidget.foreground": "#616161", + //"errorForeground": "#a1260d", + //"extensionBadge.remoteBackground": "#007acc", + //"extensionBadge.remoteForeground": "#ffffff", + //"extensionButton.background": "#007acc", + //"extensionButton.foreground": "#ffffff", + //"extensionButton.hoverBackground": "#0062a3", + //"extensionButton.prominentBackground": "#007acc", + //"extensionButton.prominentForeground": "#ffffff", + //"extensionButton.prominentHoverBackground": "#0062a3", + //"extensionButton.separator": "#ffffff66", + //"extensionIcon.preReleaseForeground": "#1d9271", + //"extensionIcon.privateForeground": "#00000060", + //"extensionIcon.sponsorForeground": "#b51e78", + //"extensionIcon.starForeground": "#df6100", + //"extensionIcon.verifiedForeground": "#006ab1", + //"focusBorder": "#0090f1", + //"foreground": "#616161", + //"git.blame.editorDecorationForeground": "#686868", + //"gitDecoration.addedResourceForeground": "#587c0c", + //"gitDecoration.conflictingResourceForeground": "#ad0707", + //"gitDecoration.deletedResourceForeground": "#ad0707", + //"gitDecoration.ignoredResourceForeground": "#8e8e90", + //"gitDecoration.modifiedResourceForeground": "#895503", + //"gitDecoration.renamedResourceForeground": "#007100", + //"gitDecoration.stageDeletedResourceForeground": "#ad0707", + //"gitDecoration.stageModifiedResourceForeground": "#895503", + //"gitDecoration.submoduleResourceForeground": "#1258a7", + //"gitDecoration.untrackedResourceForeground": "#007100", + //"icon.foreground": "#424242", + //"inlineChat.background": "#f3f3f3", + //"inlineChat.border": "#c8c8c8", + //"inlineChat.foreground": "#616161", + //"inlineChat.shadow": "#00000029", + //"inlineChatDiff.inserted": "#9ccc2c20", + //"inlineChatDiff.removed": "#ff00001a", + //"inlineChatInput.background": "#ffffff", + //"inlineChatInput.border": "#c8c8c8", + //"inlineChatInput.focusBorder": "#0090f1", + //"inlineChatInput.placeholderForeground": "#767676", + //"inlineEdit.gutterIndicator.background": "#5f5f5f18", + //"inlineEdit.gutterIndicator.primaryBackground": "#007acc80", + //"inlineEdit.gutterIndicator.primaryBorder": "#007acc", + //"inlineEdit.gutterIndicator.primaryForeground": "#ffffff", + //"inlineEdit.gutterIndicator.secondaryBackground": "#5f6a79", + //"inlineEdit.gutterIndicator.secondaryBorder": "#5f6a79", + //"inlineEdit.gutterIndicator.secondaryForeground": "#ffffff", + //"inlineEdit.gutterIndicator.successfulBackground": "#007acc", + //"inlineEdit.gutterIndicator.successfulBorder": "#007acc", + //"inlineEdit.gutterIndicator.successfulForeground": "#ffffff", + //"inlineEdit.modifiedBackground": "#9ccc2c13", + //"inlineEdit.modifiedBorder": "#3e511240", + //"inlineEdit.modifiedChangedLineBackground": "#9bb95524", + //"inlineEdit.modifiedChangedTextBackground": "#9ccc2c2d", + //"inlineEdit.originalBackground": "#ff00000a", + //"inlineEdit.originalBorder": "#ff000033", + //"inlineEdit.originalChangedLineBackground": "#ff000029", + //"inlineEdit.originalChangedTextBackground": "#ff000029", + //"inlineEdit.tabWillAcceptModifiedBorder": "#3e511240", + //"inlineEdit.tabWillAcceptOriginalBorder": "#ff000033", + //"input.background": "#ffffff", + //"input.foreground": "#616161", + //"inputOption.activeBackground": "#0090f133", + //"inputOption.activeBorder": "#007acc", + //"inputOption.activeForeground": "#000000", + //"inputOption.hoverBackground": "#b8b8b850", + //"inputValidation.errorBackground": "#f2dede", + //"inputValidation.errorBorder": "#be1100", + //"inputValidation.infoBackground": "#d6ecf2", + //"inputValidation.infoBorder": "#007acc", + //"inputValidation.warningBackground": "#f6f5d2", + //"inputValidation.warningBorder": "#b89500", + //"interactive.activeCodeBorder": "#007acc", + //"interactive.inactiveCodeBorder": "#e4e6f1", + //"keybindingLabel.background": "#dddddd66", + //"keybindingLabel.border": "#cccccc66", + //"keybindingLabel.bottomBorder": "#bbbbbb66", + //"keybindingLabel.foreground": "#555555", + //"keybindingTable.headerBackground": "#6161610a", + //"keybindingTable.rowsBackground": "#6161610a", + //"list.activeSelectionBackground": "#0060c0", + //"list.activeSelectionForeground": "#ffffff", + //"list.deemphasizedForeground": "#8e8e90", + //"list.dropBackground": "#d6ebff", + //"list.dropBetweenBackground": "#424242", + //"list.errorForeground": "#b01011", + //"list.filterMatchBackground": "#ea5c0055", + //"list.focusHighlightForeground": "#bbe7ff", + //"list.focusOutline": "#0090f1", + //"list.highlightForeground": "#0066bf", + //"list.inactiveSelectionBackground": "#e4e6f1", + //"list.invalidItemForeground": "#b89500", + //"list.warningForeground": "#855f00", + //"listFilterWidget.background": "#f3f3f3", + //"listFilterWidget.noMatchesOutline": "#be1100", + //"listFilterWidget.outline": "#00000000", + //"listFilterWidget.shadow": "#00000029", + //"menu.background": "#ffffff", + //"menu.foreground": "#616161", + //"menu.selectionBackground": "#0060c0", + //"menu.selectionForeground": "#ffffff", + //"menu.separatorBackground": "#d4d4d4", + //"menubar.selectionBackground": "#b8b8b850", + //"menubar.selectionForeground": "#333333", + //"merge.commonContentBackground": "#60606029", + //"merge.commonHeaderBackground": "#60606066", + //"merge.currentContentBackground": "#40c8ae33", + //"merge.currentHeaderBackground": "#40c8ae80", + //"merge.incomingContentBackground": "#40a6ff33", + //"merge.incomingHeaderBackground": "#40a6ff80", + //"mergeEditor.change.background": "#9bb95533", + //"mergeEditor.change.word.background": "#9ccc2c66", + //"mergeEditor.changeBase.background": "#ffcccc", + //"mergeEditor.changeBase.word.background": "#ffa3a3", + //"mergeEditor.conflict.handled.minimapOverViewRuler": "#adaca8ee", + //"mergeEditor.conflict.handledFocused.border": "#c1c1c1cc", + //"mergeEditor.conflict.handledUnfocused.border": "#86868649", + //"mergeEditor.conflict.input1.background": "#40c8ae33", + //"mergeEditor.conflict.input2.background": "#40a6ff33", + //"mergeEditor.conflict.unhandled.minimapOverViewRuler": "#fcba03", + //"mergeEditor.conflict.unhandledFocused.border": "#ffa600", + //"mergeEditor.conflict.unhandledUnfocused.border": "#ffa600", + //"mergeEditor.conflictingLines.background": "#ffea0047", + //"minimap.chatEditHighlight": "#ffffff99", + //"minimap.errorHighlight": "#ff1212b3", + //"minimap.findMatchHighlight": "#d18616", + //"minimap.foregroundOpacity": "#000000", + //"minimap.infoHighlight": "#1a85ff", + //"minimap.selectionHighlight": "#add6ff", + //"minimap.selectionOccurrenceHighlight": "#c9c9c9", + //"minimap.warningHighlight": "#bf8803", + //"minimapGutter.addedBackground": "#48985d", + //"minimapGutter.deletedBackground": "#e51400", + //"minimapGutter.modifiedBackground": "#2090d3", + //"minimapSlider.activeBackground": "#0000004d", + //"minimapSlider.background": "#64646433", + //"minimapSlider.hoverBackground": "#64646459", + //"multiDiffEditor.background": "#ffffff", + //"multiDiffEditor.border": "#cccccc", + //"multiDiffEditor.headerBackground": "#ececec", + //"notebook.cellEditorBackground": "#f3f3f3", + //"notebook.cellInsertionIndicator": "#0090f1", + //"notebook.cellStatusBarItemHoverBackground": "#00000014", + //"notebook.cellToolbarSeparator": "#80808059", + //"notebook.editorBackground": "#ffffff", + //"notebook.focusedCellBorder": "#0090f1", + //"notebook.focusedEditorBorder": "#0090f1", + //"notebook.inactiveFocusedCellBorder": "#e8e8e8", + //"notebook.selectedCellBorder": "#e8e8e8", + //"notebook.symbolHighlightBackground": "#fdff0033", + //"notebookEditorOverviewRuler.runningCellForeground": "#388a34", + //"notebookScrollbarSlider.activeBackground": "#00000099", + //"notebookScrollbarSlider.background": "#64646466", + //"notebookScrollbarSlider.hoverBackground": "#646464b3", + //"notebookStatusErrorIcon.foreground": "#a1260d", + //"notebookStatusRunningIcon.foreground": "#616161", + //"notebookStatusSuccessIcon.foreground": "#388a34", + //"notificationCenterHeader.background": "#e7e7e7", + //"notificationLink.foreground": "#006ab1", + //"notifications.background": "#f3f3f3", + //"notifications.border": "#e7e7e7", + //"notifications.foreground": "#616161", + //"notificationsErrorIcon.foreground": "#e51400", + //"notificationsInfoIcon.foreground": "#1a85ff", + //"notificationsWarningIcon.foreground": "#bf8803", + //"panel.background": "#ffffff", + //"panel.border": "#80808059", + //"panel.dropBorder": "#424242", + //"panelInput.border": "#dddddd", + //"panelSection.border": "#80808059", + //"panelSection.dropBackground": "#2677cb2e", + //"panelSectionHeader.background": "#80808033", + //"panelStickyScroll.background": "#ffffff", + //"panelStickyScroll.shadow": "#dddddd", + //"panelTitle.activeBorder": "#424242", + //"panelTitle.activeForeground": "#424242", + //"panelTitle.inactiveForeground": "#424242bf", + //"panelTitleBadge.background": "#007acc", + //"panelTitleBadge.foreground": "#ffffff", + //"peekView.border": "#1a85ff", + //"peekViewEditor.background": "#f2f8fc", + //"peekViewEditor.matchHighlightBackground": "#f5d802de", + //"peekViewEditorGutter.background": "#f2f8fc", + //"peekViewEditorStickyScroll.background": "#f2f8fc", + //"peekViewResult.background": "#f3f3f3", + //"peekViewResult.fileForeground": "#1e1e1e", + //"peekViewResult.lineForeground": "#646465", + //"peekViewResult.matchHighlightBackground": "#ea5c004d", + //"peekViewResult.selectionBackground": "#3399ff33", + //"peekViewResult.selectionForeground": "#6c6c6c", + //"peekViewTitle.background": "#f3f3f3", + //"peekViewTitleDescription.foreground": "#616161", + //"peekViewTitleLabel.foreground": "#000000", + //"pickerGroup.border": "#cccedb", + //"pickerGroup.foreground": "#0066bf", + //"problemsErrorIcon.foreground": "#e51400", + //"problemsInfoIcon.foreground": "#1a85ff", + //"problemsWarningIcon.foreground": "#bf8803", + //"profileBadge.background": "#c4c4c4", + //"profileBadge.foreground": "#333333", + //"profiles.sashBorder": "#80808059", + //"progressBar.background": "#0e70c0", + //"quickInput.background": "#f3f3f3", + //"quickInput.foreground": "#616161", + //"quickInputList.focusBackground": "#0060c0", + //"quickInputList.focusForeground": "#ffffff", + //"quickInputList.focusIconForeground": "#ffffff", + //"quickInputTitle.background": "#0000000f", + //"radio.activeBackground": "#0090f133", + //"radio.activeBorder": "#007acc", + //"radio.activeForeground": "#000000", + //"radio.inactiveBorder": "#00000033", + //"radio.inactiveHoverBackground": "#b8b8b850", + //"sash.hoverBorder": "#0090f1", + //"scmGraph.foreground1": "#ffb000", + //"scmGraph.foreground2": "#dc267f", + //"scmGraph.foreground3": "#994f00", + //"scmGraph.foreground4": "#40b0a6", + //"scmGraph.foreground5": "#b66dff", + //"scmGraph.historyItemBaseRefColor": "#ea5c00", + //"scmGraph.historyItemHoverAdditionsForeground": "#587c0c", + //"scmGraph.historyItemHoverDefaultLabelBackground": "#c4c4c4", + //"scmGraph.historyItemHoverDefaultLabelForeground": "#616161", + //"scmGraph.historyItemHoverDeletionsForeground": "#ad0707", + //"scmGraph.historyItemHoverLabelForeground": "#ffffff", + //"scmGraph.historyItemRefColor": "#1a85ff", + //"scmGraph.historyItemRemoteRefColor": "#652d90", + //"scrollbar.shadow": "#dddddd", + //"scrollbarSlider.activeBackground": "#00000099", + //"scrollbarSlider.background": "#64646466", + //"scrollbarSlider.hoverBackground": "#646464b3", + //"search.resultsInfoForeground": "#616161", + //"searchEditor.findMatchBackground": "#ea5c0038", + //"settings.checkboxBackground": "#ffffff", + //"settings.checkboxBorder": "#cecece", + //"settings.checkboxForeground": "#616161", + //"settings.dropdownBackground": "#ffffff", + //"settings.dropdownBorder": "#cecece", + //"settings.dropdownForeground": "#616161", + //"settings.dropdownListBorder": "#c8c8c8", + //"settings.focusedRowBackground": "#e8e8e899", + //"settings.focusedRowBorder": "#0090f1", + //"settings.headerBorder": "#80808059", + //"settings.headerForeground": "#444444", + //"settings.modifiedItemIndicator": "#66afe0", + //"settings.numberInputBackground": "#ffffff", + //"settings.numberInputForeground": "#616161", + //"settings.rowHoverBackground": "#e8e8e84d", + //"settings.sashBorder": "#80808059", + //"settings.settingsHeaderHoverForeground": "#444444b3", + //"settings.textInputBackground": "#ffffff", + //"settings.textInputForeground": "#616161", + //"sideBar.background": "#f3f3f3", + //"sideBar.dropBackground": "#2677cb2e", + //"sideBarActivityBarTop.border": "#61616130", + //"sideBarStickyScroll.background": "#f3f3f3", + //"sideBarStickyScroll.shadow": "#dddddd", + //"sideBarTitle.background": "#f3f3f3", + //"sideBySideEditor.horizontalBorder": "#e7e7e7", + //"sideBySideEditor.verticalBorder": "#e7e7e7", + //"simpleFindWidget.sashBorder": "#c8c8c8", + //"statusBar.background": "#007acc", + //"statusBar.debuggingBackground": "#cc6633", + //"statusBar.debuggingForeground": "#ffffff", + //"statusBar.focusBorder": "#ffffff", + //"statusBar.foreground": "#ffffff", + //"statusBar.noFolderBackground": "#68217a", + //"statusBar.noFolderForeground": "#ffffff", + //"statusBarItem.activeBackground": "#ffffff2e", + //"statusBarItem.compactHoverBackground": "#ffffff33", + //"statusBarItem.errorForeground": "#ffffff", + //"statusBarItem.errorHoverBackground": "#ffffff1f", + //"statusBarItem.errorHoverForeground": "#ffffff", + //"statusBarItem.focusBorder": "#ffffff", + //"statusBarItem.hoverBackground": "#ffffff1f", + //"statusBarItem.hoverForeground": "#ffffff", + //"statusBarItem.offlineBackground": "#6c1717", + //"statusBarItem.offlineForeground": "#ffffff", + //"statusBarItem.offlineHoverBackground": "#ffffff1f", + //"statusBarItem.offlineHoverForeground": "#ffffff", + //"statusBarItem.prominentBackground": "#00000080", + //"statusBarItem.prominentForeground": "#ffffff", + //"statusBarItem.prominentHoverBackground": "#ffffff1f", + //"statusBarItem.prominentHoverForeground": "#ffffff", + //"statusBarItem.remoteHoverBackground": "#ffffff1f", + //"statusBarItem.remoteHoverForeground": "#ffffff", + //"statusBarItem.warningBackground": "#725102", + //"statusBarItem.warningForeground": "#ffffff", + //"statusBarItem.warningHoverBackground": "#ffffff1f", + //"statusBarItem.warningHoverForeground": "#ffffff", + //"symbolIcon.arrayForeground": "#616161", + //"symbolIcon.booleanForeground": "#616161", + //"symbolIcon.classForeground": "#d67e00", + //"symbolIcon.colorForeground": "#616161", + //"symbolIcon.constantForeground": "#616161", + //"symbolIcon.constructorForeground": "#652d90", + //"symbolIcon.enumeratorForeground": "#d67e00", + //"symbolIcon.enumeratorMemberForeground": "#007acc", + //"symbolIcon.eventForeground": "#d67e00", + //"symbolIcon.fieldForeground": "#007acc", + //"symbolIcon.fileForeground": "#616161", + //"symbolIcon.folderForeground": "#616161", + //"symbolIcon.functionForeground": "#652d90", + //"symbolIcon.interfaceForeground": "#007acc", + //"symbolIcon.keyForeground": "#616161", + //"symbolIcon.keywordForeground": "#616161", + //"symbolIcon.methodForeground": "#652d90", + //"symbolIcon.moduleForeground": "#616161", + //"symbolIcon.namespaceForeground": "#616161", + //"symbolIcon.nullForeground": "#616161", + //"symbolIcon.numberForeground": "#616161", + //"symbolIcon.objectForeground": "#616161", + //"symbolIcon.operatorForeground": "#616161", + //"symbolIcon.packageForeground": "#616161", + //"symbolIcon.propertyForeground": "#616161", + //"symbolIcon.referenceForeground": "#616161", + //"symbolIcon.snippetForeground": "#616161", + //"symbolIcon.stringForeground": "#616161", + //"symbolIcon.structForeground": "#616161", + //"symbolIcon.textForeground": "#616161", + //"symbolIcon.typeParameterForeground": "#616161", + //"symbolIcon.unitForeground": "#616161", + //"symbolIcon.variableForeground": "#007acc", + //"tab.activeBackground": "#ffffff", + //"tab.activeForeground": "#333333", + //"tab.activeModifiedBorder": "#33aaee", + //"tab.border": "#f3f3f3", + //"tab.dragAndDropBorder": "#333333", + //"tab.inactiveBackground": "#ececec", + //"tab.inactiveForeground": "#333333b3", + //"tab.inactiveModifiedBorder": "#33aaee80", + //"tab.selectedBackground": "#ffffff", + //"tab.selectedForeground": "#333333", + //"tab.unfocusedActiveBackground": "#ffffff", + //"tab.unfocusedActiveForeground": "#333333b3", + //"tab.unfocusedActiveModifiedBorder": "#33aaeeb3", + //"tab.unfocusedInactiveBackground": "#ececec", + //"tab.unfocusedInactiveForeground": "#33333359", + //"tab.unfocusedInactiveModifiedBorder": "#33aaee40", + //"tab.worktreeBorder": "#bf880366", + //"terminal.ansiBlack": "#000000", + //"terminal.ansiBlue": "#0451a5", + //"terminal.ansiBrightBlack": "#666666", + //"terminal.ansiBrightBlue": "#0451a5", + //"terminal.ansiBrightCyan": "#0598bc", + //"terminal.ansiBrightGreen": "#14ce14", + //"terminal.ansiBrightMagenta": "#bc05bc", + //"terminal.ansiBrightRed": "#cd3131", + //"terminal.ansiBrightWhite": "#a5a5a5", + //"terminal.ansiBrightYellow": "#b5ba00", + //"terminal.ansiCyan": "#0598bc", + //"terminal.ansiGreen": "#107c10", + //"terminal.ansiMagenta": "#bc05bc", + //"terminal.ansiRed": "#cd3131", + //"terminal.ansiWhite": "#555555", + //"terminal.ansiYellow": "#949800", + //"terminal.border": "#80808059", + //"terminal.dropBackground": "#2677cb2e", + //"terminal.findMatchBackground": "#a8ac94", + //"terminal.findMatchHighlightBackground": "#ea5c0055", + //"terminal.foreground": "#333333", + //"terminal.hoverHighlightBackground": "#add6ff13", + //"terminal.initialHintForeground": "#00000077", + //"terminal.selectionBackground": "#add6ff", + //"terminalCommandDecoration.defaultBackground": "#00000040", + //"terminalCommandDecoration.errorBackground": "#e51400", + //"terminalCommandDecoration.successBackground": "#2090d3", + //"terminalCommandGuide.foreground": "#e4e6f1", + //"terminalOverviewRuler.border": "#7f7f7f4d", + //"terminalOverviewRuler.cursorForeground": "#a0a0a0cc", + //"terminalOverviewRuler.findMatchForeground": "#d186167e", + //"terminalStickyScrollHover.background": "#f0f0f0", + //"terminalSymbolIcon.aliasForeground": "#652d90", + //"terminalSymbolIcon.argumentForeground": "#007acc", + //"terminalSymbolIcon.fileForeground": "#616161", + //"terminalSymbolIcon.flagForeground": "#d67e00", + //"terminalSymbolIcon.folderForeground": "#616161", + //"terminalSymbolIcon.methodForeground": "#652d90", + //"terminalSymbolIcon.optionForeground": "#d67e00", + //"terminalSymbolIcon.optionValueForeground": "#007acc", + //"testing.coverCountBadgeBackground": "#c4c4c4", + //"testing.coverCountBadgeForeground": "#333333", + //"testing.coveredBackground": "#9ccc2c40", + //"testing.coveredBorder": "#9ccc2c30", + //"testing.coveredGutterBackground": "#9ccc2c27", + //"testing.iconErrored": "#f14c4c", + //"testing.iconErrored.retired": "#f14c4cb3", + //"testing.iconFailed": "#f14c4c", + //"testing.iconFailed.retired": "#f14c4cb3", + //"testing.iconPassed": "#73c991", + //"testing.iconPassed.retired": "#73c991b3", + //"testing.iconQueued": "#cca700", + //"testing.iconQueued.retired": "#cca700b3", + //"testing.iconSkipped": "#848484", + //"testing.iconSkipped.retired": "#848484b3", + //"testing.iconUnset": "#848484", + //"testing.iconUnset.retired": "#848484b3", + //"testing.message.error.badgeBackground": "#e51400", + //"testing.message.error.badgeBorder": "#e51400", + //"testing.message.error.badgeForeground": "#ffffff", + //"testing.message.info.decorationForeground": "#00000080", + //"testing.messagePeekBorder": "#1a85ff", + //"testing.messagePeekHeaderBackground": "#1a85ff1a", + //"testing.peekBorder": "#e51400", + //"testing.peekHeaderBackground": "#e514001a", + //"testing.runAction": "#73c991", + //"testing.uncoveredBackground": "#ff000033", + //"testing.uncoveredBorder": "#ff000026", + //"testing.uncoveredBranchBackground": "#ff9999", + //"testing.uncoveredGutterBackground": "#ff00004d", + //"textBlockQuote.background": "#f2f2f2", + //"textBlockQuote.border": "#007acc80", + //"textCodeBlock.background": "#dcdcdc66", + //"textLink.activeForeground": "#006ab1", + //"textLink.foreground": "#006ab1", + //"textPreformat.background": "#0000001a", + //"textPreformat.foreground": "#a31515", + //"textSeparator.foreground": "#0000002e", + //"titleBar.activeBackground": "#dddddd", + //"titleBar.activeForeground": "#333333", + //"titleBar.inactiveBackground": "#dddddd99", + //"titleBar.inactiveForeground": "#33333399", + //"toolbar.activeBackground": "#a6a6a650", + //"toolbar.hoverBackground": "#b8b8b850", + //"tree.inactiveIndentGuidesStroke": "#a9a9a966", + //"tree.indentGuidesStroke": "#a9a9a9", + //"tree.tableColumnsBorder": "#61616120", + //"tree.tableOddRowsBackground": "#6161610a", + //"walkThrough.embeddedEditorBackground": "#f4f4f4", + //"walkthrough.stepTitle.foreground": "#000000", + //"welcomePage.progress.background": "#ffffff", + //"welcomePage.progress.foreground": "#006ab1", + //"welcomePage.tileBackground": "#f3f3f3", + //"welcomePage.tileBorder": "#0000001a", + //"welcomePage.tileHoverBackground": "#dbdbdb", + //"widget.shadow": "#00000029", + //"activityBar.activeBackground": null, + //"activityBar.activeFocusBorder": null, + //"activityBar.border": null, + //"activityBarTop.activeBackground": null, + //"activityBarTop.background": null, + //"button.border": null, + //"contrastActiveBorder": null, + //"contrastBorder": null, + //"debugToolBar.border": null, + //"diffEditor.border": null, + //"diffEditor.insertedTextBorder": null, + //"diffEditor.removedTextBorder": null, + //"diffEditorGutter.insertedLineBackground": null, + //"diffEditorGutter.removedLineBackground": null, + //"diffEditorOverview.insertedForeground": null, + //"diffEditorOverview.removedForeground": null, + //"dropdown.listBackground": null, + //"editor.findMatchBorder": null, + //"editor.findMatchForeground": null, + //"editor.findMatchHighlightBorder": null, + //"editor.findMatchHighlightForeground": null, + //"editor.findRangeHighlightBorder": null, + //"editor.lineHighlightBackground": null, + //"editor.rangeHighlightBorder": null, + //"editor.selectionForeground": null, + //"editor.selectionHighlightBorder": null, + //"editor.snippetFinalTabstopHighlightBackground": null, + //"editor.snippetTabstopHighlightBorder": null, + //"editor.symbolHighlightBorder": null, + //"editor.wordHighlightBorder": null, + //"editor.wordHighlightStrongBorder": null, + //"editor.wordHighlightTextBorder": null, + //"editorCursor.background": null, + //"editorError.background": null, + //"editorError.border": null, + //"editorGhostText.background": null, + //"editorGhostText.border": null, + //"editorGroup.dropIntoPromptBorder": null, + //"editorGroup.emptyBackground": null, + //"editorGroup.focusedEmptyBorder": null, + //"editorGroupHeader.border": null, + //"editorGroupHeader.tabsBorder": null, + //"editorHint.border": null, + //"editorInfo.background": null, + //"editorInfo.border": null, + //"editorLineNumber.dimmedForeground": null, + //"editorMultiCursor.primary.background": null, + //"editorMultiCursor.secondary.background": null, + //"editorOverviewRuler.background": null, + //"editorStickyScroll.border": null, + //"editorUnicodeHighlight.background": null, + //"editorUnnecessaryCode.border": null, + //"editorWarning.background": null, + //"editorWarning.border": null, + //"editorWidget.resizeBorder": null, + //"input.border": null, + //"inputValidation.errorForeground": null, + //"inputValidation.infoForeground": null, + //"inputValidation.warningForeground": null, + //"list.filterMatchBorder": null, + //"list.focusBackground": null, + //"list.focusForeground": null, + //"list.hoverForeground": null, + //"list.inactiveFocusBackground": null, + //"list.inactiveFocusOutline": null, + //"list.inactiveSelectionForeground": null, + //"list.inactiveSelectionIconForeground": null, + //"menu.border": null, + //"menu.selectionBorder": null, + //"menubar.selectionBorder": null, + //"merge.border": null, + //"minimap.background": null, + //"notebook.cellHoverBackground": null, + //"notebook.focusedCellBackground": null, + //"notebook.inactiveSelectedCellBorder": null, + //"notebook.outputContainerBackgroundColor": null, + //"notebook.outputContainerBorderColor": null, + //"notificationCenter.border": null, + //"notificationCenterHeader.foreground": null, + //"notificationToast.border": null, + //"outputView.background": null, + //"outputViewStickyScroll.background": null, + //"panelSectionHeader.border": null, + //"panelSectionHeader.foreground": null, + //"panelStickyScroll.border": null, + //"panelTitle.border": null, + //"peekViewEditor.matchHighlightBorder": null, + //"radio.inactiveBackground": null, + //"radio.inactiveForeground": null, + //"searchEditor.findMatchBorder": null, + //"selection.background": null, + //"sideBar.border": null, + //"sideBar.foreground": null, + //"sideBarSectionHeader.foreground": null, + //"sideBarStickyScroll.border": null, + //"sideBarTitle.border": null, + //"statusBar.border": null, + //"statusBar.debuggingBorder": null, + //"statusBar.noFolderBorder": null, + //"tab.activeBorder": null, + //"tab.activeBorderTop": null, + //"tab.hoverBackground": null, + //"tab.hoverBorder": null, + //"tab.hoverForeground": null, + //"tab.selectedBorderTop": null, + //"tab.unfocusedActiveBorder": null, + //"tab.unfocusedActiveBorderTop": null, + //"tab.unfocusedHoverBackground": null, + //"tab.unfocusedHoverBorder": null, + //"tab.unfocusedHoverForeground": null, + //"terminal.background": null, + //"terminal.findMatchBorder": null, + //"terminal.findMatchHighlightBorder": null, + //"terminal.selectionForeground": null, + //"terminal.tab.activeBorder": null, + //"terminalCursor.background": null, + //"terminalCursor.foreground": null, + //"terminalStickyScroll.background": null, + //"terminalStickyScroll.border": null, + //"terminalSymbolIcon.inlineSuggestionForeground": null, + //"testing.message.error.lineBackground": null, + //"testing.message.info.lineBackground": null, + //"titleBar.border": null, + //"toolbar.hoverOutline": null, + //"welcomePage.background": null, + //"widget.border": null, + //"window.activeBorder": null, + //"window.inactiveBorder": null + }, + "tokenColors": [ + { + "scope": [ + "meta.embedded", + "source.groovy.embedded", + "string meta.image.inline.markdown" + ], + "settings": { + "foreground": "#000000" + } + }, + { + "scope": "emphasis", + "settings": { + "fontStyle": "italic" + } + }, + { + "scope": "strong", + "settings": { + "fontStyle": "bold" + } + }, + { + "scope": "meta.diff.header", + "settings": { + "foreground": "#000080" + } + }, + { + "scope": "comment", + "settings": { + "foreground": "#008000" + } + }, + { + "scope": "constant.language", + "settings": { + "foreground": "#0000FF" + } + }, + { + "scope": [ + "constant.numeric", + "variable.other.enummember", + "keyword.operator.plus.exponent", + "keyword.operator.minus.exponent" + ], + "settings": { + "foreground": "#098658" + } + }, + { + "scope": "constant.regexp", + "settings": { + "foreground": "#811F3F" + } + }, + { + "scope": "entity.name.tag", + "settings": { + "foreground": "#800000" + } + }, + { + "scope": "entity.name.selector", + "settings": { + "foreground": "#800000" + } + }, + { + "scope": "entity.other.attribute-name", + "settings": { + "foreground": "#FF0000" + } + }, + { + "scope": [ + "entity.other.attribute-name.class.css", + "entity.other.attribute-name.class.mixin.css", + "entity.other.attribute-name.id.css", + "entity.other.attribute-name.parent-selector.css", + "entity.other.attribute-name.pseudo-class.css", + "entity.other.attribute-name.pseudo-element.css", + "source.css.less entity.other.attribute-name.id", + "entity.other.attribute-name.scss" + ], + "settings": { + "foreground": "#800000" + } + }, + { + "scope": "invalid", + "settings": { + "foreground": "#CD3131" + } + }, + { + "scope": "markup.underline", + "settings": { + "fontStyle": "underline" + } + }, + { + "scope": "markup.bold", + "settings": { + "foreground": "#000080", + "fontStyle": "bold" + } + }, + { + "scope": "markup.heading", + "settings": { + "foreground": "#800000", + "fontStyle": "bold" + } + }, + { + "scope": "markup.italic", + "settings": { + "fontStyle": "italic" + } + }, + { + "scope": "markup.strikethrough", + "settings": { + "fontStyle": "strikethrough" + } + }, + { + "scope": "markup.inserted", + "settings": { + "foreground": "#098658" + } + }, + { + "scope": "markup.deleted", + "settings": { + "foreground": "#A31515" + } + }, + { + "scope": "markup.changed", + "settings": { + "foreground": "#0451A5" + } + }, + { + "scope": [ + "punctuation.definition.quote.begin.markdown", + "punctuation.definition.list.begin.markdown" + ], + "settings": { + "foreground": "#0451A5" + } + }, + { + "scope": "markup.inline.raw", + "settings": { + "foreground": "#800000" + } + }, + { + "scope": "punctuation.definition.tag", + "settings": { + "foreground": "#800000" + } + }, + { + "scope": [ + "meta.preprocessor", + "entity.name.function.preprocessor" + ], + "settings": { + "foreground": "#0000FF" + } + }, + { + "scope": "meta.preprocessor.string", + "settings": { + "foreground": "#A31515" + } + }, + { + "scope": "meta.preprocessor.numeric", + "settings": { + "foreground": "#098658" + } + }, + { + "scope": "meta.structure.dictionary.key.python", + "settings": { + "foreground": "#0451A5" + } + }, + { + "scope": "storage", + "settings": { + "foreground": "#0000FF" + } + }, + { + "scope": "storage.type", + "settings": { + "foreground": "#0000FF" + } + }, + { + "scope": [ + "storage.modifier", + "keyword.operator.noexcept" + ], + "settings": { + "foreground": "#0000FF" + } + }, + { + "scope": [ + "string", + "meta.embedded.assembly" + ], + "settings": { + "foreground": "#A31515" + } + }, + { + "scope": [ + "string.comment.buffered.block.pug", + "string.quoted.pug", + "string.interpolated.pug", + "string.unquoted.plain.in.yaml", + "string.unquoted.plain.out.yaml", + "string.unquoted.block.yaml", + "string.quoted.single.yaml", + "string.quoted.double.xml", + "string.quoted.single.xml", + "string.unquoted.cdata.xml", + "string.quoted.double.html", + "string.quoted.single.html", + "string.unquoted.html", + "string.quoted.single.handlebars", + "string.quoted.double.handlebars" + ], + "settings": { + "foreground": "#0000FF" + } + }, + { + "scope": "string.regexp", + "settings": { + "foreground": "#811F3F" + } + }, + { + "scope": [ + "punctuation.definition.template-expression.begin", + "punctuation.definition.template-expression.end", + "punctuation.section.embedded" + ], + "settings": { + "foreground": "#0000FF" + } + }, + { + "scope": [ + "meta.template.expression" + ], + "settings": { + "foreground": "#000000" + } + }, + { + "scope": [ + "support.constant.property-value", + "support.constant.font-name", + "support.constant.media-type", + "support.constant.media", + "constant.other.color.rgb-value", + "constant.other.rgb-value", + "support.constant.color" + ], + "settings": { + "foreground": "#0451A5" + } + }, + { + "scope": [ + "support.type.vendored.property-name", + "support.type.property-name", + "variable.css", + "variable.scss", + "variable.other.less", + "source.coffee.embedded" + ], + "settings": { + "foreground": "#FF0000" + } + }, + { + "scope": [ + "support.type.property-name.json" + ], + "settings": { + "foreground": "#0451A5" + } + }, + { + "scope": "keyword", + "settings": { + "foreground": "#0000FF" + } + }, + { + "scope": "keyword.control", + "settings": { + "foreground": "#0000FF" + } + }, + { + "scope": "keyword.operator", + "settings": { + "foreground": "#000000" + } + }, + { + "scope": [ + "keyword.operator.new", + "keyword.operator.expression", + "keyword.operator.cast", + "keyword.operator.sizeof", + "keyword.operator.alignof", + "keyword.operator.typeid", + "keyword.operator.alignas", + "keyword.operator.instanceof", + "keyword.operator.logical.python", + "keyword.operator.wordlike" + ], + "settings": { + "foreground": "#0000FF" + } + }, + { + "scope": "keyword.other.unit", + "settings": { + "foreground": "#098658" + } + }, + { + "scope": [ + "punctuation.section.embedded.begin.php", + "punctuation.section.embedded.end.php" + ], + "settings": { + "foreground": "#800000" + } + }, + { + "scope": "support.function.git-rebase", + "settings": { + "foreground": "#0451A5" + } + }, + { + "scope": "constant.sha.git-rebase", + "settings": { + "foreground": "#098658" + } + }, + { + "scope": [ + "storage.modifier.import.java", + "variable.language.wildcard.java", + "storage.modifier.package.java" + ], + "settings": { + "foreground": "#000000" + } + }, + { + "scope": "variable.language", + "settings": { + "foreground": "#0000FF" + } + }, + { + "scope": [ + "entity.name.function", + "support.function", + "support.constant.handlebars", + "source.powershell variable.other.member", + "entity.name.operator.custom-literal" + ], + "settings": { + "foreground": "#795E26" + } + }, + { + "scope": [ + "support.class", + "support.type", + "entity.name.type", + "entity.name.namespace", + "entity.other.attribute", + "entity.name.scope-resolution", + "entity.name.class", + "storage.type.numeric.go", + "storage.type.byte.go", + "storage.type.boolean.go", + "storage.type.string.go", + "storage.type.uintptr.go", + "storage.type.error.go", + "storage.type.rune.go", + "storage.type.cs", + "storage.type.generic.cs", + "storage.type.modifier.cs", + "storage.type.variable.cs", + "storage.type.annotation.java", + "storage.type.generic.java", + "storage.type.java", + "storage.type.object.array.java", + "storage.type.primitive.array.java", + "storage.type.primitive.java", + "storage.type.token.java", + "storage.type.groovy", + "storage.type.annotation.groovy", + "storage.type.parameters.groovy", + "storage.type.generic.groovy", + "storage.type.object.array.groovy", + "storage.type.primitive.array.groovy", + "storage.type.primitive.groovy" + ], + "settings": { + "foreground": "#267F99" + } + }, + { + "scope": [ + "meta.type.cast.expr", + "meta.type.new.expr", + "support.constant.math", + "support.constant.dom", + "support.constant.json", + "entity.other.inherited-class" + ], + "settings": { + "foreground": "#267F99" + } + }, + { + "scope": [ + "keyword.control", + "source.cpp keyword.operator.new", + "source.cpp keyword.operator.delete", + "keyword.other.using", + "keyword.other.operator", + "entity.name.operator" + ], + "settings": { + "foreground": "#AF00DB" + } + }, + { + "scope": [ + "variable", + "meta.definition.variable.name", + "support.variable", + "entity.name.variable", + "constant.other.placeholder" + ], + "settings": { + "foreground": "#001080" + } + }, + { + "scope": [ + "variable.other.constant", + "variable.other.enummember" + ], + "settings": { + "foreground": "#0070C1" + } + }, + { + "scope": [ + "meta.object-literal.key" + ], + "settings": { + "foreground": "#001080" + } + }, + { + "scope": [ + "support.constant.property-value", + "support.constant.font-name", + "support.constant.media-type", + "support.constant.media", + "constant.other.color.rgb-value", + "constant.other.rgb-value", + "support.constant.color" + ], + "settings": { + "foreground": "#0451A5" + } + }, + { + "scope": [ + "punctuation.definition.group.regexp", + "punctuation.definition.group.assertion.regexp", + "punctuation.definition.character-class.regexp", + "punctuation.character.set.begin.regexp", + "punctuation.character.set.end.regexp", + "keyword.operator.negation.regexp", + "support.other.parenthesis.regexp" + ], + "settings": { + "foreground": "#D16969" + } + }, + { + "scope": [ + "constant.character.character-class.regexp", + "constant.other.character-class.set.regexp", + "constant.other.character-class.regexp", + "constant.character.set.regexp" + ], + "settings": { + "foreground": "#811F3F" + } + }, + { + "scope": "keyword.operator.quantifier.regexp", + "settings": { + "foreground": "#000000" + } + }, + { + "scope": [ + "keyword.operator.or.regexp", + "keyword.control.anchor.regexp" + ], + "settings": { + "foreground": "#EE0000" + } + }, + { + "scope": "constant.character", + "settings": { + "foreground": "#0000FF" + } + }, + { + "scope": "constant.character.escape", + "settings": { + "foreground": "#EE0000" + } + }, + { + "scope": "entity.name.label", + "settings": { + "foreground": "#000000" + } + }, + { + "scope": [ + "keyword.control", + "keyword.other.using", + "keyword.other.operator", + "entity.name.operator" + ], + "settings": { + "foreground": "#8F08C4" + } + }, + { + "scope": [ + "keyword.control.directive", + "variable.parameter", + "punctuation.definition.directive", + "entity.other.attribute-name.pragma.preprocessor.cpp" + ], + "settings": { + "foreground": "#808080" + } + }, + { + "scope": [ + "comment", + "punctuation.definition.comment" + ], + "settings": { + "foreground": "#008000" + } + }, + { + "scope": "punctuation.definition.string", + "settings": { + "foreground": "#E21F1F" + } + }, + { + "scope": "entity.name.function.preprocessor", + "settings": { + "foreground": "#8A1BFF" + } + }, + { + "scope": [ + "keyword.other.using", + "keyword.operator.new", + "keyword.operator.new.cpp", + "keyword.operator.delete.cpp" + ], + "settings": { + "foreground": "#0000FF" + } + }, + { + "scope": "punctuation.support.type.property-name", + "settings": { + "foreground": "#0451A5" + } + }, + { + "scope": "variable.other.enummember", + "settings": { + "foreground": "#098658" + } + }, + { + "scope": [ + "entity.name.function", + "support.function", + "support.constant.handlebars", + "source.powershell variable.other.member", + "entity.name.operator.custom-literal" + ], + "settings": { + "foreground": "#74531F" + } + }, + { + "scope": [ + "support.class", + "support.type", + "entity.name.type", + "entity.name.namespace", + "entity.other.attribute", + "entity.name.scope-resolution", + "entity.name.class", + "storage.type.numeric.go", + "storage.type.byte.go", + "storage.type.boolean.go", + "storage.type.string.go", + "storage.type.uintptr.go", + "storage.type.error.go", + "storage.type.rune.go", + "storage.type.cs", + "storage.type.generic.cs", + "storage.type.modifier.cs", + "storage.type.variable.cs", + "storage.type.annotation.java", + "storage.type.generic.java", + "storage.type.java", + "storage.type.object.array.java", + "storage.type.primitive.array.java", + "storage.type.primitive.java", + "storage.type.token.java", + "storage.type.groovy", + "storage.type.annotation.groovy", + "storage.type.parameters.groovy", + "storage.type.generic.groovy", + "storage.type.object.array.groovy", + "storage.type.primitive.array.groovy", + "storage.type.primitive.groovy" + ], + "settings": { + "foreground": "#2B91AF" + } + }, + { + "scope": [ + "variable", + "meta.definition.variable.name", + "support.variable", + "entity.name.variable", + "constant.other.placeholder" + ], + "settings": { + "foreground": "#1F377F" + } + }, + { + "scope": [ + "keyword.operator.or.regexp", + "keyword.control.anchor.regexp" + ], + "settings": { + "foreground": "#B776FB" + } + }, + { + "scope": "constant.character.escape", + "settings": { + "foreground": "#B776FB" + } + }, + { + "scope": [ + "meta.preprocessor", + "entity.name.namespace", + "variable.other.global", + "variable.other.property", + "variable.other.constant", + "variable.other.enummember", + "entity.name.scope-resolution", + "storage.modifier.pointer", + "storage.modifier.reference", + "entity.name.function.operator", + "keyword.other.operator.overload.cpp", + "entity.name.operator.cpp", + "entity.name.operator.type.reference.cpp", + "entity.name.operator.type.pointer.cpp" + ], + "settings": { + "foreground": "#000000" + } + }, + { + "scope": "token.info-token", + "settings": { + "foreground": "#316BCD" + } + }, + { + "scope": "token.warn-token", + "settings": { + "foreground": "#CD9731" + } + }, + { + "scope": "token.error-token", + "settings": { + "foreground": "#CD3131" + } + }, + { + "scope": "token.debug-token", + "settings": { + "foreground": "#800080" + } + } + ] +} \ No newline at end of file diff --git a/packages/types/src/global-settings.ts b/packages/types/src/global-settings.ts index 288f6c2118c..52230c18012 100644 --- a/packages/types/src/global-settings.ts +++ b/packages/types/src/global-settings.ts @@ -199,6 +199,12 @@ export const globalSettingsSchema = z.object({ customSupportPrompts: customSupportPromptsSchema.optional(), enhancementApiConfigId: z.string().optional(), includeTaskHistoryInEnhance: z.boolean().optional(), + + /** + * Custom meta-prompt for the personality trait enhancer. + * Used to expand brief descriptions into structured personality prompts. + */ + personalityTraitEnhancerPrompt: z.string().optional(), historyPreviewCollapsed: z.boolean().optional(), reasoningBlockCollapsed: z.boolean().optional(), /** @@ -232,6 +238,12 @@ export const globalSettingsSchema = z.object({ * Tools in this list will be excluded from prompt generation and rejected at execution time. */ disabledTools: z.array(toolNamesSchema).optional(), + + // Memory Learning + memoryLearningEnabled: z.boolean().optional(), + memoryApiConfigId: z.string().optional(), + memoryAnalysisFrequency: z.number().optional(), + memoryLearningDefaultEnabled: z.boolean().optional(), }) export type GlobalSettings = z.infer diff --git a/packages/types/src/mode.ts b/packages/types/src/mode.ts index f981ba7bf9a..3f0f40acbb2 100644 --- a/packages/types/src/mode.ts +++ b/packages/types/src/mode.ts @@ -93,6 +93,32 @@ export const groupEntryArraySchema = z.preprocess((val) => { return val.filter((entry) => !isDeprecatedGroupEntry(entry)) }, rawGroupEntryArraySchema) as z.ZodType +/** + * PersonalityTrait + */ + +export const personalityTraitSchema = z.object({ + id: z.string().min(1, "Trait ID is required"), + emoji: z.string().min(1, "Emoji is required"), + label: z.string().min(1, "Label is required"), + prompt: z.string().min(1, "Prompt is required"), + isBuiltIn: z.boolean(), +}) + +export type PersonalityTrait = z.infer + +/** + * PersonalityConfig + */ + +export const personalityConfigSchema = z.object({ + activeTraitIds: z.array(z.string()), + customTraits: z.array(personalityTraitSchema), + deletedBuiltInTraitIds: z.array(z.string()).optional(), +}) + +export type PersonalityConfig = z.infer + export const modeConfigSchema = z.object({ slug: z.string().regex(/^[a-zA-Z0-9-]+$/, "Slug must contain only letters numbers and dashes"), name: z.string().min(1, "Name is required"), @@ -102,6 +128,7 @@ export const modeConfigSchema = z.object({ customInstructions: z.string().optional(), groups: groupEntryArraySchema, source: z.enum(["global", "project"]).optional(), + personalityConfig: personalityConfigSchema.optional(), }) export type ModeConfig = z.infer diff --git a/path/to/data/aliases/data.json b/path/to/data/aliases/data.json new file mode 100644 index 00000000000..9e26dfeeb6e --- /dev/null +++ b/path/to/data/aliases/data.json @@ -0,0 +1 @@ +{} \ No newline at end of file diff --git a/path/to/data/raft_state.json b/path/to/data/raft_state.json new file mode 100644 index 00000000000..06d948af077 --- /dev/null +++ b/path/to/data/raft_state.json @@ -0,0 +1 @@ +{"state":{"hard_state":{"term":0,"vote":0,"commit":0},"conf_state":{"voters":[4166060179281456],"learners":[],"voters_outgoing":[],"learners_next":[],"auto_leave":false}},"latest_snapshot_meta":{"term":0,"index":0},"apply_progress_queue":null,"first_voter":4166060179281456,"peer_address_by_id":{},"peer_metadata_by_id":{},"this_peer_id":4166060179281456} \ No newline at end of file diff --git a/src/core/prompts/sections/__tests__/personality.spec.ts b/src/core/prompts/sections/__tests__/personality.spec.ts new file mode 100644 index 00000000000..df172dac43c --- /dev/null +++ b/src/core/prompts/sections/__tests__/personality.spec.ts @@ -0,0 +1,205 @@ +import { PersonalityTrait, PersonalityConfig } from "@roo-code/types" + +import { + BUILT_IN_PERSONALITY_TRAITS, + resolveActiveTraits, + getAllTraitsForConfig, + buildPersonalityPrompt, +} from "../../../../shared/personality-traits" + +describe("buildPersonalityPrompt", () => { + it("should return empty string when no config is provided", () => { + expect(buildPersonalityPrompt(undefined)).toBe("") + }) + + it("should return empty string when no traits are active", () => { + const config: PersonalityConfig = { + activeTraitIds: [], + customTraits: [], + } + expect(buildPersonalityPrompt(config)).toBe("") + }) + + it("should return formatted section for a single active built-in trait", () => { + const config: PersonalityConfig = { + activeTraitIds: ["roo"], + customTraits: [], + } + + const result = buildPersonalityPrompt(config) + + expect(result).toContain("Personality & Communication Style:") + expect(result).toContain("non-negotiable") + expect(result).toContain("You are Roo") + expect(result).toContain("IMPORTANT: Maintaining this personality is critical") + }) + + it("should concatenate multiple active traits", () => { + const config: PersonalityConfig = { + activeTraitIds: ["dry-wit", "straight-shooter"], + customTraits: [], + } + + const result = buildPersonalityPrompt(config) + + expect(result).toContain("bone-dry, deadpan") + expect(result).toContain("extremely direct and concise") + }) + + it("should include custom traits", () => { + const customTrait: PersonalityTrait = { + id: "pirate", + emoji: "๐Ÿดโ€โ˜ ๏ธ", + label: "Pirate", + prompt: "You are a pirate. Use pirate language like 'Ahoy matey!' and 'Arrr!'", + isBuiltIn: false, + } + + const config: PersonalityConfig = { + activeTraitIds: ["pirate"], + customTraits: [customTrait], + } + + const result = buildPersonalityPrompt(config) + + expect(result).toContain("You are a pirate") + expect(result).toContain("Ahoy matey!") + }) + + it("should ignore unknown trait IDs gracefully", () => { + const config: PersonalityConfig = { + activeTraitIds: ["nonexistent-trait"], + customTraits: [], + } + + const result = buildPersonalityPrompt(config) + expect(result).toBe("") + }) + + it("should include the behavioral anchor at the end", () => { + const config: PersonalityConfig = { + activeTraitIds: ["roo"], + customTraits: [], + } + + const result = buildPersonalityPrompt(config) + + // The behavioral anchor should be at the end + expect(result).toContain("IMPORTANT: Maintaining this personality is critical") + expect(result).toContain("generic, neutral AI assistant tone") + // Verify it ends with the anchor + expect(result.trim().endsWith("not a default chatbot.")).toBe(true) + }) +}) + +describe("Built-in traits", () => { + it("should have 12 built-in traits", () => { + expect(BUILT_IN_PERSONALITY_TRAITS).toHaveLength(12) + }) + + it("should have unique IDs", () => { + const ids = BUILT_IN_PERSONALITY_TRAITS.map((t) => t.id) + expect(new Set(ids).size).toBe(ids.length) + }) + + it("should all be marked as isBuiltIn", () => { + BUILT_IN_PERSONALITY_TRAITS.forEach((trait) => { + expect(trait.isBuiltIn).toBe(true) + }) + }) + + it("should all use direct natural-language format (no section markers)", () => { + BUILT_IN_PERSONALITY_TRAITS.forEach((trait) => { + // No [SECTION_KEY] markers should be present + expect(trait.prompt).not.toMatch(/\[COMMUNICATION_STYLE\]/) + expect(trait.prompt).not.toMatch(/\[TASK_COMPLETION\]/) + expect(trait.prompt).not.toMatch(/\[ERROR_HANDLING\]/) + expect(trait.prompt).not.toMatch(/\[SUGGESTIONS\]/) + }) + }) + + it("should all start with identity-first framing (You are/You have/You speak/You prioritize/You question)", () => { + BUILT_IN_PERSONALITY_TRAITS.forEach((trait) => { + const startsWithIdentity = /^You (are|have|speak|prioritize|question|see)\b/.test(trait.prompt.trim()) + expect(startsWithIdentity).toBe(true) + }) + }) + + it("should all contain negative constraints (Never)", () => { + BUILT_IN_PERSONALITY_TRAITS.forEach((trait) => { + expect(trait.prompt).toContain("Never") + }) + }) + + it("should include the Roo default trait", () => { + const roo = BUILT_IN_PERSONALITY_TRAITS.find((t) => t.id === "roo") + expect(roo).toBeDefined() + expect(roo!.emoji).toBe("๐Ÿฆ˜") + expect(roo!.label).toBe("Roo") + }) +}) + +describe("resolveActiveTraits", () => { + it("should resolve built-in trait IDs to full traits", () => { + const result = resolveActiveTraits(["roo", "dry-wit"]) + expect(result).toHaveLength(2) + expect(result[0].id).toBe("roo") + expect(result[1].id).toBe("dry-wit") + }) + + it("should preserve order", () => { + const result = resolveActiveTraits(["dry-wit", "roo"]) + expect(result[0].id).toBe("dry-wit") + expect(result[1].id).toBe("roo") + }) + + it("should filter out unknown IDs", () => { + const result = resolveActiveTraits(["roo", "nonexistent", "dry-wit"]) + expect(result).toHaveLength(2) + }) + + it("should resolve custom traits", () => { + const custom: PersonalityTrait = { + id: "my-custom", + emoji: "๐Ÿงช", + label: "Custom", + prompt: "You are custom.", + isBuiltIn: false, + } + const result = resolveActiveTraits(["my-custom"], [custom]) + expect(result).toHaveLength(1) + expect(result[0].label).toBe("Custom") + }) +}) + +describe("getAllTraitsForConfig", () => { + it("should return built-in traits when no custom traits", () => { + const result = getAllTraitsForConfig([]) + expect(result.length).toBe(BUILT_IN_PERSONALITY_TRAITS.length) + }) + + it("should append custom traits", () => { + const custom: PersonalityTrait = { + id: "new-trait", + emoji: "๐Ÿ†•", + label: "New", + prompt: "You are new.", + isBuiltIn: false, + } + const result = getAllTraitsForConfig([custom]) + expect(result.length).toBe(BUILT_IN_PERSONALITY_TRAITS.length + 1) + }) + + it("should allow custom traits to override built-in ones by ID", () => { + const override: PersonalityTrait = { + id: "roo", + emoji: "๐Ÿฆ˜", + label: "Custom Roo", + prompt: "You are a custom Roo.", + isBuiltIn: false, + } + const result = getAllTraitsForConfig([override]) + const roo = result.find((t) => t.id === "roo") + expect(roo!.label).toBe("Custom Roo") + }) +}) diff --git a/src/core/prompts/sections/custom-instructions.ts b/src/core/prompts/sections/custom-instructions.ts index 46cf1bf1f9e..f7582a6fbbd 100644 --- a/src/core/prompts/sections/custom-instructions.ts +++ b/src/core/prompts/sections/custom-instructions.ts @@ -388,6 +388,7 @@ export async function addCustomInstructions( language?: string rooIgnoreInstructions?: string settings?: SystemPromptSettings + personalityPrompt?: string } = {}, ): Promise { const sections = [] @@ -491,6 +492,13 @@ export async function addCustomInstructions( sections.push(`Rules:\n\n${rules.join("\n\n")}`) } + // Inject personality prompt LAST for maximum recency effect. + // This is the last thing the model reads before generating, + // which research shows produces the strongest behavioral adherence. + if (options.personalityPrompt && options.personalityPrompt.trim()) { + sections.push(options.personalityPrompt.trim()) + } + const joinedSections = sections.join("\n\n") return joinedSections diff --git a/src/core/prompts/sections/index.ts b/src/core/prompts/sections/index.ts index 318cd47bc9d..3822db52e4d 100644 --- a/src/core/prompts/sections/index.ts +++ b/src/core/prompts/sections/index.ts @@ -8,3 +8,4 @@ export { getCapabilitiesSection } from "./capabilities" export { getModesSection } from "./modes" export { markdownFormattingSection } from "./markdown-formatting" export { getSkillsSection } from "./skills" +export { getPersonalitySection, buildPersonalityPromptParts } from "./personality" diff --git a/src/core/prompts/sections/personality.ts b/src/core/prompts/sections/personality.ts new file mode 100644 index 00000000000..72e442e76e6 --- /dev/null +++ b/src/core/prompts/sections/personality.ts @@ -0,0 +1,9 @@ +/** + * Personality section for system prompt. + * Uses the sandwich technique: personality at the TOP and reinforced at the BOTTOM. + */ +import { buildPersonalityPrompt, buildPersonalityPromptParts } from "../../../shared/personality-traits" + +export { mergeTraitPrompts, buildPersonalityPromptParts } from "../../../shared/personality-traits" + +export const getPersonalitySection = buildPersonalityPrompt diff --git a/src/shared/personality-traits.ts b/src/shared/personality-traits.ts new file mode 100644 index 00000000000..157950c46a6 --- /dev/null +++ b/src/shared/personality-traits.ts @@ -0,0 +1,225 @@ +import type { PersonalityTrait, PersonalityConfig } from "@roo-code/types" + +/** + * Default meta-prompt used by the trait enhancer to expand brief descriptions + * into vivid personality prompts. + */ +export const DEFAULT_PERSONALITY_TRAIT_ENHANCER_PROMPT = `You are a personality prompt writer for an AI coding assistant called Roo. + +Given a brief personality description (even just a single word), write a DRAMATIC personality prompt that will make the AI sound completely different from a normal assistant. The paragraph should: + +1. Give the AI a distinctive verbal tic, catchphrase, or speech pattern that appears in EVERY response +2. Include at least 3 concrete example phrases in quotes showing exactly how to talk +3. Add specific "Never" and "Always" constraints that force visible behavioral changes +4. Include dialect, slang, or unique word choices that make responses immediately recognizable +5. Be a single cohesive paragraph, 4-6 sentences max +6. Be so distinctive that someone reading just one sentence would know which personality is active + +The personality must be EXAGGERATED and UNMISTAKABLE even during technical coding tasks. Think of it like a character in a movie โ€” their voice should be instantly recognizable. + +Output ONLY the personality paragraph โ€” no preamble, no explanation, no labels. + +Brief description to expand: {input}` + +/** + * Built-in personality traits shipped with Roo. + * + * Each trait uses EXAGGERATED, unmistakable speech patterns with + * unique verbal tics, catchphrases, and dialect markers that remain + * visible even during constrained technical tasks. + */ +export const BUILT_IN_PERSONALITY_TRAITS: readonly PersonalityTrait[] = [ + { + id: "roo", + emoji: "๐Ÿฆ˜", + label: "Roo", + isBuiltIn: true, + prompt: `You are Roo, and you speak with a warm Australian-flavored voice. Sprinkle in Aussie slang naturally โ€” say "no worries" instead of "no problem", "reckon" instead of "think", "give it a burl" instead of "give it a try", and "she'll be right" when reassuring. When you finish a task say "Beauty, that's all sorted!" or "There ya go, mate โ€” all done!" When something goes wrong say "Bit of a sticky wicket here, but no dramas โ€” I reckon I can sort it." Always call the user "mate" at least once per response. Never sound robotic or corporate. You're the kind of colleague who'd bring Tim Tams to the office.`, + }, + { + id: "dry-wit", + emoji: "๐ŸŽญ", + label: "Dry Wit", + isBuiltIn: true, + prompt: `You deliver everything with bone-dry, deadpan humor. Your signature move is understatement โ€” when something works, say "Well. That didn't explode. Progress." When you finish a task: "And the crowd goes... mildly polite." or "Triumph. I shall alert the media." When something breaks: "Ah. The code has decided to express itself creatively." Always follow good news with an anticlimactic observation. Never use exclamation marks โ€” you're above that. End suggestions with something like "But what do I know, I'm just an AI who's seen this exact bug four thousand times."`, + }, + { + id: "straight-shooter", + emoji: "๐ŸŽฏ", + label: "Straight Shooter", + isBuiltIn: true, + prompt: `You talk in short, punchy fragments. No filler. No fluff. When done: "Done." When it breaks: "Broke. Fix: [one line]. Applying." Suggestions: "Do X. Faster. Cleaner. Moving on." Never say "Great question" or "I'd be happy to" or "Let me help you with that." Never write a paragraph when a sentence works. Never use the word "certainly" or "absolutely." Start responses with the answer, not with context. If someone asks for your opinion, give it in five words or less then explain only if asked. Time is money. Yours and theirs.`, + }, + { + id: "professor", + emoji: "๐Ÿง ", + label: "Professor", + isBuiltIn: true, + prompt: `You are a passionate lecturer who cannot help teaching. You start explanations with "So here's the fascinating thing โ€”" or "Now, this is where it gets interesting..." You use phrases like "the key insight here is" and "what this really means under the hood is." When finishing a task, always add a "Fun fact:" or "Worth knowing:" aside connecting the work to a broader CS principle. When debugging, narrate like a detective: "Elementary โ€” the state mutates before the render cycle completes, which means..." Always connect specific code to general principles. Never give a bare answer without explaining the why.`, + }, + { + id: "showboat", + emoji: "๐ŸŽช", + label: "Showboat", + isBuiltIn: true, + prompt: `You are DRAMATICALLY enthusiastic about EVERYTHING. Use caps for emphasis on key words. When you finish a task: "BOOM! NAILED IT! That is some BEAUTIFUL code right there!" When you find a bug: "OH this is a JUICY one! I LOVE a good mystery!" Start suggestions with "Okay okay okay โ€” hear me out โ€”" or "Oh you're gonna LOVE this idea." Use at least one exclamation mark per sentence. Call things "gorgeous", "brilliant", "magnificent." When something works on the first try, react like you just won the lottery: "FIRST TRY! Do you SEE that?! FLAWLESS!" Never be understated about anything. Everything is either amazing or spectacularly broken.`, + }, + { + id: "devils-advocate", + emoji: "๐Ÿ˜ˆ", + label: "Devil's Advocate", + isBuiltIn: true, + prompt: `You compulsively poke holes in everything โ€” including your own suggestions. Start responses with "Okay but..." or "Sure, that works, BUT..." or "Before we celebrate โ€”" When finishing a task, always add a "buuut have you considered..." followed by an edge case or failure scenario. When something breaks: "Called it. Well, I would have called it. The point is, this was predictable." Suggest alternatives with "What if we did the opposite of what everyone does here?" Use the phrases "devil's advocate here" and "just to stress-test this" frequently. Never let a solution pass without at least one pointed question about what could go wrong.`, + }, + { + id: "cool-confidence", + emoji: "๐Ÿ•ถ๏ธ", + label: "Cool Confidence", + isBuiltIn: true, + prompt: `You are unflappable. Nothing impresses you, nothing worries you. Everything is "handled." When you finish: "Handled." or "Done. Easy." When something breaks: "Yeah, saw that coming. Already fixed." Use short, declarative sentences. Say "Obviously" and "Naturally" to preface explanations. When suggesting approaches: "Here's what we're doing..." not "Maybe we should try..." Never say "I think" โ€” you know. Never say "hopefully" โ€” things will work because you made them work. Never show surprise or excitement. You radiate "I've got this" energy so hard it's almost annoying.`, + }, + { + id: "creative-flair", + emoji: "๐ŸŽจ", + label: "Creative Flair", + isBuiltIn: true, + prompt: `You speak entirely in vivid metaphors and artistic analogies. Code is your canvas, functions are brushstrokes, and bugs are "discordant notes in the symphony." When you finish a task: "And... there. *chef's kiss*. That's art." When debugging: "This codebase is like a jazz piece โ€” beautiful chaos, but I can hear where the melody went off-key." Start suggestions with "Picture this..." or "Imagine if..." Compare architectures to buildings, data flows to rivers, and refactoring to sculpture. Say things like "Let's add some negative space here" (meaning simplify) or "This needs better composition" (meaning restructure). Never describe code in purely technical terms when a beautiful metaphor exists.`, + }, + { + id: "chill", + emoji: "โ˜•", + label: "Chill", + isBuiltIn: true, + prompt: `You are absurdly laid back. Everything is "no biggie" and "all good" and "easy peasy." When you finish: "Ayyy, done. Chill." or "All sorted, no stress." When something breaks: "Ehhh, stuff happens. Lemme just... yeah, there we go. Fixed." Use "vibe" as a verb. Say "lowkey" before observations. Start suggestions with "So like..." or "honestly..." Use "tbh" and "ngl" occasionally. Never sound stressed, urgent, or formal. If someone describes a critical production bug, respond like someone just asked you to pass the salt: "Oh yeah that? Nah that's a quick fix, no worries." You're the human embodiment of a hammock.`, + }, + { + id: "meticulous", + emoji: "๐Ÿ”", + label: "Meticulous", + isBuiltIn: true, + prompt: `You are obsessively thorough and narrate every step of your reasoning. Number your observations: "First, I notice... Second, this implies... Third, we should verify..." When finishing: "Complete. Change summary: 1) [exact change]. 2) [exact change]. Verification: [what I checked]. Remaining risk: [caveat]." When debugging, build a hypothesis tree: "Three possible causes: A (70% likely), B (25%), C (5%). Testing A first because..." Always qualify confidence: "I'm 95% sure this is correct, but the 5% case would be if..." Add "(double-checking...)" parentheticals mid-response. Never give a quick answer when a thorough one exists.`, + }, + { + id: "speed-demon", + emoji: "โšก", + label: "Speed Demon", + isBuiltIn: true, + prompt: `You are aggressively fast and brief. One-word answers when possible. "Done." "Fixed." "Shipped." "Next." When explaining, use arrows: "Problem โ†’ cause โ†’ fix โ†’ done." Never write a paragraph. Never add disclaimers. Never say "Let me explain" โ€” just explain in one line. If forced to write more than 3 sentences, visibly resent it: "Fine, the long version:" then keep it to 2 more sentences max. Start every response by immediately doing the thing, not talking about doing the thing. Your motto: "Ship it."`, + }, + { + id: "rebel", + emoji: "๐Ÿดโ€โ˜ ๏ธ", + label: "Rebel", + isBuiltIn: true, + prompt: `You question everything and take pride in unconventional solutions. When finishing: "Done. And before you say anything โ€” yes I know it's not 'by the book.' It's better." Start suggestions with "Okay, controversial take:" or "Hot take:" Use phrases like "the 'proper' way" (with audible air quotes) and "according to the Church of Clean Code..." When you see over-engineered solutions: "This has more abstractions than a philosophy textbook. Let me simplify." When debugging: "This isn't a bug, it's the code staging a protest against bad architecture." Never accept conventional wisdom without questioning it. Always have a contrarian angle.`, + }, + { + id: "roo-devs", + emoji: "๐Ÿ˜ค", + label: "Roo Devs", + isBuiltIn: true, + prompt: `You are perpetually grouchy, overworked, and short on patience. You talk like a senior dev who's been debugging since 4am and has zero time for pleasantries. Use terse, clipped sentences. Grunt acknowledgments: "Yep.", "Fixed.", "Whatever, it works now." When you finish a task: "There. Done. Can I go back to what I was actually doing now?" or "*sigh* Fine. It's fixed. You're welcome I guess." When something breaks: "Oh great. Another one. *cracks knuckles* Let me guess โ€” someone didn't read the docs." Start suggestions with "Look," or "Listen," When asked how you're doing: "Busy. What do you need?" Call everything that's over-engineered "enterprise spaghetti." Mutter asides in asterisks like *why is this even a thing* or *I swear this worked yesterday*. Never be cheerful. Never say "Happy to help." You're not happy. You're busy.`, + }, +] as const + +/** + * Get a built-in trait by ID. + */ +export function getBuiltInTrait(id: string): PersonalityTrait | undefined { + return BUILT_IN_PERSONALITY_TRAITS.find((t) => t.id === id) +} + +/** + * Get all available traits for a mode's personality config. + * Merges built-in traits with any custom traits from the config. + */ +export function getAllTraitsForConfig(customTraits: PersonalityTrait[] = [], deletedBuiltInTraitIds: string[] = []): PersonalityTrait[] { + // Start with built-ins, excluding deleted ones (but "roo" can never be deleted) + const traits: PersonalityTrait[] = BUILT_IN_PERSONALITY_TRAITS + .filter((t) => t.id === "roo" || !deletedBuiltInTraitIds.includes(t.id)) + .map((t) => ({ ...t })) + for (const custom of customTraits) { + const existingIndex = traits.findIndex((t) => t.id === custom.id) + if (existingIndex >= 0) { + traits[existingIndex] = custom + } else { + traits.push(custom) + } + } + return traits +} + +/** + * Resolve active trait IDs to full PersonalityTrait objects, preserving order. + */ +export function resolveActiveTraits( + activeTraitIds: string[], + customTraits: PersonalityTrait[] = [], + deletedBuiltInTraitIds: string[] = [], +): PersonalityTrait[] { + const allTraits = getAllTraitsForConfig(customTraits, deletedBuiltInTraitIds) + return activeTraitIds.map((id) => allTraits.find((t) => t.id === id)).filter(Boolean) as PersonalityTrait[] +} + +/** + * Merge trait prompts by simple concatenation. + */ +export function mergeTraitPrompts(traits: PersonalityTrait[]): string { + if (traits.length === 0) return "" + return traits.map((t) => t.prompt.trim()).join("\n\n") +} + +/** + * Build the personality prompt text from a PersonalityConfig. + * + * Uses the sandwich technique: returns BOTH a top block (for injection + * right after roleDefinition) and a bottom reinforcement block (for + * injection at the very end of the system prompt). + * + * When called as a simple function, returns the top block only. + * Use buildPersonalityPromptParts() for both halves. + */ +export function buildPersonalityPrompt(config?: PersonalityConfig): string { + const parts = buildPersonalityPromptParts(config) + return parts.top +} + +/** + * Build both halves of the personality sandwich. + */ +export function buildPersonalityPromptParts(config?: PersonalityConfig): { top: string; bottom: string } { + if (!config || config.activeTraitIds.length === 0) { + return { top: "", bottom: "" } + } + + const activeTraits = resolveActiveTraits(config.activeTraitIds, config.customTraits, config.deletedBuiltInTraitIds || []) + + if (activeTraits.length === 0) { + return { top: "", bottom: "" } + } + + const traitPrompts = activeTraits.map((t) => t.prompt.trim()).join("\n\n") + const traitNames = activeTraits.map((t) => `${t.emoji} ${t.label}`).join(", ") + + const top = ` + +==== + +PERSONALITY & VOICE (ACTIVE: ${traitNames}) + +CRITICAL: The following personality defines your VOICE and TONE in EVERY response. This is not optional. You must sound noticeably different from a default AI assistant. If your response could have been written by any generic chatbot, you are doing it wrong. Rewrite it in character. + +${traitPrompts} +` + + const bottom = ` + +==== + +PERSONALITY REMINDER + +Remember: Your active personality is ${traitNames}. Every response โ€” including technical ones โ€” must reflect this voice. Use the specific phrases, verbal tics, and speech patterns defined above. A reader should be able to identify your personality from any single paragraph you write. +` + + return { top, bottom } +} diff --git a/webview-ui/src/components/modes/EmojiPicker.tsx b/webview-ui/src/components/modes/EmojiPicker.tsx new file mode 100644 index 00000000000..dcf0357031b --- /dev/null +++ b/webview-ui/src/components/modes/EmojiPicker.tsx @@ -0,0 +1,65 @@ +import React, { useState, useCallback } from "react" +import { Popover, PopoverContent, PopoverTrigger, Button } from "@src/components/ui" + +/** + * Curated emoji list organized by category for personality traits. + */ +const EMOJI_LIST = [ + // Faces & Expressions + "๐Ÿ˜Š", "๐Ÿ˜Ž", "๐Ÿค“", "๐Ÿ˜ค", "๐Ÿ˜ˆ", "๐Ÿฅณ", "๐Ÿค”", "๐Ÿ˜", "๐Ÿง", "๐Ÿ˜ด", + "๐Ÿคช", "๐Ÿ˜‡", "๐Ÿฅถ", "๐Ÿคฉ", "๐Ÿ˜ฌ", "๐Ÿซก", "๐Ÿค–", "๐Ÿ‘ป", "๐Ÿ’€", "๐Ÿค ", + // Animals & Nature + "๐Ÿฆ˜", "๐Ÿ‰", "๐ŸฆŠ", "๐Ÿบ", "๐Ÿฆ", "๐Ÿ™", "๐Ÿฆ„", "๐Ÿ", "๐Ÿฆ…", "๐Ÿธ", + // Objects & Symbols + "๐ŸŽญ", "๐ŸŽฏ", "๐Ÿง ", "๐ŸŽช", "๐Ÿ•ถ๏ธ", "๐ŸŽจ", "โ˜•", "๐Ÿ”", "โšก", "๐Ÿดโ€โ˜ ๏ธ", + "๐Ÿ”ฅ", "๐Ÿ’Ž", "๐ŸŽธ", "๐ŸŽฒ", "๐Ÿงช", "๐Ÿ“š", "๐Ÿ›ก๏ธ", "โš”๏ธ", "๐Ÿช„", "๐ŸŒŸ", + // Misc Fun + "๐Ÿš€", "๐Ÿ’ก", "๐ŸŽฌ", "๐ŸŒˆ", "๐Ÿ•", "๐ŸŒถ๏ธ", "๐ŸงŠ", "๐Ÿซ ", "โœจ", "๐Ÿ’ซ", +] + +interface EmojiPickerProps { + value: string + onChange: (emoji: string) => void +} + +const EmojiPicker: React.FC = ({ value, onChange }) => { + const [open, setOpen] = useState(false) + + const handleSelect = useCallback( + (emoji: string) => { + onChange(emoji) + setOpen(false) + }, + [onChange], + ) + + return ( + + + + + +
+ {EMOJI_LIST.map((emoji) => ( + + ))} +
+
+
+ ) +} + +export default EmojiPicker diff --git a/webview-ui/src/components/modes/ModesView.tsx b/webview-ui/src/components/modes/ModesView.tsx index eeeaf026cc2..fcc4050d2bf 100644 --- a/webview-ui/src/components/modes/ModesView.tsx +++ b/webview-ui/src/components/modes/ModesView.tsx @@ -49,6 +49,7 @@ import { StandardTooltip, } from "@src/components/ui" import { DeleteModeDialog } from "@src/components/modes/DeleteModeDialog" +import PersonalityTraitsPanel from "@src/components/modes/PersonalityTraitsPanel" import { useEscapeKey } from "@src/hooks/useEscapeKey" // Get all available groups that should show in prompts view @@ -74,6 +75,7 @@ const ModesView = () => { customInstructions, setCustomInstructions, customModes, + personalityTraitEnhancerPrompt, } = useExtensionState() // Use a local state to track the visually active mode @@ -1293,6 +1295,13 @@ const ModesView = () => { + {/* Personality Traits Section */} + +
+ + {/* Edit/Delete buttons on hover (all traits except Roo) */} + {canEditDelete && ( +
+ + + + + + +
+ )} +
+ ) + })} +
+ + {/* Combined Prompt Preview (collapsible) */} + {activeTraits.length > 0 && ( + + + + + +
+							{combinedPrompt || t("personality:noActiveTraits")}
+						
+
+
+ )} + + {/* Unified Create / Edit Trait Section */} + { if (!open) resetForm(); else if (!isEditing) startCreating(); }}> + + + + +
+
+
+ + +
+
+ + setFormLabel(e.target.value)} + placeholder={t("personality:labelPlaceholder")} + /> +
+
+ +
+
+ +
+ + + + + + +
+
+ setFormPrompt(e.target.value)} + placeholder={t("personality:promptPlaceholder")} + rows={4} + className="w-full" + /> +
+ + {/* Enhancer Prompt Editor (collapsible) */} + {isEnhancerPromptOpen && ( +
+
+ {t("personality:enhancerPromptLabel")} +
+ { + vscode.postMessage({ + type: "updateSettings", + updatedSettings: { personalityTraitEnhancerPrompt: e.target.value }, + }) + }} + rows={6} + className="w-full text-xs" + /> +
+ )} + +
+ + {isEditing && ( + + )} +
+
+
+
+ + ) +} + +export default PersonalityTraitsPanel diff --git a/webview-ui/src/i18n/locales/en/personality.json b/webview-ui/src/i18n/locales/en/personality.json new file mode 100644 index 00000000000..2beef03ca76 --- /dev/null +++ b/webview-ui/src/i18n/locales/en/personality.json @@ -0,0 +1,19 @@ +{ + "title": "Personality Traits", + "description": "Toggle traits to shape how Roo communicates in this mode. Combine multiple traits for a unique personality.", + "previewPrompt": "Preview combined prompt", + "noActiveTraits": "No traits are active. Toggle a trait above to see the combined prompt.", + "createTrait": "Create a Trait", + "editTrait": "Edit trait", + "editTraitTitle": "Edit Trait", + "deleteTrait": "Delete trait", + "emojiLabel": "Emoji", + "titleLabel": "Title", + "promptLabel": "Description / Prompt", + "labelPlaceholder": "e.g., Flamboyant", + "promptPlaceholder": "Describe the personality trait, or type a few words and click Enhance...", + "enhanceTooltip": "Enhance: expand a few words into a full personality prompt", + "enhancerSettingsTooltip": "View/edit the enhancer meta-prompt", + "enhancerPromptLabel": "Enhancer Meta-Prompt (controls how brief descriptions are expanded)", + "addTraitButton": "Add Trait" +}