agent-ecosystem/agent-teams-controller/src/internal/kanbanStore.js
iliya 4cf330e8cc feat: integrate agent-teams-controller and enhance task management
- Added agent-teams-controller as a dependency and updated the bundling configuration to exclude it.
- Refactored task management functions to utilize the new taskStore, improving code organization and maintainability.
- Introduced new methods for handling task states, including soft deletion and restoration.
- Enhanced kanban functionality with improved reviewer management and task column updates.
- Updated tests to reflect changes in task creation and approval processes, ensuring robust coverage.
- Improved task ID handling and display logic for better user experience across components.
2026-03-07 16:01:32 +02:00

112 lines
3.3 KiB
JavaScript

const fs = require('fs');
const path = require('path');
function nowIso() {
return new Date().toISOString();
}
function readJson(filePath, fallbackValue) {
try {
return JSON.parse(fs.readFileSync(filePath, 'utf8'));
} catch {
return fallbackValue;
}
}
function writeJson(filePath, value) {
fs.mkdirSync(path.dirname(filePath), { recursive: true });
const tempPath = `${filePath}.${process.pid}.${Date.now()}.tmp`;
fs.writeFileSync(tempPath, JSON.stringify(value, null, 2));
fs.renameSync(tempPath, filePath);
}
function getDefaultState(teamName) {
return {
teamName,
reviewers: [],
tasks: {},
};
}
function sanitizeState(teamName, rawState) {
const state = rawState && typeof rawState === 'object' ? rawState : {};
const tasks = {};
if (state.tasks && typeof state.tasks === 'object') {
for (const [taskId, entry] of Object.entries(state.tasks)) {
if (!entry || typeof entry !== 'object') continue;
if (entry.column !== 'review' && entry.column !== 'approved') continue;
if (typeof entry.movedAt !== 'string') continue;
tasks[String(taskId)] = {
column: entry.column,
movedAt: entry.movedAt,
...(entry.reviewer === null || typeof entry.reviewer === 'string'
? { reviewer: entry.reviewer }
: {}),
...(typeof entry.errorDescription === 'string'
? { errorDescription: entry.errorDescription }
: {}),
};
}
}
return {
teamName,
reviewers: Array.isArray(state.reviewers)
? state.reviewers.filter((entry) => typeof entry === 'string' && entry.trim())
: [],
tasks,
...(state.columnOrder && typeof state.columnOrder === 'object'
? { columnOrder: state.columnOrder }
: {}),
};
}
function readKanbanState(paths, teamName) {
return sanitizeState(teamName, readJson(paths.kanbanPath, getDefaultState(teamName)));
}
function writeKanbanState(paths, teamName, state) {
writeJson(paths.kanbanPath, sanitizeState(teamName, state));
}
function setKanbanColumn(paths, teamName, taskId, column) {
if (column !== 'review' && column !== 'approved') {
throw new Error(`Invalid kanban column: ${String(column)}`);
}
const state = readKanbanState(paths, teamName);
state.tasks[String(taskId)] =
column === 'review'
? { column: 'review', reviewer: null, movedAt: nowIso() }
: { column: 'approved', movedAt: nowIso() };
writeKanbanState(paths, teamName, state);
return state;
}
function clearKanban(paths, teamName, taskId) {
const state = readKanbanState(paths, teamName);
delete state.tasks[String(taskId)];
writeKanbanState(paths, teamName, state);
return state;
}
function updateColumnOrder(paths, teamName, columnId, orderedTaskIds) {
const state = readKanbanState(paths, teamName);
const nextColumnOrder = { ...(state.columnOrder || {}) };
if (Array.isArray(orderedTaskIds) && orderedTaskIds.length > 0) {
nextColumnOrder[columnId] = orderedTaskIds.map((entry) => String(entry));
} else {
delete nextColumnOrder[columnId];
}
state.columnOrder = Object.keys(nextColumnOrder).length > 0 ? nextColumnOrder : undefined;
writeKanbanState(paths, teamName, state);
return state;
}
module.exports = {
clearKanban,
readKanbanState,
setKanbanColumn,
updateColumnOrder,
writeKanbanState,
};