mirror of
https://github.com/catlog22/Claude-Code-Workflow.git
synced 2026-02-10 02:24:35 +08:00
Refactor API calls to use csrfFetch for enhanced security across multiple views, including loop-monitor, mcp-manager, memory, prompt-history, rules-manager, session-detail, and skills-manager. Additionally, add Phase 1 and Phase 2 documentation for session initialization and orchestration loop in the ccw-loop-b skill.
This commit is contained in:
@@ -132,23 +132,40 @@ export async function csrfValidation(ctx: CsrfMiddlewareContext): Promise<boolea
|
||||
const headerToken = getHeaderValue(req.headers['x-csrf-token']);
|
||||
const cookies = parseCookieHeader(getHeaderValue(req.headers.cookie));
|
||||
const cookieToken = cookies['XSRF-TOKEN'];
|
||||
|
||||
let bodyToken: string | null = null;
|
||||
if (!headerToken && !cookieToken) {
|
||||
const body = await readJsonBody(req);
|
||||
bodyToken = extractCsrfTokenFromBody(body);
|
||||
}
|
||||
|
||||
const token = headerToken || bodyToken || cookieToken || null;
|
||||
const sessionId = cookies.ccw_session_id;
|
||||
|
||||
if (!token || !sessionId) {
|
||||
if (!sessionId) {
|
||||
writeJson(res, 403, { error: 'CSRF validation failed' });
|
||||
return false;
|
||||
}
|
||||
|
||||
const tokenManager = getCsrfTokenManager();
|
||||
const ok = tokenManager.validateToken(token, sessionId);
|
||||
|
||||
const validate = (token: string | null): boolean => {
|
||||
if (!token) return false;
|
||||
return tokenManager.validateToken(token, sessionId);
|
||||
};
|
||||
|
||||
let ok = false;
|
||||
if (headerToken) {
|
||||
ok = validate(headerToken);
|
||||
if (!ok && cookieToken && cookieToken !== headerToken) {
|
||||
ok = validate(cookieToken);
|
||||
}
|
||||
} else if (cookieToken) {
|
||||
ok = validate(cookieToken);
|
||||
}
|
||||
|
||||
if (!ok) {
|
||||
let bodyToken: string | null = null;
|
||||
if (!cookieToken) {
|
||||
const body = await readJsonBody(req);
|
||||
bodyToken = extractCsrfTokenFromBody(body);
|
||||
}
|
||||
|
||||
ok = validate(bodyToken);
|
||||
}
|
||||
|
||||
if (!ok) {
|
||||
writeJson(res, 403, { error: 'CSRF validation failed' });
|
||||
return false;
|
||||
|
||||
@@ -453,7 +453,7 @@ async function deleteExecution(executionId, sourceDir) {
|
||||
basePath = isAbsolute ? sourceDir : projectPath + '/' + sourceDir;
|
||||
}
|
||||
|
||||
const response = await fetch(`/api/cli/execution?path=${encodeURIComponent(basePath)}&id=${encodeURIComponent(executionId)}`, {
|
||||
const response = await csrfFetch(`/api/cli/execution?path=${encodeURIComponent(basePath)}&id=${encodeURIComponent(executionId)}`, {
|
||||
method: 'DELETE'
|
||||
});
|
||||
|
||||
|
||||
@@ -1434,7 +1434,7 @@ async function submitHookWizard() {
|
||||
const timeout = wizardConfig.timeout || 300;
|
||||
try {
|
||||
const configParams = JSON.stringify({ action: 'configure', threshold, timeout });
|
||||
const response = await fetch('/api/tools/execute', {
|
||||
const response = await csrfFetch('/api/tools/execute', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ tool: 'memory_queue', params: configParams })
|
||||
@@ -1559,4 +1559,4 @@ function editTemplateAsNew(templateId) {
|
||||
command: template.command,
|
||||
args: template.args || []
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -160,7 +160,7 @@ async function markFileAsUpdated() {
|
||||
if (!selectedFile) return;
|
||||
|
||||
try {
|
||||
var res = await fetch('/api/memory/claude/mark-updated', {
|
||||
var res = await csrfFetch('/api/memory/claude/mark-updated', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({
|
||||
@@ -483,7 +483,7 @@ async function saveClaudeFile() {
|
||||
var newContent = editor.value;
|
||||
|
||||
try {
|
||||
var res = await fetch('/api/memory/claude/file', {
|
||||
var res = await csrfFetch('/api/memory/claude/file', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({
|
||||
@@ -682,7 +682,7 @@ async function syncFileWithCLI() {
|
||||
if (syncButton) syncButton.disabled = true;
|
||||
|
||||
try {
|
||||
var response = await fetch('/api/memory/claude/sync', {
|
||||
var response = await csrfFetch('/api/memory/claude/sync', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({
|
||||
@@ -846,7 +846,7 @@ async function createNewFile() {
|
||||
}
|
||||
|
||||
try {
|
||||
var res = await fetch('/api/memory/claude/create', {
|
||||
var res = await csrfFetch('/api/memory/claude/create', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({
|
||||
@@ -885,7 +885,7 @@ async function confirmDeleteFile() {
|
||||
if (!confirmed) return;
|
||||
|
||||
try {
|
||||
var res = await fetch('/api/memory/claude/file?path=' + encodeURIComponent(selectedFile.path) + '&confirm=true', {
|
||||
var res = await csrfFetch('/api/memory/claude/file?path=' + encodeURIComponent(selectedFile.path) + '&confirm=true', {
|
||||
method: 'DELETE'
|
||||
});
|
||||
|
||||
@@ -1083,7 +1083,7 @@ async function confirmBatchDeleteProject() {
|
||||
);
|
||||
|
||||
try {
|
||||
var res = await fetch('/api/memory/claude/batch-delete', {
|
||||
var res = await csrfFetch('/api/memory/claude/batch-delete', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({
|
||||
|
||||
@@ -677,7 +677,7 @@ async function loadFileBrowserDirectory(path) {
|
||||
}
|
||||
|
||||
try {
|
||||
var response = await fetch('/api/dialog/browse', {
|
||||
var response = await csrfFetch('/api/dialog/browse', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ path: path, showHidden: fileBrowserState.showHidden })
|
||||
@@ -2546,7 +2546,7 @@ async function runCcwUpgrade() {
|
||||
showRefreshToast(t('ccw.upgradeStarting'), 'info');
|
||||
|
||||
try {
|
||||
var response = await fetch('/api/ccw/upgrade', {
|
||||
var response = await csrfFetch('/api/ccw/upgrade', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({})
|
||||
@@ -2620,7 +2620,7 @@ async function executeCliFromDashboard() {
|
||||
if (execBtn) execBtn.disabled = true;
|
||||
|
||||
try {
|
||||
var response = await fetch('/api/cli/execute', {
|
||||
var response = await csrfFetch('/api/cli/execute', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({
|
||||
@@ -2851,7 +2851,7 @@ async function startCliInstall(toolName) {
|
||||
}, 1000);
|
||||
|
||||
try {
|
||||
var response = await fetch('/api/cli/install', {
|
||||
var response = await csrfFetch('/api/cli/install', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ tool: toolName })
|
||||
@@ -2992,7 +2992,7 @@ async function startCliUninstall(toolName) {
|
||||
}, 500);
|
||||
|
||||
try {
|
||||
var response = await fetch('/api/cli/uninstall', {
|
||||
var response = await csrfFetch('/api/cli/uninstall', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ tool: toolName })
|
||||
@@ -3241,7 +3241,7 @@ function initCodexLensConfigEvents(currentConfig) {
|
||||
saveBtn.innerHTML = '<span class="animate-pulse">' + t('common.saving') + '</span>';
|
||||
|
||||
try {
|
||||
var response = await fetch('/api/codexlens/config', {
|
||||
var response = await csrfFetch('/api/codexlens/config', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ index_dir: newIndexDir })
|
||||
@@ -3478,7 +3478,7 @@ async function downloadModel(profile) {
|
||||
'</div>';
|
||||
|
||||
try {
|
||||
var response = await fetch('/api/codexlens/models/download', {
|
||||
var response = await csrfFetch('/api/codexlens/models/download', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ profile: profile })
|
||||
@@ -3517,7 +3517,7 @@ async function deleteModel(profile) {
|
||||
'</div>';
|
||||
|
||||
try {
|
||||
var response = await fetch('/api/codexlens/models/delete', {
|
||||
var response = await csrfFetch('/api/codexlens/models/delete', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ profile: profile })
|
||||
@@ -3553,7 +3553,7 @@ async function cleanCurrentWorkspaceIndex() {
|
||||
// Get current workspace path (projectPath is a global variable from state.js)
|
||||
var workspacePath = projectPath;
|
||||
|
||||
var response = await fetch('/api/codexlens/clean', {
|
||||
var response = await csrfFetch('/api/codexlens/clean', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ path: workspacePath })
|
||||
@@ -3589,7 +3589,7 @@ async function cleanCodexLensIndexes() {
|
||||
try {
|
||||
showRefreshToast(t('codexlens.cleaning'), 'info');
|
||||
|
||||
var response = await fetch('/api/codexlens/clean', {
|
||||
var response = await csrfFetch('/api/codexlens/clean', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ all: true })
|
||||
|
||||
@@ -186,7 +186,7 @@ async function refreshWorkspaceIndexStatus(forceRefresh) {
|
||||
} else {
|
||||
// Fallback: direct fetch if preloadService not available
|
||||
var path = encodeURIComponent(projectPath || '');
|
||||
var response = await fetch('/api/codexlens/workspace-status?path=' + path);
|
||||
var response = await csrfFetch('/api/codexlens/workspace-status?path=' + path);
|
||||
if (!response.ok) throw new Error('HTTP ' + response.status);
|
||||
freshData = await response.json();
|
||||
}
|
||||
@@ -341,8 +341,8 @@ async function showCodexLensConfigModal(forceRefresh) {
|
||||
|
||||
// Fetch current config and status in parallel
|
||||
const [configResponse, statusResponse] = await Promise.all([
|
||||
fetch('/api/codexlens/config'),
|
||||
fetch('/api/codexlens/status')
|
||||
csrfFetch('/api/codexlens/config'),
|
||||
csrfFetch('/api/codexlens/status')
|
||||
]);
|
||||
config = await configResponse.json();
|
||||
status = await statusResponse.json();
|
||||
@@ -778,7 +778,7 @@ function initCodexLensConfigEvents(currentConfig) {
|
||||
saveBtn.innerHTML = '<span class="animate-pulse">' + t('common.saving') + '</span>';
|
||||
|
||||
try {
|
||||
var response = await fetch('/api/codexlens/config', {
|
||||
var response = await csrfFetch('/api/codexlens/config', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({
|
||||
@@ -1147,7 +1147,7 @@ async function loadEnvVariables(forceRefresh) {
|
||||
if (!forceRefresh && isCacheValid('env')) {
|
||||
result = getCachedData('env');
|
||||
} else {
|
||||
var envResponse = await fetch('/api/codexlens/env');
|
||||
var envResponse = await csrfFetch('/api/codexlens/env');
|
||||
result = await envResponse.json();
|
||||
if (result.success) {
|
||||
setCacheData('env', result);
|
||||
@@ -1643,7 +1643,7 @@ async function saveEnvVariables() {
|
||||
});
|
||||
|
||||
try {
|
||||
var response = await fetch('/api/codexlens/env', {
|
||||
var response = await csrfFetch('/api/codexlens/env', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ env: env })
|
||||
@@ -1678,7 +1678,7 @@ var cachedRerankerModels = { local: [], api: [], apiModels: [] };
|
||||
*/
|
||||
async function detectGpuSupport() {
|
||||
try {
|
||||
var response = await fetch('/api/codexlens/gpu/detect');
|
||||
var response = await csrfFetch('/api/codexlens/gpu/detect');
|
||||
var result = await response.json();
|
||||
if (result.success) {
|
||||
detectedGpuInfo = result;
|
||||
@@ -1703,7 +1703,7 @@ async function loadSemanticDepsStatus(forceRefresh) {
|
||||
if (!forceRefresh && isCacheValid('semanticStatus')) {
|
||||
result = getCachedData('semanticStatus');
|
||||
} else {
|
||||
var response = await fetch('/api/codexlens/semantic/status');
|
||||
var response = await csrfFetch('/api/codexlens/semantic/status');
|
||||
result = await response.json();
|
||||
setCacheData('semanticStatus', result);
|
||||
}
|
||||
@@ -1870,7 +1870,7 @@ function getSelectedGpuMode() {
|
||||
*/
|
||||
async function loadGpuDevices() {
|
||||
try {
|
||||
var response = await fetch('/api/codexlens/gpu/list');
|
||||
var response = await csrfFetch('/api/codexlens/gpu/list');
|
||||
var result = await response.json();
|
||||
if (result.success && result.result) {
|
||||
availableGpuDevices = result.result;
|
||||
@@ -1949,7 +1949,7 @@ async function selectGpuDevice(deviceId) {
|
||||
try {
|
||||
showRefreshToast(t('codexlens.selectingGpu') || 'Selecting GPU...', 'info');
|
||||
|
||||
var response = await fetch('/api/codexlens/gpu/select', {
|
||||
var response = await csrfFetch('/api/codexlens/gpu/select', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ device_id: deviceId })
|
||||
@@ -1975,7 +1975,7 @@ async function resetGpuDevice() {
|
||||
try {
|
||||
showRefreshToast(t('codexlens.resettingGpu') || 'Resetting GPU selection...', 'info');
|
||||
|
||||
var response = await fetch('/api/codexlens/gpu/reset', {
|
||||
var response = await csrfFetch('/api/codexlens/gpu/reset', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' }
|
||||
});
|
||||
@@ -2019,7 +2019,7 @@ async function installSemanticDepsWithGpu() {
|
||||
'</div>';
|
||||
|
||||
try {
|
||||
var response = await fetch('/api/codexlens/semantic/install', {
|
||||
var response = await csrfFetch('/api/codexlens/semantic/install', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ gpuMode: gpuMode })
|
||||
@@ -2059,7 +2059,7 @@ async function loadSpladeStatus() {
|
||||
if (!container) return;
|
||||
|
||||
try {
|
||||
var response = await fetch('/api/codexlens/splade/status');
|
||||
var response = await csrfFetch('/api/codexlens/splade/status');
|
||||
var status = await response.json();
|
||||
|
||||
if (status.available) {
|
||||
@@ -2112,7 +2112,7 @@ async function installSplade(gpu) {
|
||||
if (window.lucide) lucide.createIcons();
|
||||
|
||||
try {
|
||||
var response = await fetch('/api/codexlens/splade/install', {
|
||||
var response = await csrfFetch('/api/codexlens/splade/install', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ gpu: gpu })
|
||||
@@ -2413,7 +2413,7 @@ async function reinstallFastEmbed(mode) {
|
||||
'</div>';
|
||||
|
||||
try {
|
||||
var response = await fetch('/api/codexlens/semantic/install', {
|
||||
var response = await csrfFetch('/api/codexlens/semantic/install', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ gpuMode: mode })
|
||||
@@ -2455,7 +2455,7 @@ async function loadFastEmbedInstallStatus(forceRefresh) {
|
||||
result = getCachedData('semanticStatus');
|
||||
console.log('[CodexLens] Using cached semantic status');
|
||||
} else {
|
||||
var semanticResponse = await fetch('/api/codexlens/semantic/status');
|
||||
var semanticResponse = await csrfFetch('/api/codexlens/semantic/status');
|
||||
result = await semanticResponse.json();
|
||||
setCacheData('semanticStatus', result);
|
||||
}
|
||||
@@ -2463,7 +2463,7 @@ async function loadFastEmbedInstallStatus(forceRefresh) {
|
||||
// Load GPU list and LiteLLM status (not cached - less frequently used)
|
||||
console.log('[CodexLens] Fetching GPU list and LiteLLM status...');
|
||||
var [gpuResponse, litellmResponse] = await Promise.all([
|
||||
fetch('/api/codexlens/gpu/list'),
|
||||
csrfFetch('/api/codexlens/gpu/list'),
|
||||
fetch('/api/litellm-api/ccw-litellm/status').catch(function() { return { ok: false }; })
|
||||
]);
|
||||
|
||||
@@ -2551,7 +2551,7 @@ async function installFastEmbed() {
|
||||
'</div>';
|
||||
|
||||
try {
|
||||
var response = await fetch('/api/codexlens/semantic/install', {
|
||||
var response = await csrfFetch('/api/codexlens/semantic/install', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ gpuMode: selectedMode })
|
||||
@@ -2604,8 +2604,8 @@ async function loadModelList(forceRefresh) {
|
||||
} else {
|
||||
// Fetch config and models in parallel
|
||||
var [configResponse, modelsResponse] = await Promise.all([
|
||||
fetch('/api/codexlens/config'),
|
||||
fetch('/api/codexlens/models')
|
||||
csrfFetch('/api/codexlens/config'),
|
||||
csrfFetch('/api/codexlens/models')
|
||||
]);
|
||||
config = await configResponse.json();
|
||||
result = await modelsResponse.json();
|
||||
@@ -2854,7 +2854,7 @@ async function downloadModel(profile) {
|
||||
'</div>';
|
||||
|
||||
try {
|
||||
var response = await fetch('/api/codexlens/models/download', {
|
||||
var response = await csrfFetch('/api/codexlens/models/download', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ profile: profile })
|
||||
@@ -2899,7 +2899,7 @@ async function deleteModel(profile) {
|
||||
'</div>';
|
||||
|
||||
try {
|
||||
var response = await fetch('/api/codexlens/models/delete', {
|
||||
var response = await csrfFetch('/api/codexlens/models/delete', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ profile: profile })
|
||||
@@ -2948,7 +2948,7 @@ async function downloadCustomModel() {
|
||||
input.value = '';
|
||||
|
||||
try {
|
||||
var response = await fetch('/api/codexlens/models/download-custom', {
|
||||
var response = await csrfFetch('/api/codexlens/models/download-custom', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ model_name: modelName, model_type: 'embedding' })
|
||||
@@ -2981,7 +2981,7 @@ async function deleteDiscoveredModel(cachePath) {
|
||||
}
|
||||
|
||||
try {
|
||||
var response = await fetch('/api/codexlens/models/delete-path', {
|
||||
var response = await csrfFetch('/api/codexlens/models/delete-path', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ cache_path: cachePath })
|
||||
@@ -3044,8 +3044,8 @@ async function loadRerankerModelList(forceRefresh) {
|
||||
} else {
|
||||
// Fetch both config and models list in parallel
|
||||
var [configResponse, modelsResponse] = await Promise.all([
|
||||
fetch('/api/codexlens/reranker/config'),
|
||||
fetch('/api/codexlens/reranker/models')
|
||||
csrfFetch('/api/codexlens/reranker/config'),
|
||||
csrfFetch('/api/codexlens/reranker/models')
|
||||
]);
|
||||
|
||||
if (!configResponse.ok) {
|
||||
@@ -3218,7 +3218,7 @@ async function downloadRerankerModel(profile) {
|
||||
}
|
||||
|
||||
try {
|
||||
var response = await fetch('/api/codexlens/reranker/models/download', {
|
||||
var response = await csrfFetch('/api/codexlens/reranker/models/download', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ profile: profile })
|
||||
@@ -3248,7 +3248,7 @@ async function deleteRerankerModel(profile) {
|
||||
}
|
||||
|
||||
try {
|
||||
var response = await fetch('/api/codexlens/reranker/models/delete', {
|
||||
var response = await csrfFetch('/api/codexlens/reranker/models/delete', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ profile: profile })
|
||||
@@ -3272,7 +3272,7 @@ async function deleteRerankerModel(profile) {
|
||||
*/
|
||||
async function updateRerankerBackend(backend) {
|
||||
try {
|
||||
var response = await fetch('/api/codexlens/reranker/config', {
|
||||
var response = await csrfFetch('/api/codexlens/reranker/config', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ backend: backend })
|
||||
@@ -3296,7 +3296,7 @@ async function updateRerankerBackend(backend) {
|
||||
*/
|
||||
async function selectRerankerModel(modelName) {
|
||||
try {
|
||||
var response = await fetch('/api/codexlens/reranker/config', {
|
||||
var response = await csrfFetch('/api/codexlens/reranker/config', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ model_name: modelName })
|
||||
@@ -3321,7 +3321,7 @@ async function selectRerankerModel(modelName) {
|
||||
async function switchToLocalReranker(modelName) {
|
||||
try {
|
||||
// First switch backend to fastembed
|
||||
var backendResponse = await fetch('/api/codexlens/reranker/config', {
|
||||
var backendResponse = await csrfFetch('/api/codexlens/reranker/config', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ backend: 'fastembed' })
|
||||
@@ -3334,7 +3334,7 @@ async function switchToLocalReranker(modelName) {
|
||||
}
|
||||
|
||||
// Then select the model
|
||||
var modelResponse = await fetch('/api/codexlens/reranker/config', {
|
||||
var modelResponse = await csrfFetch('/api/codexlens/reranker/config', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ model_name: modelName })
|
||||
@@ -3425,7 +3425,7 @@ async function loadGpuDevicesForModeSelector() {
|
||||
if (!gpuSelect) return;
|
||||
|
||||
try {
|
||||
var response = await fetch('/api/codexlens/gpu/list');
|
||||
var response = await csrfFetch('/api/codexlens/gpu/list');
|
||||
if (!response.ok) {
|
||||
console.warn('[CodexLens] GPU list endpoint returned:', response.status);
|
||||
gpuSelect.innerHTML = '<option value="auto">Auto</option>';
|
||||
@@ -3483,7 +3483,7 @@ async function toggleModelModeLock() {
|
||||
try {
|
||||
// Save embedding backend preference
|
||||
var embeddingBackend = mode === 'local' ? 'fastembed' : 'litellm';
|
||||
await fetch('/api/codexlens/config', {
|
||||
await csrfFetch('/api/codexlens/config', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({
|
||||
@@ -3494,7 +3494,7 @@ async function toggleModelModeLock() {
|
||||
|
||||
// Save reranker backend preference
|
||||
var rerankerBackend = mode === 'local' ? 'fastembed' : 'litellm';
|
||||
await fetch('/api/codexlens/reranker/config', {
|
||||
await csrfFetch('/api/codexlens/reranker/config', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ backend: rerankerBackend })
|
||||
@@ -3529,7 +3529,7 @@ async function initModelModeFromConfig() {
|
||||
if (!modeSelect) return;
|
||||
|
||||
try {
|
||||
var response = await fetch('/api/codexlens/config');
|
||||
var response = await csrfFetch('/api/codexlens/config');
|
||||
var config = await response.json();
|
||||
|
||||
var embeddingBackend = config.embedding_backend || 'fastembed';
|
||||
@@ -3550,7 +3550,7 @@ async function updateSemanticStatusBadge() {
|
||||
if (!badge) return;
|
||||
|
||||
try {
|
||||
var response = await fetch('/api/codexlens/semantic/status');
|
||||
var response = await csrfFetch('/api/codexlens/semantic/status');
|
||||
var result = await response.json();
|
||||
|
||||
if (result.available) {
|
||||
@@ -3609,7 +3609,7 @@ async function initCodexLensIndex(indexType, embeddingModel, embeddingBackend, m
|
||||
// LiteLLM backend uses remote embeddings and does not require fastembed/ONNX deps.
|
||||
if ((indexType === 'vector' || indexType === 'full') && embeddingBackend !== 'litellm') {
|
||||
try {
|
||||
var semanticResponse = await fetch('/api/codexlens/semantic/status');
|
||||
var semanticResponse = await csrfFetch('/api/codexlens/semantic/status');
|
||||
var semanticStatus = await semanticResponse.json();
|
||||
|
||||
if (!semanticStatus.available) {
|
||||
@@ -3623,7 +3623,7 @@ async function initCodexLensIndex(indexType, embeddingModel, embeddingBackend, m
|
||||
// Install semantic dependencies first
|
||||
showRefreshToast(t('codexlens.installingDeps') || 'Installing semantic dependencies...', 'info');
|
||||
try {
|
||||
var installResponse = await csrfFetch('/api/codexlens/semantic/install', { method: 'POST' });
|
||||
var installResponse = await csrfcsrfFetch('/api/codexlens/semantic/install', { method: 'POST' });
|
||||
var installResult = await installResponse.json();
|
||||
|
||||
if (!installResult.success) {
|
||||
@@ -3757,7 +3757,7 @@ async function startCodexLensIndexing(indexType, embeddingModel, embeddingBacken
|
||||
|
||||
try {
|
||||
console.log('[CodexLens] Starting index for:', projectPath, 'type:', indexType, 'model:', embeddingModel, 'backend:', embeddingBackend, 'maxWorkers:', maxWorkers, 'incremental:', incremental);
|
||||
var response = await fetch('/api/codexlens/init', {
|
||||
var response = await csrfFetch('/api/codexlens/init', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ path: projectPath, indexType: indexType, embeddingModel: embeddingModel, embeddingBackend: embeddingBackend, maxWorkers: maxWorkers, incremental: incremental })
|
||||
@@ -3879,7 +3879,7 @@ async function cancelCodexLensIndexing() {
|
||||
}
|
||||
|
||||
try {
|
||||
var response = await fetch('/api/codexlens/cancel', {
|
||||
var response = await csrfFetch('/api/codexlens/cancel', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' }
|
||||
});
|
||||
@@ -4040,7 +4040,7 @@ async function startCodexLensInstallFallback() {
|
||||
}, 1500);
|
||||
|
||||
try {
|
||||
var response = await fetch('/api/codexlens/bootstrap', {
|
||||
var response = await csrfFetch('/api/codexlens/bootstrap', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({})
|
||||
@@ -4191,7 +4191,7 @@ async function startCodexLensUninstallFallback() {
|
||||
}, 500);
|
||||
|
||||
try {
|
||||
var response = await fetch('/api/codexlens/uninstall', {
|
||||
var response = await csrfFetch('/api/codexlens/uninstall', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({})
|
||||
@@ -4247,7 +4247,7 @@ async function cleanCurrentWorkspaceIndex() {
|
||||
// Get current workspace path (projectPath is a global variable from state.js)
|
||||
var workspacePath = projectPath;
|
||||
|
||||
var response = await fetch('/api/codexlens/clean', {
|
||||
var response = await csrfFetch('/api/codexlens/clean', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ path: workspacePath })
|
||||
@@ -4283,7 +4283,7 @@ async function cleanCodexLensIndexes() {
|
||||
try {
|
||||
showRefreshToast(t('codexlens.cleaning'), 'info');
|
||||
|
||||
var response = await fetch('/api/codexlens/clean', {
|
||||
var response = await csrfFetch('/api/codexlens/clean', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ all: true })
|
||||
@@ -4346,7 +4346,7 @@ async function renderCodexLensManager() {
|
||||
// Fallback to legacy individual calls
|
||||
console.log('[CodexLens] Fallback to legacy loadCodexLensStatus...');
|
||||
await loadCodexLensStatus();
|
||||
var response = await fetch('/api/codexlens/config');
|
||||
var response = await csrfFetch('/api/codexlens/config');
|
||||
config = await response.json();
|
||||
}
|
||||
|
||||
@@ -4967,7 +4967,7 @@ window.runFtsIncrementalUpdate = async function runFtsIncrementalUpdate() {
|
||||
|
||||
try {
|
||||
// Use index update endpoint for FTS incremental
|
||||
var response = await fetch('/api/codexlens/init', {
|
||||
var response = await csrfFetch('/api/codexlens/init', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({
|
||||
@@ -4998,7 +4998,7 @@ window.runVectorFullIndex = async function runVectorFullIndex() {
|
||||
|
||||
try {
|
||||
// Fetch env settings to get the configured embedding model
|
||||
var envResponse = await fetch('/api/codexlens/env');
|
||||
var envResponse = await csrfFetch('/api/codexlens/env');
|
||||
var envData = await envResponse.json();
|
||||
var embeddingModel = envData.CODEXLENS_EMBEDDING_MODEL || envData.LITELLM_EMBEDDING_MODEL || 'code';
|
||||
|
||||
@@ -5020,7 +5020,7 @@ window.runVectorIncrementalUpdate = async function runVectorIncrementalUpdate()
|
||||
|
||||
try {
|
||||
// Fetch env settings to get the configured embedding model
|
||||
var envResponse = await fetch('/api/codexlens/env');
|
||||
var envResponse = await csrfFetch('/api/codexlens/env');
|
||||
var envData = await envResponse.json();
|
||||
var embeddingModel = envData.CODEXLENS_EMBEDDING_MODEL || envData.LITELLM_EMBEDDING_MODEL || null;
|
||||
|
||||
@@ -5037,7 +5037,7 @@ window.runVectorIncrementalUpdate = async function runVectorIncrementalUpdate()
|
||||
requestBody.model = embeddingModel;
|
||||
}
|
||||
|
||||
var response = await fetch('/api/codexlens/embeddings/generate', {
|
||||
var response = await csrfFetch('/api/codexlens/embeddings/generate', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify(requestBody)
|
||||
@@ -5067,7 +5067,7 @@ window.runIncrementalUpdate = async function runIncrementalUpdate() {
|
||||
showRefreshToast('Starting incremental update...', 'info');
|
||||
|
||||
try {
|
||||
var response = await fetch('/api/codexlens/update', {
|
||||
var response = await csrfFetch('/api/codexlens/update', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ path: projectPath })
|
||||
@@ -5098,7 +5098,7 @@ window.toggleWatcher = async function toggleWatcher() {
|
||||
try {
|
||||
console.log('[CodexLens] Checking watcher status...');
|
||||
// Pass path parameter to get specific watcher status
|
||||
var statusResponse = await fetch('/api/codexlens/watch/status?path=' + encodeURIComponent(projectPath));
|
||||
var statusResponse = await csrfFetch('/api/codexlens/watch/status?path=' + encodeURIComponent(projectPath));
|
||||
var statusResult = await statusResponse.json();
|
||||
console.log('[CodexLens] Status result:', statusResult);
|
||||
|
||||
@@ -5121,7 +5121,7 @@ window.toggleWatcher = async function toggleWatcher() {
|
||||
var action = isRunning ? 'stop' : 'start';
|
||||
console.log('[CodexLens] Action:', action);
|
||||
|
||||
var response = await fetch('/api/codexlens/watch/' + action, {
|
||||
var response = await csrfFetch('/api/codexlens/watch/' + action, {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ path: projectPath })
|
||||
@@ -5210,7 +5210,7 @@ function startWatcherPolling() {
|
||||
watcherPollInterval = setInterval(async function() {
|
||||
try {
|
||||
// Must include path parameter to get specific watcher status
|
||||
var response = await fetch('/api/codexlens/watch/status?path=' + encodeURIComponent(projectPath));
|
||||
var response = await csrfFetch('/api/codexlens/watch/status?path=' + encodeURIComponent(projectPath));
|
||||
var result = await response.json();
|
||||
|
||||
if (result.success && result.running) {
|
||||
@@ -5337,7 +5337,7 @@ async function initWatcherStatus() {
|
||||
try {
|
||||
var projectPath = window.CCW_PROJECT_ROOT || '.';
|
||||
// Pass path parameter to get specific watcher status
|
||||
var response = await fetch('/api/codexlens/watch/status?path=' + encodeURIComponent(projectPath));
|
||||
var response = await csrfFetch('/api/codexlens/watch/status?path=' + encodeURIComponent(projectPath));
|
||||
var result = await response.json();
|
||||
if (result.success) {
|
||||
// Handle both single watcher response (with path param) and array response (without path param)
|
||||
@@ -5393,7 +5393,7 @@ function initCodexLensManagerPageEvents(currentConfig) {
|
||||
saveBtn.disabled = true;
|
||||
saveBtn.innerHTML = '<span class="animate-pulse">' + t('common.saving') + '</span>';
|
||||
try {
|
||||
var response = await csrfFetch('/api/codexlens/config', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ index_dir: newIndexDir }) });
|
||||
var response = await csrfcsrfFetch('/api/codexlens/config', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ index_dir: newIndexDir }) });
|
||||
var result = await response.json();
|
||||
if (result.success) { if (window.cacheManager) { window.cacheManager.invalidate('codexlens-config'); } showRefreshToast(t('codexlens.configSaved'), 'success'); renderCodexLensManager(); }
|
||||
else { showRefreshToast(t('common.saveFailed') + ': ' + result.error, 'error'); }
|
||||
@@ -5466,7 +5466,7 @@ function showIndexInitModal() {
|
||||
*/
|
||||
async function loadIndexStatsForPage() {
|
||||
try {
|
||||
var response = await fetch('/api/codexlens/indexes');
|
||||
var response = await csrfFetch('/api/codexlens/indexes');
|
||||
if (!response.ok) throw new Error('Failed to load index stats');
|
||||
var data = await response.json();
|
||||
renderIndexStatsForPage(data);
|
||||
@@ -5575,7 +5575,7 @@ async function checkIndexHealth() {
|
||||
|
||||
try {
|
||||
// Get current workspace index info
|
||||
var indexResponse = await fetch('/api/codexlens/indexes');
|
||||
var indexResponse = await csrfFetch('/api/codexlens/indexes');
|
||||
var indexData = await indexResponse.json();
|
||||
var indexes = indexData.indexes || [];
|
||||
|
||||
@@ -5653,7 +5653,7 @@ async function cleanIndexProjectFromPage(projectId) {
|
||||
try {
|
||||
showRefreshToast(t('index.cleaning') || 'Cleaning index...', 'info');
|
||||
|
||||
var response = await fetch('/api/codexlens/clean', {
|
||||
var response = await csrfFetch('/api/codexlens/clean', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ projectId: projectId })
|
||||
@@ -5683,7 +5683,7 @@ async function cleanAllIndexesFromPage() {
|
||||
try {
|
||||
showRefreshToast(t('index.cleaning') || 'Cleaning indexes...', 'info');
|
||||
|
||||
var response = await fetch('/api/codexlens/clean', {
|
||||
var response = await csrfFetch('/api/codexlens/clean', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ all: true })
|
||||
@@ -6010,7 +6010,7 @@ async function saveRotationConfig() {
|
||||
providers: providers
|
||||
};
|
||||
|
||||
var response = await fetch('/api/litellm-api/codexlens/rotation', {
|
||||
var response = await csrfFetch('/api/litellm-api/codexlens/rotation', {
|
||||
method: 'PUT',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify(rotationConfig)
|
||||
@@ -6052,7 +6052,7 @@ async function showRerankerConfigModal() {
|
||||
showRefreshToast(t('codexlens.loadingRerankerConfig') || 'Loading reranker configuration...', 'info');
|
||||
|
||||
// Fetch current reranker config
|
||||
const response = await fetch('/api/codexlens/reranker/config');
|
||||
const response = await csrfFetch('/api/codexlens/reranker/config');
|
||||
const config = await response.json();
|
||||
|
||||
if (!config.success) {
|
||||
@@ -6341,7 +6341,7 @@ async function saveRerankerConfig() {
|
||||
payload.litellm_endpoint = document.getElementById('rerankerLitellmEndpoint').value;
|
||||
}
|
||||
|
||||
var response = await fetch('/api/codexlens/reranker/config', {
|
||||
var response = await csrfFetch('/api/codexlens/reranker/config', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify(payload)
|
||||
@@ -6373,8 +6373,8 @@ async function showWatcherControlModal() {
|
||||
|
||||
// Fetch current watcher status and indexed projects in parallel
|
||||
const [statusResponse, indexesResponse] = await Promise.all([
|
||||
fetch('/api/codexlens/watch/status'),
|
||||
fetch('/api/codexlens/indexes')
|
||||
csrfFetch('/api/codexlens/watch/status'),
|
||||
csrfFetch('/api/codexlens/indexes')
|
||||
]);
|
||||
const status = await statusResponse.json();
|
||||
const indexes = await indexesResponse.json();
|
||||
@@ -6562,7 +6562,7 @@ async function toggleWatcher() {
|
||||
var watchPath = document.getElementById('watcherPath').value.trim();
|
||||
var debounceMs = parseInt(document.getElementById('watcherDebounce').value, 10) || 1000;
|
||||
|
||||
var response = await fetch('/api/codexlens/watch/start', {
|
||||
var response = await csrfFetch('/api/codexlens/watch/start', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ path: watchPath || undefined, debounce_ms: debounceMs })
|
||||
@@ -6581,7 +6581,7 @@ async function toggleWatcher() {
|
||||
}
|
||||
} else {
|
||||
// Stop watcher
|
||||
var response = await fetch('/api/codexlens/watch/stop', {
|
||||
var response = await csrfFetch('/api/codexlens/watch/stop', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' }
|
||||
});
|
||||
@@ -6625,7 +6625,7 @@ function startWatcherStatusPolling() {
|
||||
return;
|
||||
}
|
||||
|
||||
var response = await fetch('/api/codexlens/watch/status');
|
||||
var response = await csrfFetch('/api/codexlens/watch/status');
|
||||
var status = await response.json();
|
||||
|
||||
if (status.running) {
|
||||
@@ -6711,7 +6711,7 @@ async function flushWatcherNow() {
|
||||
var watchPath = document.getElementById('watcherPath');
|
||||
var path = watchPath ? watchPath.value.trim() : '';
|
||||
|
||||
var response = await fetch('/api/codexlens/watch/flush', {
|
||||
var response = await csrfFetch('/api/codexlens/watch/flush', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ path: path || undefined })
|
||||
@@ -6744,7 +6744,7 @@ async function showIndexHistory() {
|
||||
var watchPath = document.getElementById('watcherPath');
|
||||
var path = watchPath ? watchPath.value.trim() : '';
|
||||
|
||||
var response = await fetch('/api/codexlens/watch/history?limit=10&path=' + encodeURIComponent(path));
|
||||
var response = await csrfFetch('/api/codexlens/watch/history?limit=10&path=' + encodeURIComponent(path));
|
||||
var result = await response.json();
|
||||
|
||||
if (!result.success || !result.history || result.history.length === 0) {
|
||||
@@ -6945,7 +6945,7 @@ window.toggleIgnorePatternsSection = toggleIgnorePatternsSection;
|
||||
*/
|
||||
async function loadIgnorePatterns() {
|
||||
try {
|
||||
var response = await fetch('/api/codexlens/ignore-patterns');
|
||||
var response = await csrfFetch('/api/codexlens/ignore-patterns');
|
||||
var data = await response.json();
|
||||
|
||||
if (data.success) {
|
||||
@@ -6987,7 +6987,7 @@ async function saveIgnorePatterns() {
|
||||
var extensionFilters = filtersInput ? filtersInput.value.split('\n').map(function(p) { return p.trim(); }).filter(function(p) { return p; }) : [];
|
||||
|
||||
try {
|
||||
var response = await fetch('/api/codexlens/ignore-patterns', {
|
||||
var response = await csrfFetch('/api/codexlens/ignore-patterns', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ patterns: patterns, extensionFilters: extensionFilters })
|
||||
@@ -7020,7 +7020,7 @@ async function resetIgnorePatterns() {
|
||||
if (!ignorePatternsDefaults) {
|
||||
// Load defaults first if not cached
|
||||
try {
|
||||
var response = await fetch('/api/codexlens/ignore-patterns');
|
||||
var response = await csrfFetch('/api/codexlens/ignore-patterns');
|
||||
var data = await response.json();
|
||||
if (data.success) {
|
||||
ignorePatternsDefaults = data.defaults;
|
||||
@@ -7075,7 +7075,7 @@ async function initIgnorePatternsCount() {
|
||||
var extensionFilters = fallbackDefaults.extensionFilters;
|
||||
|
||||
try {
|
||||
var response = await fetch('/api/codexlens/ignore-patterns');
|
||||
var response = await csrfFetch('/api/codexlens/ignore-patterns');
|
||||
var data = await response.json();
|
||||
|
||||
if (data.success) {
|
||||
@@ -7121,3 +7121,4 @@ window.refreshCodexLensData = async function(forceRefresh) {
|
||||
await refreshWorkspaceIndexStatus(true);
|
||||
showRefreshToast(t('common.refreshed') || 'Refreshed', 'success');
|
||||
};
|
||||
|
||||
|
||||
@@ -399,7 +399,7 @@ async function toggleCommandEnabled(commandName, currentlyEnabled) {
|
||||
}
|
||||
|
||||
try {
|
||||
var response = await fetch('/api/commands/' + encodeURIComponent(commandName) + '/toggle', {
|
||||
var response = await csrfFetch('/api/commands/' + encodeURIComponent(commandName) + '/toggle', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({
|
||||
@@ -453,7 +453,7 @@ async function toggleGroupEnabled(groupName, currentlyAllEnabled) {
|
||||
const enable = !currentlyAllEnabled;
|
||||
|
||||
try {
|
||||
const response = await fetch('/api/commands/group/' + encodeURIComponent(groupName) + '/toggle', {
|
||||
const response = await csrfFetch('/api/commands/group/' + encodeURIComponent(groupName) + '/toggle', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({
|
||||
|
||||
@@ -121,7 +121,7 @@ function switchToSemanticStatus() {
|
||||
async function triggerEmbedding() {
|
||||
try {
|
||||
showNotification(t('coreMemory.embeddingInProgress'), 'info');
|
||||
const response = await fetch(`/api/core-memory/embed?path=${encodeURIComponent(projectPath)}`, {
|
||||
const response = await csrfFetch(`/api/core-memory/embed?path=${encodeURIComponent(projectPath)}`, {
|
||||
method: 'POST'
|
||||
});
|
||||
if (!response.ok) throw new Error(`HTTP ${response.status}`);
|
||||
@@ -342,7 +342,7 @@ async function triggerAutoClustering(scope = 'recent') {
|
||||
try {
|
||||
showNotification(t('coreMemory.clusteringInProgress'), 'info');
|
||||
|
||||
const response = await fetch(`/api/core-memory/clusters/auto?path=${encodeURIComponent(projectPath)}`, {
|
||||
const response = await csrfFetch(`/api/core-memory/clusters/auto?path=${encodeURIComponent(projectPath)}`, {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ scope })
|
||||
@@ -375,7 +375,7 @@ async function createCluster() {
|
||||
if (!name) return;
|
||||
|
||||
try {
|
||||
const response = await fetch(`/api/core-memory/clusters?path=${encodeURIComponent(projectPath)}`, {
|
||||
const response = await csrfFetch(`/api/core-memory/clusters?path=${encodeURIComponent(projectPath)}`, {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ name })
|
||||
@@ -409,7 +409,7 @@ function editCluster(clusterId) {
|
||||
*/
|
||||
async function updateCluster(clusterId, updates) {
|
||||
try {
|
||||
const response = await fetch(`/api/core-memory/clusters/${clusterId}?path=${encodeURIComponent(projectPath)}`, {
|
||||
const response = await csrfFetch(`/api/core-memory/clusters/${clusterId}?path=${encodeURIComponent(projectPath)}`, {
|
||||
method: 'PATCH',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify(updates)
|
||||
@@ -435,7 +435,7 @@ async function deleteCluster(clusterId) {
|
||||
if (!confirm(t('coreMemory.confirmDeleteCluster'))) return;
|
||||
|
||||
try {
|
||||
const response = await fetch(`/api/core-memory/clusters/${clusterId}?path=${encodeURIComponent(projectPath)}`, {
|
||||
const response = await csrfFetch(`/api/core-memory/clusters/${clusterId}?path=${encodeURIComponent(projectPath)}`, {
|
||||
method: 'DELETE'
|
||||
});
|
||||
|
||||
@@ -459,7 +459,7 @@ async function deleteCluster(clusterId) {
|
||||
*/
|
||||
async function removeMember(clusterId, sessionId) {
|
||||
try {
|
||||
const response = await fetch(
|
||||
const response = await csrfFetch(
|
||||
`/api/core-memory/clusters/${clusterId}/members/${sessionId}?path=${encodeURIComponent(projectPath)}`,
|
||||
{ method: 'DELETE' }
|
||||
);
|
||||
|
||||
@@ -470,7 +470,7 @@ async function saveMemory() {
|
||||
}
|
||||
|
||||
try {
|
||||
const response = await fetch('/api/core-memory/memories', {
|
||||
const response = await csrfFetch('/api/core-memory/memories', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify(payload)
|
||||
@@ -491,7 +491,7 @@ async function archiveMemory(memoryId) {
|
||||
if (!confirm(t('coreMemory.confirmArchive'))) return;
|
||||
|
||||
try {
|
||||
const response = await fetch(`/api/core-memory/memories/${memoryId}/archive?path=${encodeURIComponent(projectPath)}`, {
|
||||
const response = await csrfFetch(`/api/core-memory/memories/${memoryId}/archive?path=${encodeURIComponent(projectPath)}`, {
|
||||
method: 'POST'
|
||||
});
|
||||
|
||||
@@ -512,7 +512,7 @@ async function unarchiveMemory(memoryId) {
|
||||
|
||||
memory.archived = false;
|
||||
|
||||
const response = await fetch('/api/core-memory/memories', {
|
||||
const response = await csrfFetch('/api/core-memory/memories', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ ...memory, path: projectPath })
|
||||
@@ -532,7 +532,7 @@ async function deleteMemory(memoryId) {
|
||||
if (!confirm(t('coreMemory.confirmDelete'))) return;
|
||||
|
||||
try {
|
||||
const response = await fetch(`/api/core-memory/memories/${memoryId}?path=${encodeURIComponent(projectPath)}`, {
|
||||
const response = await csrfFetch(`/api/core-memory/memories/${memoryId}?path=${encodeURIComponent(projectPath)}`, {
|
||||
method: 'DELETE'
|
||||
});
|
||||
|
||||
@@ -551,7 +551,7 @@ async function generateMemorySummary(memoryId) {
|
||||
try {
|
||||
showNotification(t('coreMemory.generatingSummary'), 'info');
|
||||
|
||||
const response = await fetch(`/api/core-memory/memories/${memoryId}/summary`, {
|
||||
const response = await csrfFetch(`/api/core-memory/memories/${memoryId}/summary`, {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ tool: 'gemini', path: projectPath })
|
||||
@@ -861,7 +861,7 @@ async function toggleFavorite(memoryId) {
|
||||
}
|
||||
metadata.favorite = !metadata.favorite;
|
||||
|
||||
const response = await fetch('/api/core-memory/memories', {
|
||||
const response = await csrfFetch('/api/core-memory/memories', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ ...memory, metadata, path: projectPath })
|
||||
|
||||
@@ -570,7 +570,7 @@ async function executeUpdateClaudeMd() {
|
||||
statusEl.innerHTML = '<div class="status-running">⏳ Running update...</div>';
|
||||
|
||||
try {
|
||||
const response = await fetch('/api/update-claude-md', {
|
||||
const response = await csrfFetch('/api/update-claude-md', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ path, tool, strategy })
|
||||
@@ -808,7 +808,7 @@ async function executeTask(task) {
|
||||
addGlobalNotification('info', `Processing: ${folderName}`, `Strategy: ${task.strategy}, Tool: ${task.tool}`, 'Explorer');
|
||||
|
||||
try {
|
||||
const response = await fetch('/api/update-claude-md', {
|
||||
const response = await csrfFetch('/api/update-claude-md', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({
|
||||
@@ -885,4 +885,3 @@ async function startTaskQueue() {
|
||||
// Refresh tree to show updated CLAUDE.md files
|
||||
await refreshExplorerTree();
|
||||
}
|
||||
|
||||
|
||||
@@ -362,7 +362,7 @@ async function batchDeleteExecutions(ids) {
|
||||
showRefreshToast('Deleting ' + ids.length + ' executions...', 'info');
|
||||
|
||||
try {
|
||||
var response = await fetch('/api/cli/batch-delete', {
|
||||
var response = await csrfFetch('/api/cli/batch-delete', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({
|
||||
|
||||
@@ -66,7 +66,7 @@ async function renderIssueDiscovery() {
|
||||
async function loadDiscoveryData() {
|
||||
discoveryLoading = true;
|
||||
try {
|
||||
const response = await fetch('/api/discoveries?path=' + encodeURIComponent(projectPath));
|
||||
const response = await csrfFetch('/api/discoveries?path=' + encodeURIComponent(projectPath));
|
||||
if (!response.ok) throw new Error('Failed to load discoveries');
|
||||
const data = await response.json();
|
||||
discoveryData.discoveries = data.discoveries || [];
|
||||
@@ -81,7 +81,7 @@ async function loadDiscoveryData() {
|
||||
|
||||
async function loadDiscoveryDetail(discoveryId) {
|
||||
try {
|
||||
const response = await fetch('/api/discoveries/' + encodeURIComponent(discoveryId) + '?path=' + encodeURIComponent(projectPath));
|
||||
const response = await csrfFetch('/api/discoveries/' + encodeURIComponent(discoveryId) + '?path=' + encodeURIComponent(projectPath));
|
||||
if (!response.ok) throw new Error('Failed to load discovery detail');
|
||||
return await response.json();
|
||||
} catch (err) {
|
||||
@@ -111,7 +111,7 @@ async function loadDiscoveryFindings(discoveryId) {
|
||||
|
||||
async function loadDiscoveryProgress(discoveryId) {
|
||||
try {
|
||||
const response = await fetch('/api/discoveries/' + encodeURIComponent(discoveryId) + '/progress?path=' + encodeURIComponent(projectPath));
|
||||
const response = await csrfFetch('/api/discoveries/' + encodeURIComponent(discoveryId) + '/progress?path=' + encodeURIComponent(projectPath));
|
||||
if (!response.ok) return null;
|
||||
return await response.json();
|
||||
} catch (err) {
|
||||
@@ -568,7 +568,7 @@ async function exportSelectedFindings() {
|
||||
if (!discoveryId) return;
|
||||
|
||||
try {
|
||||
const response = await fetch('/api/discoveries/' + encodeURIComponent(discoveryId) + '/export?path=' + encodeURIComponent(projectPath), {
|
||||
const response = await csrfFetch('/api/discoveries/' + encodeURIComponent(discoveryId) + '/export?path=' + encodeURIComponent(projectPath), {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ finding_ids: Array.from(discoveryData.selectedFindings) })
|
||||
@@ -603,7 +603,7 @@ async function exportSingleFinding(findingId) {
|
||||
if (!discoveryId) return;
|
||||
|
||||
try {
|
||||
const response = await fetch('/api/discoveries/' + encodeURIComponent(discoveryId) + '/export?path=' + encodeURIComponent(projectPath), {
|
||||
const response = await csrfFetch('/api/discoveries/' + encodeURIComponent(discoveryId) + '/export?path=' + encodeURIComponent(projectPath), {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ finding_ids: [findingId] })
|
||||
@@ -629,7 +629,7 @@ async function dismissFinding(findingId) {
|
||||
if (!discoveryId) return;
|
||||
|
||||
try {
|
||||
const response = await fetch('/api/discoveries/' + encodeURIComponent(discoveryId) + '/findings/' + encodeURIComponent(findingId) + '?path=' + encodeURIComponent(projectPath), {
|
||||
const response = await csrfFetch('/api/discoveries/' + encodeURIComponent(discoveryId) + '/findings/' + encodeURIComponent(findingId) + '?path=' + encodeURIComponent(projectPath), {
|
||||
method: 'PATCH',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ dismissed: true })
|
||||
@@ -664,7 +664,7 @@ async function deleteDiscovery(discoveryId) {
|
||||
if (!confirm(`Delete discovery ${discoveryId}? This cannot be undone.`)) return;
|
||||
|
||||
try {
|
||||
const response = await fetch('/api/discoveries/' + encodeURIComponent(discoveryId) + '?path=' + encodeURIComponent(projectPath), {
|
||||
const response = await csrfFetch('/api/discoveries/' + encodeURIComponent(discoveryId) + '?path=' + encodeURIComponent(projectPath), {
|
||||
method: 'DELETE'
|
||||
});
|
||||
|
||||
@@ -728,3 +728,4 @@ function cleanupDiscoveryView() {
|
||||
discoveryData.selectedFindings.clear();
|
||||
discoveryData.viewMode = 'list';
|
||||
}
|
||||
|
||||
|
||||
@@ -57,7 +57,7 @@ async function renderIssueManager() {
|
||||
async function loadIssueData() {
|
||||
issueLoading = true;
|
||||
try {
|
||||
const response = await fetch('/api/issues?path=' + encodeURIComponent(projectPath));
|
||||
const response = await csrfFetch('/api/issues?path=' + encodeURIComponent(projectPath));
|
||||
if (!response.ok) throw new Error('Failed to load issues');
|
||||
const data = await response.json();
|
||||
issueData.issues = data.issues || [];
|
||||
@@ -72,7 +72,7 @@ async function loadIssueData() {
|
||||
|
||||
async function loadIssueHistory() {
|
||||
try {
|
||||
const response = await fetch('/api/issues/history?path=' + encodeURIComponent(projectPath));
|
||||
const response = await csrfFetch('/api/issues/history?path=' + encodeURIComponent(projectPath));
|
||||
if (!response.ok) throw new Error('Failed to load issue history');
|
||||
const data = await response.json();
|
||||
issueData.historyIssues = data.issues || [];
|
||||
@@ -84,7 +84,7 @@ async function loadIssueHistory() {
|
||||
|
||||
async function loadQueueData() {
|
||||
try {
|
||||
const response = await fetch('/api/queue?path=' + encodeURIComponent(projectPath));
|
||||
const response = await csrfFetch('/api/queue?path=' + encodeURIComponent(projectPath));
|
||||
if (!response.ok) throw new Error('Failed to load queue');
|
||||
issueData.queue = await response.json();
|
||||
} catch (err) {
|
||||
@@ -95,7 +95,7 @@ async function loadQueueData() {
|
||||
|
||||
async function loadAllQueues() {
|
||||
try {
|
||||
const response = await fetch('/api/queue/history?path=' + encodeURIComponent(projectPath));
|
||||
const response = await csrfFetch('/api/queue/history?path=' + encodeURIComponent(projectPath));
|
||||
if (!response.ok) throw new Error('Failed to load queue history');
|
||||
const data = await response.json();
|
||||
queueData.queues = data.queues || [];
|
||||
@@ -109,7 +109,7 @@ async function loadAllQueues() {
|
||||
|
||||
async function loadIssueDetail(issueId) {
|
||||
try {
|
||||
const response = await fetch('/api/issues/' + encodeURIComponent(issueId) + '?path=' + encodeURIComponent(projectPath));
|
||||
const response = await csrfFetch('/api/issues/' + encodeURIComponent(issueId) + '?path=' + encodeURIComponent(projectPath));
|
||||
if (!response.ok) throw new Error('Failed to load issue detail');
|
||||
return await response.json();
|
||||
} catch (err) {
|
||||
@@ -774,7 +774,7 @@ function toggleQueueExpand(queueId) {
|
||||
|
||||
async function activateQueue(queueId) {
|
||||
try {
|
||||
const response = await fetch('/api/queue/switch?path=' + encodeURIComponent(projectPath), {
|
||||
const response = await csrfFetch('/api/queue/switch?path=' + encodeURIComponent(projectPath), {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ queueId })
|
||||
@@ -795,7 +795,7 @@ async function activateQueue(queueId) {
|
||||
|
||||
async function deactivateQueue(queueId) {
|
||||
try {
|
||||
const response = await fetch('/api/queue/deactivate?path=' + encodeURIComponent(projectPath), {
|
||||
const response = await csrfFetch('/api/queue/deactivate?path=' + encodeURIComponent(projectPath), {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ queueId })
|
||||
@@ -824,7 +824,7 @@ function confirmDeleteQueue(queueId) {
|
||||
|
||||
async function deleteQueue(queueId) {
|
||||
try {
|
||||
const response = await fetch('/api/queue/' + encodeURIComponent(queueId) + '?path=' + encodeURIComponent(projectPath), {
|
||||
const response = await csrfFetch('/api/queue/' + encodeURIComponent(queueId) + '?path=' + encodeURIComponent(projectPath), {
|
||||
method: 'DELETE'
|
||||
});
|
||||
const result = await response.json();
|
||||
@@ -847,7 +847,7 @@ async function renderExpandedQueueView(queueId) {
|
||||
// Fetch queue detail
|
||||
let queue;
|
||||
try {
|
||||
const response = await fetch('/api/queue/' + encodeURIComponent(queueId) + '?path=' + encodeURIComponent(projectPath));
|
||||
const response = await csrfFetch('/api/queue/' + encodeURIComponent(queueId) + '?path=' + encodeURIComponent(projectPath));
|
||||
queue = await response.json();
|
||||
if (queue.error) throw new Error(queue.error);
|
||||
} catch (err) {
|
||||
@@ -1107,7 +1107,7 @@ async function deleteQueueItem(queueId, itemId) {
|
||||
if (!confirm('Delete this item from queue?')) return;
|
||||
|
||||
try {
|
||||
const response = await fetch('/api/queue/' + queueId + '/item/' + encodeURIComponent(itemId) + '?path=' + encodeURIComponent(projectPath), {
|
||||
const response = await csrfFetch('/api/queue/' + queueId + '/item/' + encodeURIComponent(itemId) + '?path=' + encodeURIComponent(projectPath), {
|
||||
method: 'DELETE'
|
||||
});
|
||||
const result = await response.json();
|
||||
@@ -1202,7 +1202,7 @@ async function executeQueueMerge(sourceQueueId) {
|
||||
if (!targetQueueId) return;
|
||||
|
||||
try {
|
||||
const response = await fetch('/api/queue/merge?path=' + encodeURIComponent(projectPath), {
|
||||
const response = await csrfFetch('/api/queue/merge?path=' + encodeURIComponent(projectPath), {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ sourceQueueId, targetQueueId })
|
||||
@@ -1237,7 +1237,7 @@ async function showSplitQueueModal(queueId) {
|
||||
// Fetch queue details
|
||||
let queue;
|
||||
try {
|
||||
const response = await fetch('/api/queue/' + encodeURIComponent(queueId) + '?path=' + encodeURIComponent(projectPath));
|
||||
const response = await csrfFetch('/api/queue/' + encodeURIComponent(queueId) + '?path=' + encodeURIComponent(projectPath));
|
||||
queue = await response.json();
|
||||
if (queue.error) throw new Error(queue.error);
|
||||
} catch (err) {
|
||||
@@ -1384,7 +1384,7 @@ async function executeQueueSplit(sourceQueueId) {
|
||||
}
|
||||
|
||||
try {
|
||||
const response = await fetch('/api/queue/split?path=' + encodeURIComponent(projectPath), {
|
||||
const response = await csrfFetch('/api/queue/split?path=' + encodeURIComponent(projectPath), {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ sourceQueueId, itemIds: selectedItemIds })
|
||||
@@ -1714,7 +1714,7 @@ function handleIssueDrop(e) {
|
||||
|
||||
async function saveQueueOrder(groupId, newOrder) {
|
||||
try {
|
||||
const response = await fetch('/api/queue/reorder?path=' + encodeURIComponent(projectPath), {
|
||||
const response = await csrfFetch('/api/queue/reorder?path=' + encodeURIComponent(projectPath), {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ groupId, newOrder })
|
||||
@@ -1896,7 +1896,7 @@ function confirmDeleteIssue(issueId, isArchived) {
|
||||
|
||||
async function deleteIssue(issueId, isArchived) {
|
||||
try {
|
||||
const response = await fetch('/api/issues/' + encodeURIComponent(issueId) + '?path=' + encodeURIComponent(projectPath), {
|
||||
const response = await csrfFetch('/api/issues/' + encodeURIComponent(issueId) + '?path=' + encodeURIComponent(projectPath), {
|
||||
method: 'DELETE'
|
||||
});
|
||||
const result = await response.json();
|
||||
@@ -1928,7 +1928,7 @@ function confirmArchiveIssue(issueId) {
|
||||
|
||||
async function archiveIssue(issueId) {
|
||||
try {
|
||||
const response = await fetch('/api/issues/' + encodeURIComponent(issueId) + '/archive?path=' + encodeURIComponent(projectPath), {
|
||||
const response = await csrfFetch('/api/issues/' + encodeURIComponent(issueId) + '/archive?path=' + encodeURIComponent(projectPath), {
|
||||
method: 'POST'
|
||||
});
|
||||
const result = await response.json();
|
||||
@@ -2262,7 +2262,7 @@ async function toggleSolutionBind() {
|
||||
const action = solution.is_bound ? 'unbind' : 'bind';
|
||||
|
||||
try {
|
||||
const response = await fetch('/api/issues/' + encodeURIComponent(issueId) + '?path=' + encodeURIComponent(projectPath), {
|
||||
const response = await csrfFetch('/api/issues/' + encodeURIComponent(issueId) + '?path=' + encodeURIComponent(projectPath), {
|
||||
method: 'PATCH',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({
|
||||
@@ -2372,7 +2372,7 @@ async function saveFieldEdit(issueId, field) {
|
||||
if (!value) return;
|
||||
|
||||
try {
|
||||
const response = await fetch('/api/issues/' + encodeURIComponent(issueId) + '?path=' + encodeURIComponent(projectPath), {
|
||||
const response = await csrfFetch('/api/issues/' + encodeURIComponent(issueId) + '?path=' + encodeURIComponent(projectPath), {
|
||||
method: 'PATCH',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ [field]: value })
|
||||
@@ -2402,7 +2402,7 @@ async function saveContextEdit(issueId) {
|
||||
const value = textarea.value;
|
||||
|
||||
try {
|
||||
const response = await fetch('/api/issues/' + encodeURIComponent(issueId) + '?path=' + encodeURIComponent(projectPath), {
|
||||
const response = await csrfFetch('/api/issues/' + encodeURIComponent(issueId) + '?path=' + encodeURIComponent(projectPath), {
|
||||
method: 'PATCH',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ context: value })
|
||||
@@ -2432,7 +2432,7 @@ function cancelEdit() {
|
||||
|
||||
async function updateTaskStatus(issueId, taskId, status) {
|
||||
try {
|
||||
const response = await fetch('/api/issues/' + encodeURIComponent(issueId) + '/tasks/' + encodeURIComponent(taskId) + '?path=' + encodeURIComponent(projectPath), {
|
||||
const response = await csrfFetch('/api/issues/' + encodeURIComponent(issueId) + '/tasks/' + encodeURIComponent(taskId) + '?path=' + encodeURIComponent(projectPath), {
|
||||
method: 'PATCH',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ status })
|
||||
@@ -2748,7 +2748,7 @@ async function pullGitHubIssues() {
|
||||
});
|
||||
if (labels) params.set('labels', labels);
|
||||
|
||||
const response = await fetch('/api/issues/pull?' + params.toString(), {
|
||||
const response = await csrfFetch('/api/issues/pull?' + params.toString(), {
|
||||
method: 'POST'
|
||||
});
|
||||
|
||||
@@ -2833,7 +2833,7 @@ async function createIssue() {
|
||||
}
|
||||
|
||||
try {
|
||||
const response = await fetch('/api/issues?path=' + encodeURIComponent(projectPath), {
|
||||
const response = await csrfFetch('/api/issues?path=' + encodeURIComponent(projectPath), {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({
|
||||
@@ -2871,7 +2871,7 @@ async function deleteIssue(issueId) {
|
||||
}
|
||||
|
||||
try {
|
||||
const response = await fetch('/api/issues/' + encodeURIComponent(issueId) + '?path=' + encodeURIComponent(projectPath), {
|
||||
const response = await csrfFetch('/api/issues/' + encodeURIComponent(issueId) + '?path=' + encodeURIComponent(projectPath), {
|
||||
method: 'DELETE'
|
||||
});
|
||||
|
||||
@@ -3092,7 +3092,7 @@ function hideQueueHistoryModal() {
|
||||
|
||||
async function switchToQueue(queueId) {
|
||||
try {
|
||||
const response = await fetch(`/api/queue/switch?path=${encodeURIComponent(projectPath)}`, {
|
||||
const response = await csrfFetch(`/api/queue/switch?path=${encodeURIComponent(projectPath)}`, {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ queueId })
|
||||
@@ -3246,3 +3246,4 @@ function copyCommand(command) {
|
||||
showNotification(t('common.copied') || 'Copied to clipboard', 'success');
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -42,7 +42,7 @@ async function getEnabledTools() {
|
||||
}
|
||||
|
||||
try {
|
||||
const response = await fetch('/api/cli/tools-config');
|
||||
const response = await csrfFetch('/api/cli/tools-config');
|
||||
const result = await response.json();
|
||||
|
||||
if (result.tools && typeof result.tools === 'object') {
|
||||
@@ -238,7 +238,7 @@ function handleLoopUpdate(data) {
|
||||
async function loadLoops() {
|
||||
try {
|
||||
// Fetch v2 loops (new simplified format)
|
||||
const v2Response = await fetch('/api/loops/v2');
|
||||
const v2Response = await csrfFetch('/api/loops/v2');
|
||||
const v2Result = await v2Response.json();
|
||||
|
||||
if (v2Result.success && v2Result.data) {
|
||||
@@ -248,7 +248,7 @@ async function loadLoops() {
|
||||
}
|
||||
|
||||
// Fetch v1 loops (legacy format with task_id)
|
||||
const v1Response = await fetch('/api/loops');
|
||||
const v1Response = await csrfFetch('/api/loops');
|
||||
const v1Result = await v1Response.json();
|
||||
|
||||
if (v1Result.success && v1Result.data) {
|
||||
@@ -276,7 +276,7 @@ async function loadLoops() {
|
||||
*/
|
||||
async function showTasksTabIfAny() {
|
||||
try {
|
||||
const response = await fetch('/api/tasks');
|
||||
const response = await csrfFetch('/api/tasks');
|
||||
const result = await response.json();
|
||||
|
||||
if (result.success) {
|
||||
@@ -642,7 +642,7 @@ async function pauseLoop(loopId) {
|
||||
const endpoint = isV2 ? `/api/loops/v2/${loopId}/pause` : `/api/loops/${loopId}/pause`;
|
||||
|
||||
try {
|
||||
const response = await fetch(endpoint, { method: 'POST' });
|
||||
const response = await csrfFetch(endpoint, { method: 'POST' });
|
||||
const result = await response.json();
|
||||
|
||||
if (result.success) {
|
||||
@@ -666,7 +666,7 @@ async function resumeLoop(loopId) {
|
||||
const endpoint = isV2 ? `/api/loops/v2/${loopId}/resume` : `/api/loops/${loopId}/resume`;
|
||||
|
||||
try {
|
||||
const response = await fetch(endpoint, { method: 'POST' });
|
||||
const response = await csrfFetch(endpoint, { method: 'POST' });
|
||||
const result = await response.json();
|
||||
|
||||
if (result.success) {
|
||||
@@ -708,7 +708,7 @@ async function stopLoop(loopId) {
|
||||
const endpoint = isV2 ? `/api/loops/v2/${loopId}/stop` : `/api/loops/${loopId}/stop`;
|
||||
|
||||
try {
|
||||
const response = await fetch(endpoint, { method: 'POST' });
|
||||
const response = await csrfFetch(endpoint, { method: 'POST' });
|
||||
const result = await response.json();
|
||||
|
||||
if (result.success) {
|
||||
@@ -728,7 +728,7 @@ async function stopLoop(loopId) {
|
||||
*/
|
||||
async function startLoopV2(loopId) {
|
||||
try {
|
||||
const response = await fetch(`/api/loops/v2/${loopId}/start`, { method: 'POST' });
|
||||
const response = await csrfFetch(`/api/loops/v2/${loopId}/start`, { method: 'POST' });
|
||||
const result = await response.json();
|
||||
|
||||
if (result.success) {
|
||||
@@ -984,7 +984,7 @@ function handleTaskDrop(e) {
|
||||
*/
|
||||
async function saveTaskOrder(loopId, newOrder) {
|
||||
try {
|
||||
const response = await fetch(`/api/loops/v2/${encodeURIComponent(loopId)}/tasks/reorder`, {
|
||||
const response = await csrfFetch(`/api/loops/v2/${encodeURIComponent(loopId)}/tasks/reorder`, {
|
||||
method: 'PUT',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ ordered_task_ids: newOrder })
|
||||
@@ -1224,7 +1224,7 @@ async function handleAddTask(event, loopId) {
|
||||
|
||||
try {
|
||||
// Call POST /api/loops/v2/:loopId/tasks
|
||||
const response = await fetch(`/api/loops/v2/${encodeURIComponent(loopId)}/tasks`, {
|
||||
const response = await csrfFetch(`/api/loops/v2/${encodeURIComponent(loopId)}/tasks`, {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({
|
||||
@@ -1383,7 +1383,7 @@ async function handleEditTask(event, loopId, taskId) {
|
||||
|
||||
try {
|
||||
// Call PUT /api/loops/v2/:loopId/tasks/:taskId
|
||||
const response = await fetch(`/api/loops/v2/${encodeURIComponent(loopId)}/tasks/${encodeURIComponent(taskId)}`, {
|
||||
const response = await csrfFetch(`/api/loops/v2/${encodeURIComponent(loopId)}/tasks/${encodeURIComponent(taskId)}`, {
|
||||
method: 'PUT',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({
|
||||
@@ -1435,7 +1435,7 @@ async function deleteTask(taskId) {
|
||||
|
||||
try {
|
||||
// Call DELETE /api/loops/v2/:loopId/tasks/:taskId
|
||||
const response = await fetch(`/api/loops/v2/${encodeURIComponent(loopId)}/tasks/${encodeURIComponent(taskId)}`, {
|
||||
const response = await csrfFetch(`/api/loops/v2/${encodeURIComponent(loopId)}/tasks/${encodeURIComponent(taskId)}`, {
|
||||
method: 'DELETE'
|
||||
});
|
||||
|
||||
@@ -1912,7 +1912,7 @@ async function handleKanbanDrop(event, loopId, newStatus) {
|
||||
*/
|
||||
async function updateLoopStatus(loopId, status) {
|
||||
try {
|
||||
const response = await fetch(`/api/loops/v2/${encodeURIComponent(loopId)}/status`, {
|
||||
const response = await csrfFetch(`/api/loops/v2/${encodeURIComponent(loopId)}/status`, {
|
||||
method: 'PATCH',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ status })
|
||||
@@ -1953,7 +1953,7 @@ async function updateLoopStatus(loopId, status) {
|
||||
*/
|
||||
async function updateLoopMetadata(loopId, metadata) {
|
||||
try {
|
||||
const response = await fetch(`/api/loops/v2/${encodeURIComponent(loopId)}`, {
|
||||
const response = await csrfFetch(`/api/loops/v2/${encodeURIComponent(loopId)}`, {
|
||||
method: 'PUT',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify(metadata)
|
||||
@@ -1995,7 +1995,7 @@ async function updateLoopMetadata(loopId, metadata) {
|
||||
*/
|
||||
async function updateTaskStatus(loopId, taskId, newStatus) {
|
||||
try {
|
||||
const response = await fetch(`/api/loops/v2/${encodeURIComponent(loopId)}/tasks/${encodeURIComponent(taskId)}`, {
|
||||
const response = await csrfFetch(`/api/loops/v2/${encodeURIComponent(loopId)}/tasks/${encodeURIComponent(taskId)}`, {
|
||||
method: 'PUT',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ status: newStatus })
|
||||
@@ -2493,7 +2493,7 @@ function renderGroupedLoopList() {
|
||||
*/
|
||||
async function showTasksTab() {
|
||||
try {
|
||||
const response = await fetch('/api/tasks');
|
||||
const response = await csrfFetch('/api/tasks');
|
||||
const result = await response.json();
|
||||
|
||||
if (!result.success) {
|
||||
@@ -2578,7 +2578,7 @@ function renderTaskCard(task) {
|
||||
*/
|
||||
async function startLoopFromTask(taskId) {
|
||||
try {
|
||||
const response = await fetch('/api/loops', {
|
||||
const response = await csrfFetch('/api/loops', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ taskId })
|
||||
@@ -2750,7 +2750,7 @@ window.availableCliTools = [];
|
||||
*/
|
||||
async function fetchAvailableCliTools() {
|
||||
try {
|
||||
const response = await fetch('/api/cli/status');
|
||||
const response = await csrfFetch('/api/cli/status');
|
||||
const data = await response.json();
|
||||
// Return only available tools (where available: true)
|
||||
return Object.entries(data)
|
||||
@@ -2992,7 +2992,7 @@ async function handleSimpleCreateLoop(event) {
|
||||
|
||||
try {
|
||||
// Call POST /api/loops/v2
|
||||
const response = await fetch('/api/loops/v2', {
|
||||
const response = await csrfFetch('/api/loops/v2', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({
|
||||
@@ -3046,7 +3046,7 @@ function closeCreateLoopModal() {
|
||||
*/
|
||||
async function importFromIssue() {
|
||||
try {
|
||||
const response = await fetch('/api/issues');
|
||||
const response = await csrfFetch('/api/issues');
|
||||
const data = await response.json();
|
||||
|
||||
if (!data.issues || data.issues.length === 0) {
|
||||
@@ -3321,7 +3321,7 @@ async function handleCreateLoopSubmit(event) {
|
||||
|
||||
try {
|
||||
// Create task only (don't auto-start)
|
||||
const createResponse = await fetch('/api/tasks', {
|
||||
const createResponse = await csrfFetch('/api/tasks', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify(task)
|
||||
@@ -3343,3 +3343,4 @@ async function handleCreateLoopSubmit(event) {
|
||||
showError(t('loop.createFailed') + ': ' + err.message);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1452,7 +1452,7 @@ async function copyCrossCliServer(name, config, fromCli, targetCli) {
|
||||
body = { serverName: name, serverConfig: config };
|
||||
}
|
||||
|
||||
const res = await fetch(endpoint, {
|
||||
const res = await csrfFetch(endpoint, {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify(body)
|
||||
@@ -2141,7 +2141,7 @@ let mcpTemplates = [];
|
||||
*/
|
||||
async function loadMcpTemplates() {
|
||||
try {
|
||||
const response = await fetch('/api/mcp-templates');
|
||||
const response = await csrfFetch('/api/mcp-templates');
|
||||
const data = await response.json();
|
||||
|
||||
if (data.success) {
|
||||
@@ -2178,7 +2178,7 @@ async function saveMcpAsTemplate(serverName, serverConfig) {
|
||||
category: 'user'
|
||||
};
|
||||
|
||||
const response = await fetch('/api/mcp-templates', {
|
||||
const response = await csrfFetch('/api/mcp-templates', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify(payload)
|
||||
@@ -2235,7 +2235,7 @@ async function installFromTemplate(templateName, scope = 'project') {
|
||||
*/
|
||||
async function deleteMcpTemplate(templateName) {
|
||||
try {
|
||||
const response = await fetch(`/api/mcp-templates/${encodeURIComponent(templateName)}`, {
|
||||
const response = await csrfFetch(`/api/mcp-templates/${encodeURIComponent(templateName)}`, {
|
||||
method: 'DELETE'
|
||||
});
|
||||
|
||||
@@ -2261,3 +2261,4 @@ window.closeMcpEditModal = closeMcpEditModal;
|
||||
window.saveMcpEdit = saveMcpEdit;
|
||||
window.deleteMcpFromEdit = deleteMcpFromEdit;
|
||||
window.saveMcpAsTemplate = saveMcpAsTemplate;
|
||||
|
||||
|
||||
@@ -122,7 +122,7 @@ function renderActiveMemoryControls() {
|
||||
// ========== Data Loading ==========
|
||||
async function loadMemoryStats() {
|
||||
try {
|
||||
var response = await fetch('/api/memory/stats?filter=' + memoryTimeFilter);
|
||||
var response = await csrfFetch('/api/memory/stats?filter=' + memoryTimeFilter);
|
||||
if (!response.ok) throw new Error('Failed to load memory stats');
|
||||
var data = await response.json();
|
||||
memoryStats = data.stats || { mostRead: [], mostEdited: [] };
|
||||
@@ -136,7 +136,7 @@ async function loadMemoryStats() {
|
||||
|
||||
async function loadMemoryGraph() {
|
||||
try {
|
||||
var response = await fetch('/api/memory/graph');
|
||||
var response = await csrfFetch('/api/memory/graph');
|
||||
if (!response.ok) throw new Error('Failed to load memory graph');
|
||||
var data = await response.json();
|
||||
memoryGraphData = data.graph || { nodes: [], edges: [] };
|
||||
@@ -150,7 +150,7 @@ async function loadMemoryGraph() {
|
||||
|
||||
async function loadRecentContext() {
|
||||
try {
|
||||
var response = await fetch('/api/memory/recent');
|
||||
var response = await csrfFetch('/api/memory/recent');
|
||||
if (!response.ok) throw new Error('Failed to load recent context');
|
||||
var data = await response.json();
|
||||
recentContext = data.recent || [];
|
||||
@@ -164,7 +164,7 @@ async function loadRecentContext() {
|
||||
|
||||
async function loadInsightsHistory() {
|
||||
try {
|
||||
var response = await fetch('/api/memory/insights?limit=10');
|
||||
var response = await csrfFetch('/api/memory/insights?limit=10');
|
||||
if (!response.ok) throw new Error('Failed to load insights history');
|
||||
var data = await response.json();
|
||||
insightsHistory = data.insights || [];
|
||||
@@ -206,7 +206,7 @@ function stopActiveMemorySyncTimer() {
|
||||
|
||||
async function loadActiveMemoryStatus() {
|
||||
try {
|
||||
var response = await fetch('/api/memory/active/status');
|
||||
var response = await csrfFetch('/api/memory/active/status');
|
||||
if (!response.ok) throw new Error('Failed to load active memory status');
|
||||
var data = await response.json();
|
||||
activeMemoryEnabled = data.enabled || false;
|
||||
@@ -232,7 +232,7 @@ async function loadActiveMemoryStatus() {
|
||||
|
||||
async function toggleActiveMemory(enabled) {
|
||||
try {
|
||||
var response = await fetch('/api/memory/active/toggle', {
|
||||
var response = await csrfFetch('/api/memory/active/toggle', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({
|
||||
@@ -273,7 +273,7 @@ async function updateActiveMemoryConfig(key, value) {
|
||||
activeMemoryConfig[key] = value;
|
||||
|
||||
try {
|
||||
var response = await fetch('/api/memory/active/config', {
|
||||
var response = await csrfFetch('/api/memory/active/config', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ config: activeMemoryConfig })
|
||||
@@ -304,7 +304,7 @@ async function syncActiveMemory() {
|
||||
}
|
||||
|
||||
try {
|
||||
var response = await fetch('/api/memory/active/sync', {
|
||||
var response = await csrfFetch('/api/memory/active/sync', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({
|
||||
@@ -1030,7 +1030,7 @@ function getToolIcon(tool) {
|
||||
|
||||
async function showInsightDetail(insightId) {
|
||||
try {
|
||||
var response = await fetch('/api/memory/insights/' + insightId);
|
||||
var response = await csrfFetch('/api/memory/insights/' + insightId);
|
||||
if (!response.ok) throw new Error('Failed to load insight detail');
|
||||
var data = await response.json();
|
||||
selectedInsight = data.insight;
|
||||
@@ -1114,7 +1114,7 @@ async function deleteInsight(insightId) {
|
||||
if (!confirm(t('memory.confirmDeleteInsight'))) return;
|
||||
|
||||
try {
|
||||
var response = await csrfFetch('/api/memory/insights/' + insightId, { method: 'DELETE' });
|
||||
var response = await csrfcsrfFetch('/api/memory/insights/' + insightId, { method: 'DELETE' });
|
||||
if (!response.ok) throw new Error('Failed to delete insight');
|
||||
|
||||
selectedInsight = null;
|
||||
@@ -1219,3 +1219,4 @@ function formatTimestamp(timestamp) {
|
||||
// Otherwise show date
|
||||
return date.toLocaleDateString() + ' ' + date.toLocaleTimeString();
|
||||
}
|
||||
|
||||
|
||||
@@ -15,7 +15,7 @@ var selectedPromptInsight = null; // Currently selected insight for detail view
|
||||
async function loadPromptHistory() {
|
||||
try {
|
||||
// Use native Claude history.jsonl as primary source
|
||||
var response = await fetch('/api/memory/native-history?path=' + encodeURIComponent(projectPath) + '&limit=200');
|
||||
var response = await csrfFetch('/api/memory/native-history?path=' + encodeURIComponent(projectPath) + '&limit=200');
|
||||
if (!response.ok) throw new Error('Failed to load prompt history');
|
||||
var data = await response.json();
|
||||
promptHistoryData = data.prompts || [];
|
||||
@@ -30,7 +30,7 @@ async function loadPromptHistory() {
|
||||
|
||||
async function loadPromptInsights() {
|
||||
try {
|
||||
var response = await fetch('/api/memory/insights?path=' + encodeURIComponent(projectPath));
|
||||
var response = await csrfFetch('/api/memory/insights?path=' + encodeURIComponent(projectPath));
|
||||
if (!response.ok) throw new Error('Failed to load insights');
|
||||
var data = await response.json();
|
||||
promptInsights = data.insights || null;
|
||||
@@ -44,7 +44,7 @@ async function loadPromptInsights() {
|
||||
|
||||
async function loadPromptInsightsHistory() {
|
||||
try {
|
||||
var response = await fetch('/api/memory/insights?limit=20&path=' + encodeURIComponent(projectPath));
|
||||
var response = await csrfFetch('/api/memory/insights?limit=20&path=' + encodeURIComponent(projectPath));
|
||||
if (!response.ok) throw new Error('Failed to load insights history');
|
||||
var data = await response.json();
|
||||
promptInsightsHistory = data.insights || [];
|
||||
@@ -347,7 +347,7 @@ function formatPromptTimestamp(timestamp) {
|
||||
|
||||
async function showPromptInsightDetail(insightId) {
|
||||
try {
|
||||
var response = await fetch('/api/memory/insights/' + insightId);
|
||||
var response = await csrfFetch('/api/memory/insights/' + insightId);
|
||||
if (!response.ok) throw new Error('Failed to load insight detail');
|
||||
var data = await response.json();
|
||||
selectedPromptInsight = data.insight;
|
||||
@@ -431,7 +431,7 @@ async function deletePromptInsight(insightId) {
|
||||
if (!confirm(isZh() ? '确定要删除这条洞察记录吗?' : 'Are you sure you want to delete this insight?')) return;
|
||||
|
||||
try {
|
||||
var response = await csrfFetch('/api/memory/insights/' + insightId, { method: 'DELETE' });
|
||||
var response = await csrfcsrfFetch('/api/memory/insights/' + insightId, { method: 'DELETE' });
|
||||
if (!response.ok) throw new Error('Failed to delete insight');
|
||||
|
||||
selectedPromptInsight = null;
|
||||
@@ -676,7 +676,7 @@ async function triggerCliInsightsAnalysis() {
|
||||
renderPromptHistoryView();
|
||||
|
||||
try {
|
||||
var response = await fetch('/api/memory/insights/analyze', {
|
||||
var response = await csrfFetch('/api/memory/insights/analyze', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({
|
||||
@@ -711,3 +711,4 @@ async function triggerCliInsightsAnalysis() {
|
||||
renderPromptHistoryView();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -36,7 +36,7 @@ async function renderRulesManager() {
|
||||
async function loadRulesData() {
|
||||
rulesLoading = true;
|
||||
try {
|
||||
const response = await fetch('/api/rules?path=' + encodeURIComponent(projectPath));
|
||||
const response = await csrfFetch('/api/rules?path=' + encodeURIComponent(projectPath));
|
||||
if (!response.ok) throw new Error('Failed to load rules');
|
||||
const data = await response.json();
|
||||
rulesData = {
|
||||
@@ -284,7 +284,7 @@ function renderRuleDetailPanel(rule) {
|
||||
|
||||
async function showRuleDetail(ruleName, location) {
|
||||
try {
|
||||
const response = await fetch('/api/rules/' + encodeURIComponent(ruleName) + '?location=' + location + '&path=' + encodeURIComponent(projectPath));
|
||||
const response = await csrfFetch('/api/rules/' + encodeURIComponent(ruleName) + '?location=' + location + '&path=' + encodeURIComponent(projectPath));
|
||||
if (!response.ok) throw new Error('Failed to load rule detail');
|
||||
const data = await response.json();
|
||||
selectedRule = data.rule;
|
||||
@@ -306,7 +306,7 @@ async function deleteRule(ruleName, location) {
|
||||
if (!confirm(t('rules.deleteConfirm', { name: ruleName }))) return;
|
||||
|
||||
try {
|
||||
const response = await fetch('/api/rules/' + encodeURIComponent(ruleName), {
|
||||
const response = await csrfFetch('/api/rules/' + encodeURIComponent(ruleName), {
|
||||
method: 'DELETE',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ location, projectPath })
|
||||
@@ -847,7 +847,7 @@ async function createRule() {
|
||||
}
|
||||
|
||||
try {
|
||||
const response = await fetch('/api/rules/create', {
|
||||
const response = await csrfFetch('/api/rules/create', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify(requestBody)
|
||||
@@ -878,3 +878,4 @@ async function createRule() {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -567,7 +567,7 @@ async function updateSingleTaskStatus(taskId, newStatus) {
|
||||
}
|
||||
|
||||
try {
|
||||
const response = await fetch('/api/update-task-status', {
|
||||
const response = await csrfFetch('/api/update-task-status', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({
|
||||
@@ -610,7 +610,7 @@ async function bulkSetAllStatus(newStatus) {
|
||||
}
|
||||
|
||||
try {
|
||||
const response = await fetch('/api/bulk-update-task-status', {
|
||||
const response = await csrfFetch('/api/bulk-update-task-status', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({
|
||||
@@ -651,7 +651,7 @@ async function bulkSetPendingToInProgress() {
|
||||
}
|
||||
|
||||
try {
|
||||
const response = await fetch('/api/bulk-update-task-status', {
|
||||
const response = await csrfFetch('/api/bulk-update-task-status', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({
|
||||
@@ -691,7 +691,7 @@ async function bulkSetInProgressToCompleted() {
|
||||
}
|
||||
|
||||
try {
|
||||
const response = await fetch('/api/bulk-update-task-status', {
|
||||
const response = await csrfFetch('/api/bulk-update-task-status', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({
|
||||
@@ -779,3 +779,4 @@ function showToast(message, type = 'info') {
|
||||
setTimeout(() => toast.remove(), 300);
|
||||
}, 3000);
|
||||
}
|
||||
|
||||
|
||||
@@ -39,7 +39,7 @@ async function renderSkillsManager() {
|
||||
async function loadSkillsData() {
|
||||
skillsLoading = true;
|
||||
try {
|
||||
const response = await fetch('/api/skills?path=' + encodeURIComponent(projectPath) + '&includeDisabled=true');
|
||||
const response = await csrfFetch('/api/skills?path=' + encodeURIComponent(projectPath) + '&includeDisabled=true');
|
||||
if (!response.ok) throw new Error('Failed to load skills');
|
||||
const data = await response.json();
|
||||
skillsData = {
|
||||
@@ -380,7 +380,7 @@ function renderSkillDetailPanel(skill) {
|
||||
|
||||
async function showSkillDetail(skillName, location) {
|
||||
try {
|
||||
const response = await fetch('/api/skills/' + encodeURIComponent(skillName) + '?location=' + location + '&path=' + encodeURIComponent(projectPath));
|
||||
const response = await csrfFetch('/api/skills/' + encodeURIComponent(skillName) + '?location=' + location + '&path=' + encodeURIComponent(projectPath));
|
||||
if (!response.ok) throw new Error('Failed to load skill detail');
|
||||
const data = await response.json();
|
||||
selectedSkill = data.skill;
|
||||
@@ -402,7 +402,7 @@ async function deleteSkill(skillName, location) {
|
||||
if (!confirm(t('skills.deleteConfirm', { name: skillName }))) return;
|
||||
|
||||
try {
|
||||
const response = await fetch('/api/skills/' + encodeURIComponent(skillName), {
|
||||
const response = await csrfFetch('/api/skills/' + encodeURIComponent(skillName), {
|
||||
method: 'DELETE',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ location, projectPath })
|
||||
@@ -458,7 +458,7 @@ async function toggleSkillEnabled(skillName, location, currentlyEnabled) {
|
||||
}
|
||||
|
||||
try {
|
||||
var response = await fetch('/api/skills/' + encodeURIComponent(skillName) + '/' + action, {
|
||||
var response = await csrfFetch('/api/skills/' + encodeURIComponent(skillName) + '/' + action, {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ location: location, projectPath: projectPath })
|
||||
@@ -821,7 +821,7 @@ async function validateSkillImport() {
|
||||
showValidationResult({ loading: true });
|
||||
|
||||
try {
|
||||
const response = await fetch('/api/skills/validate-import', {
|
||||
const response = await csrfFetch('/api/skills/validate-import', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ sourcePath })
|
||||
@@ -910,7 +910,7 @@ async function createSkill() {
|
||||
}
|
||||
|
||||
try {
|
||||
const response = await fetch('/api/skills/create', {
|
||||
const response = await csrfFetch('/api/skills/create', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({
|
||||
@@ -975,7 +975,7 @@ async function createSkill() {
|
||||
showToast(t('skills.generating'), 'info');
|
||||
}
|
||||
|
||||
const response = await fetch('/api/skills/create', {
|
||||
const response = await csrfFetch('/api/skills/create', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({
|
||||
@@ -1158,7 +1158,7 @@ async function saveSkillFile() {
|
||||
const { skillName, fileName, location } = skillFileEditorState;
|
||||
|
||||
try {
|
||||
const response = await fetch('/api/skills/' + encodeURIComponent(skillName) + '/file', {
|
||||
const response = await csrfFetch('/api/skills/' + encodeURIComponent(skillName) + '/file', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({
|
||||
@@ -1280,3 +1280,4 @@ async function toggleSkillFolder(skillName, subPath, location, element) {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user