Add per-feature Cursor channel toggles for admin and runtime.
Memind CI / Test, build, and release guards (push) Has been cancelled
Memind CI / Test, build, and release guards (push) Has been cancelled
Expose page/data/scheduled-task/chat-bridge switches in the智趣体验通道 config so Tang can roll out Cursor paths independently with DeepSeek fallback. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -0,0 +1,97 @@
|
||||
export const CURSOR_CHANNEL_FEATURES = Object.freeze({
|
||||
PAGE_GENERATE: 'pageGenerate',
|
||||
PAGE_DATA: 'pageData',
|
||||
EXCEL_ANALYSIS: 'excelAnalysis',
|
||||
CHAT_BRIDGE: 'chatBridge',
|
||||
SCHEDULED_TASKS: 'scheduledTasks',
|
||||
});
|
||||
|
||||
export const CURSOR_TASK_KIND = Object.freeze({
|
||||
PAGE_GENERATION: 'page_generation',
|
||||
PAGE_DATA: 'page_data',
|
||||
EXCEL_ANALYSIS: 'excel_analysis',
|
||||
});
|
||||
|
||||
const TASK_KIND_TO_FEATURE = Object.freeze({
|
||||
[CURSOR_TASK_KIND.PAGE_GENERATION]: CURSOR_CHANNEL_FEATURES.PAGE_GENERATE,
|
||||
[CURSOR_TASK_KIND.PAGE_DATA]: CURSOR_CHANNEL_FEATURES.PAGE_DATA,
|
||||
[CURSOR_TASK_KIND.EXCEL_ANALYSIS]: CURSOR_CHANNEL_FEATURES.EXCEL_ANALYSIS,
|
||||
});
|
||||
|
||||
export function defaultCursorChannelFeatures() {
|
||||
return {
|
||||
[CURSOR_CHANNEL_FEATURES.PAGE_GENERATE]: { enabled: true },
|
||||
[CURSOR_CHANNEL_FEATURES.PAGE_DATA]: { enabled: false },
|
||||
[CURSOR_CHANNEL_FEATURES.EXCEL_ANALYSIS]: { enabled: false },
|
||||
[CURSOR_CHANNEL_FEATURES.CHAT_BRIDGE]: { enabled: false },
|
||||
[CURSOR_CHANNEL_FEATURES.SCHEDULED_TASKS]: { enabled: false },
|
||||
};
|
||||
}
|
||||
|
||||
function normalizeFeatureFlag(value, fallback = false) {
|
||||
if (value == null) return fallback;
|
||||
if (typeof value === 'boolean') return value;
|
||||
if (typeof value === 'object' && value !== null && 'enabled' in value) {
|
||||
return normalizeFeatureFlag(value.enabled, fallback);
|
||||
}
|
||||
const normalized = String(value).trim().toLowerCase();
|
||||
if (['1', 'true', 'yes', 'on'].includes(normalized)) return true;
|
||||
if (['0', 'false', 'no', 'off'].includes(normalized)) return false;
|
||||
return fallback;
|
||||
}
|
||||
|
||||
export function normalizeCursorChannelFeatures(rawFeatures, {
|
||||
intentAllowlist = ['page.generate'],
|
||||
} = {}) {
|
||||
const defaults = defaultCursorChannelFeatures();
|
||||
const source = rawFeatures && typeof rawFeatures === 'object' ? rawFeatures : {};
|
||||
const legacyIntents = Array.isArray(intentAllowlist)
|
||||
? intentAllowlist.map((item) => String(item ?? '').trim()).filter(Boolean)
|
||||
: [];
|
||||
|
||||
const hasExplicitFeatures = Object.keys(source).length > 0;
|
||||
return {
|
||||
[CURSOR_CHANNEL_FEATURES.PAGE_GENERATE]: {
|
||||
enabled: hasExplicitFeatures
|
||||
? normalizeFeatureFlag(
|
||||
source[CURSOR_CHANNEL_FEATURES.PAGE_GENERATE],
|
||||
legacyIntents.includes('page.generate'),
|
||||
)
|
||||
: legacyIntents.includes('page.generate'),
|
||||
},
|
||||
[CURSOR_CHANNEL_FEATURES.PAGE_DATA]: {
|
||||
enabled: normalizeFeatureFlag(source[CURSOR_CHANNEL_FEATURES.PAGE_DATA], false),
|
||||
},
|
||||
[CURSOR_CHANNEL_FEATURES.EXCEL_ANALYSIS]: {
|
||||
enabled: normalizeFeatureFlag(source[CURSOR_CHANNEL_FEATURES.EXCEL_ANALYSIS], false),
|
||||
},
|
||||
[CURSOR_CHANNEL_FEATURES.CHAT_BRIDGE]: {
|
||||
enabled: normalizeFeatureFlag(source[CURSOR_CHANNEL_FEATURES.CHAT_BRIDGE], false),
|
||||
},
|
||||
[CURSOR_CHANNEL_FEATURES.SCHEDULED_TASKS]: {
|
||||
enabled: normalizeFeatureFlag(source[CURSOR_CHANNEL_FEATURES.SCHEDULED_TASKS], false),
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
export function intentAllowlistFromFeatures(features) {
|
||||
const normalized = normalizeCursorChannelFeatures(features);
|
||||
const intents = [];
|
||||
if (normalized[CURSOR_CHANNEL_FEATURES.PAGE_GENERATE]?.enabled) {
|
||||
intents.push('page.generate');
|
||||
}
|
||||
return intents.length > 0 ? intents : ['page.generate'];
|
||||
}
|
||||
|
||||
export function isCursorFeatureEnabled(policy, featureKey) {
|
||||
if (!policy?.enabled) return false;
|
||||
const features = policy.features
|
||||
?? normalizeCursorChannelFeatures(null, { intentAllowlist: policy.intentAllowlist });
|
||||
return normalizeFeatureFlag(features?.[featureKey], false);
|
||||
}
|
||||
|
||||
export function isCursorTaskKindEnabled(policy, taskKind) {
|
||||
const featureKey = TASK_KIND_TO_FEATURE[String(taskKind ?? '').trim()];
|
||||
if (!featureKey) return false;
|
||||
return isCursorFeatureEnabled(policy, featureKey);
|
||||
}
|
||||
Reference in New Issue
Block a user