feat: 升级至 v0.3.13 — 任务管理系统重构(删除 todo_write + IPC 越权防护 + UI 自动刷新)
This commit is contained in:
@@ -11,6 +11,7 @@
|
||||
|
||||
import { ipcMain, BrowserWindow, shell, app, dialog } from 'electron';
|
||||
import { join } from 'path';
|
||||
import { nanoid } from 'nanoid';
|
||||
import type { SessionService } from '../services/session.service';
|
||||
import type { ConfigService } from '../services/config.service';
|
||||
import type { WorkspaceService } from '../services/workspace.service';
|
||||
@@ -1567,18 +1568,35 @@ export function registerAllIPCHandlers(
|
||||
return { success: false, error: 'Invalid parentId' };
|
||||
}
|
||||
const db = sessionService.getDB();
|
||||
const id = `task_${Date.now()}_${Math.random().toString(36).slice(2, 8)}`;
|
||||
// P4 统一(v0.3.13): ID 生成方式与 task_manager 工具一致(nanoid)
|
||||
const id = `task_${nanoid(12)}`;
|
||||
try {
|
||||
// P4 统一: 计算 order_idx = MAX(同 session+parent 的 order_idx) + 1(与 task_manager 工具一致)
|
||||
// 注意:parent_id IS NULL 时需要单独处理,COALESCE(NULL, NULL) 仍为 NULL
|
||||
const parentId = (req.parentId as string | null) ?? null;
|
||||
let orderIdx = 0;
|
||||
if (parentId === null) {
|
||||
const orderRow = db.prepare(
|
||||
'SELECT COALESCE(MAX(order_idx), -1) AS maxOrder FROM tasks WHERE session_id = ? AND parent_id IS NULL'
|
||||
).get(req.sessionId) as { maxOrder: number } | undefined;
|
||||
orderIdx = (orderRow?.maxOrder ?? -1) + 1;
|
||||
} else {
|
||||
const orderRow = db.prepare(
|
||||
'SELECT COALESCE(MAX(order_idx), -1) AS maxOrder FROM tasks WHERE session_id = ? AND parent_id = ?'
|
||||
).get(req.sessionId, parentId) as { maxOrder: number } | undefined;
|
||||
orderIdx = (orderRow?.maxOrder ?? -1) + 1;
|
||||
}
|
||||
db.prepare(`
|
||||
INSERT INTO tasks (id, session_id, title, description, status, priority, parent_id, created_at, updated_at)
|
||||
VALUES (?, ?, ?, ?, 'pending', ?, ?, ?, ?)
|
||||
INSERT INTO tasks (id, session_id, title, description, status, priority, parent_id, order_idx, created_at, updated_at)
|
||||
VALUES (?, ?, ?, ?, 'pending', ?, ?, ?, ?, ?)
|
||||
`).run(
|
||||
id,
|
||||
req.sessionId,
|
||||
req.title,
|
||||
typeof req.description === 'string' ? req.description : '',
|
||||
(req.priority as string) ?? 'medium',
|
||||
(req.parentId as string | null) ?? null,
|
||||
parentId,
|
||||
orderIdx,
|
||||
Date.now(),
|
||||
Date.now(),
|
||||
);
|
||||
@@ -1588,11 +1606,15 @@ export function registerAllIPCHandlers(
|
||||
}
|
||||
});
|
||||
|
||||
ipcMain.handle('tasks:update', async (_event, id: unknown, updates: unknown) => {
|
||||
ipcMain.handle('tasks:update', async (_event, id: unknown, updates: unknown, sessionId: unknown) => {
|
||||
// M-47 修复: 校验 id 和 updates 结构/枚举
|
||||
if (typeof id !== 'string' || !id) {
|
||||
return { success: false, error: 'Invalid task id' };
|
||||
}
|
||||
// P1 修复(v0.3.13): 补 session_id 越权保护(与 task_manager 工具一致)
|
||||
if (typeof sessionId !== 'string' || !sessionId) {
|
||||
return { success: false, error: 'Invalid sessionId' };
|
||||
}
|
||||
if (!updates || typeof updates !== 'object') {
|
||||
return { success: false, error: 'Invalid updates' };
|
||||
}
|
||||
@@ -1625,22 +1647,28 @@ export function registerAllIPCHandlers(
|
||||
if (fields.length === 0) return { success: true };
|
||||
fields.push('updated_at = ?'); values.push(Date.now());
|
||||
if (u.status === 'completed') { fields.push('completed_at = ?'); values.push(Date.now()); }
|
||||
values.push(id);
|
||||
db.prepare(`UPDATE tasks SET ${fields.join(', ')} WHERE id = ?`).run(...values);
|
||||
values.push(id, sessionId);
|
||||
// P1 修复(v0.3.13): WHERE 补 session_id 校验,防越权修改其他会话任务
|
||||
db.prepare(`UPDATE tasks SET ${fields.join(', ')} WHERE id = ? AND session_id = ?`).run(...values);
|
||||
return { success: true };
|
||||
} catch (error) {
|
||||
return { success: false, error: (error as Error).message };
|
||||
}
|
||||
});
|
||||
|
||||
ipcMain.handle('tasks:delete', async (_event, id: unknown) => {
|
||||
ipcMain.handle('tasks:delete', async (_event, id: unknown, sessionId: unknown) => {
|
||||
// M-48 修复: 校验 id 类型
|
||||
if (typeof id !== 'string' || !id) {
|
||||
return { success: false, error: 'Invalid task id' };
|
||||
}
|
||||
// P1 修复(v0.3.13): 补 session_id 越权保护
|
||||
if (typeof sessionId !== 'string' || !sessionId) {
|
||||
return { success: false, error: 'Invalid sessionId' };
|
||||
}
|
||||
const db = sessionService.getDB();
|
||||
try {
|
||||
db.prepare('DELETE FROM tasks WHERE id = ?').run(id);
|
||||
// P1 修复: WHERE 补 session_id 校验
|
||||
db.prepare('DELETE FROM tasks WHERE id = ? AND session_id = ?').run(id, sessionId);
|
||||
return { success: true };
|
||||
} catch (error) {
|
||||
return { success: false, error: (error as Error).message };
|
||||
|
||||
Reference in New Issue
Block a user