Compare commits

...

3 Commits

Author SHA1 Message Date
copilot-swe-agent[bot]
0d3378896e Update UI components to remove old AI buttons and only use Copilot
Co-authored-by: estruyf <2900833+estruyf@users.noreply.github.com>
2025-12-03 15:09:50 +00:00
copilot-swe-agent[bot]
37f248d13f Remove obsolete sponsor AI features and add new AI setting
Co-authored-by: estruyf <2900833+estruyf@users.noreply.github.com>
2025-12-03 15:06:10 +00:00
copilot-swe-agent[bot]
3e4d17b2fc Initial plan 2025-12-03 14:55:08 +00:00
11 changed files with 36 additions and 239 deletions

View File

@@ -139,11 +139,10 @@
}
}
},
"frontMatter.sponsors.ai.enabled": {
"frontMatter.ai.enabled": {
"type": "boolean",
"default": false,
"markdownDescription": "%setting.frontMatter.sponsors.ai.enabled.markdownDescription%",
"scope": "Sponsors"
"default": true,
"markdownDescription": "%setting.frontMatter.ai.enabled.markdownDescription%"
},
"frontMatter.extensibility.scripts": {
"type": "array",

View File

@@ -55,7 +55,7 @@
"setting.frontMatter.projects.markdownDescription": "Specify the list of projects to load in the Front Matter CMS. [Local](https://file%2B.vscode-resource.vscode-cdn.net/Users/eliostruyf/nodejs/frontmatter-test-projects/astro-blog/test.html) - [Docs](https://frontmatter.codes/docs/settings/overview#frontmatter.projects) - [View in VS Code](vscode://simpleBrowser.show?%5B%22https://frontmatter.codes/docs/settings/overview%23frontmatter.projects%22%5D)",
"setting.frontMatter.projects.items.properties.name.markdownDescription": "Specify the name of the project.",
"setting.frontMatter.projects.items.properties.default.markdownDescription": "Specify if this project is the default project to load.",
"setting.frontMatter.sponsors.ai.enabled.markdownDescription": "Specify if you want to enable AI suggestions. [Docs](https://frontmatter.codes/docs/settings/overview#frontmatter.sponsors.ai.enabled) - [View in VS Code](command:simpleBrowser.show?%5B%22https://frontmatter.codes/docs/settings/overview%23frontmatter.sponsors.ai.enabled%22%5D)",
"setting.frontMatter.ai.enabled.markdownDescription": "Specify if you want to enable AI suggestions (requires GitHub Copilot extension). [Docs](https://frontmatter.codes/docs/settings/overview#frontmatter.ai.enabled) - [View in VS Code](command:simpleBrowser.show?%5B%22https://frontmatter.codes/docs/settings/overview%23frontmatter.ai.enabled%22%5D)",
"setting.frontMatter.extensibility.scripts.markdownDescription": "Specify the list of scripts to load in the Front Matter CMS. [Docs](https://frontmatter.codes/docs/settings/overview#frontmatter.extensibility.scripts) - [View in VS Code](command:simpleBrowser.show?%5B%22https://frontmatter.codes/docs/settings/overview%23frontmatter.extensibility.scripts%22%5D)",
"setting.frontMatter.experimental.markdownDescription": "Specify if you want to enable the experimental features. [Docs](https://frontmatter.codes/docs/settings/overview#frontmatter.experimental) - [View in VS Code](command:simpleBrowser.show?%5B%22https://frontmatter.codes/docs/settings/overview%23frontmatter.experimental%22%5D)",
"setting.frontMatter.extends.markdownDescription": "Specify the list of paths/URLs to extend the Front Matter CMS config. [Docs](https://frontmatter.codes/docs/settings/overview#frontmatter.extends) - [View in VS Code](command:simpleBrowser.show?%5B%22https://frontmatter.codes/docs/settings/overview%23frontmatter.extends%22%5D)",

View File

@@ -117,14 +117,10 @@ export const SETTING_SNIPPETS_WRAPPER = 'snippets.wrapper.enabled';
export const SETTING_WEBSITE_URL = 'website.host';
export const SETTING_COPILOT_FAMILY = 'copilot.family';
export const SETTING_AI_ENABLED = 'ai.enabled';
export const SETTING_LOGGING = 'logging';
/**
* Sponsors only settings
*/
export const SETTING_SPONSORS_AI_ENABLED = 'sponsors.ai.enabled';
/**
* Project override support
*/

View File

@@ -1,7 +1,7 @@
import {
SETTING_GLOBAL_TIMEZONE,
SETTING_PANEL_ACTIONS_DISABLED,
SETTING_SPONSORS_AI_ENABLED,
SETTING_AI_ENABLED,
SETTING_WEBSITE_URL
} from './../constants/settings';
import { workspace } from 'vscode';
@@ -52,7 +52,7 @@ export class PanelSettings {
try {
return {
aiEnabled: Settings.get<boolean>(SETTING_SPONSORS_AI_ENABLED) || false,
aiEnabled: Settings.get<boolean>(SETTING_AI_ENABLED) !== false,
copilotEnabled: await Copilot.isInstalled(),
git: await GitListener.getSettings(),
seo: {

View File

@@ -1,11 +1,10 @@
import { authentication, QuickPickItem, QuickPickItemKind, window } from 'vscode';
import { Folders } from '../commands/Folders';
import { SETTING_SPONSORS_AI_ENABLED } from '../constants';
import { SETTING_AI_ENABLED } from '../constants';
import { ContentType } from './ContentType';
import { Notifications } from './Notifications';
import { Settings } from './SettingsHelper';
import { Logger } from './Logger';
import { SponsorAi } from '../services/SponsorAI';
import * as l10n from '@vscode/l10n';
import { LocalizationKey } from '../localization';
import { ContentFolder } from '../models';
@@ -40,56 +39,30 @@ export class Questions {
* @returns
*/
public static async ContentTitle(showWarning = true): Promise<string | undefined> {
const aiEnabled = Settings.get<boolean>(SETTING_SPONSORS_AI_ENABLED);
const aiEnabled = Settings.get<boolean>(SETTING_AI_ENABLED);
let title: string | undefined = '';
const isCopilotInstalled = await Copilot.isInstalled();
let aiTitles: string[] | undefined;
if (aiEnabled || isCopilotInstalled) {
if (isCopilotInstalled) {
title = await window.showInputBox({
title: l10n.t(LocalizationKey.helpersQuestionsContentTitleAiInputTitle),
prompt: l10n.t(LocalizationKey.helpersQuestionsContentTitleAiInputPrompt),
placeHolder: l10n.t(LocalizationKey.helpersQuestionsContentTitleAiInputPlaceholder),
ignoreFocusOut: true
});
// Only show AI suggestions if both the setting is enabled and Copilot is installed
if (aiEnabled !== false && isCopilotInstalled) {
title = await window.showInputBox({
title: l10n.t(LocalizationKey.helpersQuestionsContentTitleAiInputTitle),
prompt: l10n.t(LocalizationKey.helpersQuestionsContentTitleAiInputPrompt),
placeHolder: l10n.t(LocalizationKey.helpersQuestionsContentTitleAiInputPlaceholder),
ignoreFocusOut: true
});
if (title) {
try {
aiTitles = await Copilot.suggestTitles(title);
} catch (e) {
Logger.error((e as Error).message);
Notifications.error(
l10n.t(LocalizationKey.helpersQuestionsContentTitleCopilotInputFailed)
);
title = undefined;
}
}
} else {
const githubAuth = await authentication.getSession('github', ['read:user'], {
silent: true
});
if (githubAuth && githubAuth.account.label) {
title = await window.showInputBox({
title: l10n.t(LocalizationKey.helpersQuestionsContentTitleAiInputTitle),
prompt: l10n.t(LocalizationKey.helpersQuestionsContentTitleAiInputPrompt),
placeHolder: l10n.t(LocalizationKey.helpersQuestionsContentTitleAiInputPlaceholder),
ignoreFocusOut: true
});
if (title) {
try {
aiTitles = await SponsorAi.getTitles(githubAuth.accessToken, title);
} catch (e) {
Logger.error((e as Error).message);
Notifications.error(
l10n.t(LocalizationKey.helpersQuestionsContentTitleAiInputFailed)
);
title = undefined;
}
}
if (title) {
try {
aiTitles = await Copilot.suggestTitles(title);
} catch (e) {
Logger.error((e as Error).message);
Notifications.error(
l10n.t(LocalizationKey.helpersQuestionsContentTitleCopilotInputFailed)
);
title = undefined;
}
}

View File

@@ -5,7 +5,7 @@ import { Folders } from '../../commands/Folders';
import { Command } from '../../panelWebView/Command';
import { CommandToCode } from '../../panelWebView/CommandToCode';
import { BaseListener } from './BaseListener';
import { Uri, authentication, commands, window } from 'vscode';
import { Uri, commands, window } from 'vscode';
import {
ArticleHelper,
Extension,
@@ -40,7 +40,6 @@ import {
import { encodeEmoji, fieldWhenClause, getTitleField } from '../../utils';
import { PanelProvider } from '../../panelWebView/PanelProvider';
import { MessageHandlerData } from '@estruyf/vscode';
import { SponsorAi } from '../../services/SponsorAI';
import { Terminal } from '../../services';
import * as l10n from '@vscode/l10n';
import { LocalizationKey } from '../../localization';
@@ -102,9 +101,6 @@ export class DataListener extends BaseListener {
case CommandToCode.getDataEntries:
this.getDataFileEntries(msg.command, msg.requestId || '', msg.payload);
break;
case CommandToCode.aiSuggestDescription:
this.aiSuggestTaxonomy(msg.command, msg.requestId);
break;
case CommandToCode.copilotSuggestDescription:
this.copilotSuggestDescription(msg.command, msg.requestId);
break;
@@ -179,68 +175,6 @@ export class DataListener extends BaseListener {
}
}
/**
* Suggests taxonomy using AI.
* @param command - The command string.
* @param requestId - The optional request ID.
*/
private static async aiSuggestTaxonomy(command: string, requestId?: string) {
if (!command || !requestId) {
return;
}
const extPath = Extension.getInstance().extensionPath;
const panel = PanelProvider.getInstance(extPath);
const editor = window.activeTextEditor;
if (!editor) {
panel.getWebview()?.postMessage({
command,
requestId,
error: l10n.t(LocalizationKey.listenersPanelDataListenerAiSuggestTaxonomyNoEditorError)
} as MessageHandlerData<string>);
return;
}
const article = ArticleHelper.getFrontMatter(editor);
if (!article || !article.data) {
panel.getWebview()?.postMessage({
command,
requestId,
error: l10n.t(LocalizationKey.listenersPanelDataListenerAiSuggestTaxonomyNoDataError)
} as MessageHandlerData<string>);
return;
}
const githubAuth = await authentication.getSession('github', ['read:user'], { silent: true });
if (!githubAuth || !githubAuth.accessToken) {
return;
}
const titleField = getTitleField();
const suggestion = await SponsorAi.getDescription(
githubAuth.accessToken,
article.data[titleField] || '',
article.content || ''
);
if (!suggestion) {
panel.getWebview()?.postMessage({
command,
requestId,
error: l10n.t(LocalizationKey.listenersPanelDataListenerAiSuggestTaxonomyNoDataError)
} as MessageHandlerData<string>);
return;
}
panel.getWebview()?.postMessage({
command,
requestId,
payload: suggestion || []
} as MessageHandlerData<string>);
}
/**
* Retrieve the information about the registered folders and its files
*/

View File

@@ -1,11 +1,10 @@
import { CommandToCode } from '../../panelWebView/CommandToCode';
import { TagType } from '../../panelWebView/TagType';
import { BaseListener } from './BaseListener';
import { authentication, window } from 'vscode';
import { window } from 'vscode';
import { ArticleHelper, Extension, Settings, TaxonomyHelper } from '../../helpers';
import { BlockFieldData, CustomTaxonomyData, PostMessageData, TaxonomyType } from '../../models';
import { DataListener } from '.';
import { SponsorAi } from '../../services/SponsorAI';
import { PanelProvider } from '../../panelWebView/PanelProvider';
import { MessageHandlerData } from '@estruyf/vscode';
import * as l10n from '@vscode/l10n';
@@ -60,9 +59,6 @@ export class TaxonomyListener extends BaseListener {
case CommandToCode.addToCustomTaxonomy:
this.addCustomTaxonomy(msg.payload);
break;
case CommandToCode.aiSuggestTaxonomy:
this.aiSuggestTaxonomy(msg.command, msg.requestId, msg.payload);
break;
case CommandToCode.copilotSuggestTaxonomy:
this.copilotSuggestTaxonomy(msg.command, msg.requestId, msg.payload);
break;
@@ -120,73 +116,6 @@ export class TaxonomyListener extends BaseListener {
}
}
/**
* Suggests taxonomy based on the provided command, request ID, and tag type.
*
* @param command - The command to execute.
* @param requestId - The ID of the request.
* @param type - The type of tag.
* @returns A Promise that resolves to void.
*/
private static async aiSuggestTaxonomy(command: string, requestId?: string, type?: TagType) {
if (!command || !requestId || !type) {
return;
}
const extPath = Extension.getInstance().extensionPath;
const panel = PanelProvider.getInstance(extPath);
const editor = window.activeTextEditor;
if (!editor) {
panel.getWebview()?.postMessage({
command,
requestId,
error: l10n.t(LocalizationKey.listenersPanelTaxonomyListenerAiSuggestTaxonomyNoDataError)
} as MessageHandlerData<string>);
return;
}
const article = ArticleHelper.getFrontMatter(editor);
if (!article || !article.data) {
panel.getWebview()?.postMessage({
command,
requestId,
error: l10n.t(LocalizationKey.listenersPanelTaxonomyListenerAiSuggestTaxonomyNoEditorError)
} as MessageHandlerData<string>);
return;
}
const githubAuth = await authentication.getSession('github', ['read:user'], { silent: true });
if (!githubAuth || !githubAuth.accessToken) {
return;
}
const titleField = getTitleField();
const descriptionField = getDescriptionField();
const suggestions = await SponsorAi.getTaxonomySuggestions(
githubAuth.accessToken,
article.data[titleField] || '',
article.data[descriptionField] || '',
type
);
if (!suggestions) {
panel.getWebview()?.postMessage({
command,
requestId,
error: l10n.t(LocalizationKey.listenersPanelTaxonomyListenerAiSuggestTaxonomyNoDataError)
} as MessageHandlerData<string>);
return;
}
panel.getWebview()?.postMessage({
command,
requestId,
payload: suggestions || []
} as MessageHandlerData<string[]>);
}
/**
* Update the tags in the current document
* @param tagType

View File

@@ -40,8 +40,6 @@ export enum CommandToCode {
getDataEntries = 'get-data-entries',
generateSlug = 'generate-slug',
stopServer = 'stop-server',
aiSuggestTaxonomy = 'ai-suggest-taxonomy',
aiSuggestDescription = 'ai-suggest-description',
copilotSuggestTitle = 'copilot-suggest-title',
copilotSuggestDescription = 'copilot-suggest-description',
copilotSuggestTaxonomy = 'copilot-suggest-taxonomy',

View File

@@ -260,13 +260,11 @@ const TagPicker: React.FunctionComponent<ITagPickerProps> = ({
}
const suggestTaxonomy = useCallback(
(aiType: 'ai' | 'copilot', type: TagType) => {
(type: TagType) => {
setLoading(localize(LocalizationKey.panelTagPickerAiGenerating));
const command =
aiType === 'ai' ? CommandToCode.aiSuggestTaxonomy : CommandToCode.copilotSuggestTaxonomy;
messageHandler
.request<string[]>(command, type)
.request<string[]>(CommandToCode.copilotSuggestTaxonomy, type)
.then((values) => {
setLoading(undefined);
updateTaxonomy(values)
@@ -311,22 +309,7 @@ const TagPicker: React.FunctionComponent<ITagPickerProps> = ({
return (
<>
{settings?.aiEnabled && (
<button
className="metadata_field__title__action"
title={localize(
LocalizationKey.panelTagPickerAiSuggest,
label?.toLowerCase() || type.toLowerCase()
)}
type="button"
onClick={() => suggestTaxonomy('ai', type)}
disabled={!!loading}
>
<SparklesIcon />
</button>
)}
{settings?.copilotEnabled && (
{settings?.aiEnabled && settings?.copilotEnabled && (
<button
className="metadata_field__title__action"
title={localize(
@@ -334,7 +317,7 @@ const TagPicker: React.FunctionComponent<ITagPickerProps> = ({
label?.toLowerCase() || type.toLowerCase()
)}
type="button"
onClick={() => suggestTaxonomy('copilot', type)}
onClick={() => suggestTaxonomy(type)}
disabled={!!loading}
>
<CopilotIcon />

View File

@@ -105,13 +105,11 @@ export const TextField: React.FunctionComponent<ITextFieldProps> = ({
});
};
const suggestDescription = (type: 'ai' | 'copilot') => {
const suggestDescription = () => {
setLoading(localize(LocalizationKey.panelFieldsTextFieldAiGenerate));
messageHandler
.request<string>(
type === 'copilot' ? CommandToCode.copilotSuggestDescription : CommandToCode.aiSuggestDescription
)
.request<string>(CommandToCode.copilotSuggestDescription)
.then((suggestion) => {
setLoading(undefined);
@@ -132,24 +130,12 @@ export const TextField: React.FunctionComponent<ITextFieldProps> = ({
return (
<>
{settings?.aiEnabled && settings.seo.descriptionField === name && (
<button
className="metadata_field__title__action inline-block text-[var(--vscode-editor-foreground)] disabled:opacity-50"
title={localize(LocalizationKey.panelFieldsTextFieldAiMessage, label?.toLowerCase())}
type="button"
onClick={() => suggestDescription('ai')}
disabled={!!loading}
>
<SparklesIcon />
</button>
)}
{settings?.copilotEnabled && (
{settings?.aiEnabled && settings?.copilotEnabled && (
<button
className="metadata_field__title__action inline-block text-[var(--vscode-editor-foreground)] disabled:opacity-50"
title={localize(LocalizationKey.panelFieldsTextFieldCopilotMessage, label?.toLowerCase())}
type="button"
onClick={() => settings.seo.descriptionField === name ? suggestDescription('copilot') : suggestTitle()}
onClick={() => settings.seo.descriptionField === name ? suggestDescription() : suggestTitle()}
disabled={!!loading}
>
<CopilotIcon />

View File

@@ -2,5 +2,4 @@ export * from './Credentials';
export * from './ModeSwitch';
export * from './PagesParser';
export * from './PinnedItems';
export * from './SponsorAI';
export * from './Terminal';