Some checks failed
ci/woodpecker/push/ci Pipeline failed
Co-authored-by: Jason Woltje <jason@diversecanvas.com> Co-committed-by: Jason Woltje <jason@diversecanvas.com>
78 lines
2.1 KiB
TypeScript
78 lines
2.1 KiB
TypeScript
import { Injectable, Logger } from '@nestjs/common';
|
|
import {
|
|
loadMission,
|
|
getMissionStatus,
|
|
getTaskStatus,
|
|
parseTasksFile,
|
|
type Mission,
|
|
type MissionStatusSummary,
|
|
type MissionTask,
|
|
type TaskDetail,
|
|
} from '@mosaic/coord';
|
|
import { promises as fs } from 'node:fs';
|
|
import path from 'node:path';
|
|
|
|
/**
|
|
* File-based coord operations for agent tool consumption.
|
|
* DB-backed mission CRUD is handled directly by MissionsController via Brain repos.
|
|
*/
|
|
@Injectable()
|
|
export class CoordService {
|
|
private readonly logger = new Logger(CoordService.name);
|
|
|
|
async loadMission(projectPath: string): Promise<Mission | null> {
|
|
try {
|
|
return await loadMission(projectPath);
|
|
} catch (err) {
|
|
this.logger.debug(
|
|
`No coord mission at ${projectPath}: ${err instanceof Error ? err.message : String(err)}`,
|
|
);
|
|
return null;
|
|
}
|
|
}
|
|
|
|
async getMissionStatus(projectPath: string): Promise<MissionStatusSummary | null> {
|
|
const mission = await this.loadMission(projectPath);
|
|
if (!mission) return null;
|
|
|
|
try {
|
|
return await getMissionStatus(mission);
|
|
} catch (err) {
|
|
this.logger.error(
|
|
`Failed to get mission status: ${err instanceof Error ? err.message : String(err)}`,
|
|
);
|
|
return null;
|
|
}
|
|
}
|
|
|
|
async getTaskStatus(projectPath: string, taskId: string): Promise<TaskDetail | null> {
|
|
const mission = await this.loadMission(projectPath);
|
|
if (!mission) return null;
|
|
|
|
try {
|
|
return await getTaskStatus(mission, taskId);
|
|
} catch (err) {
|
|
this.logger.error(
|
|
`Failed to get task status for ${taskId}: ${err instanceof Error ? err.message : String(err)}`,
|
|
);
|
|
return null;
|
|
}
|
|
}
|
|
|
|
async listTasks(projectPath: string): Promise<MissionTask[]> {
|
|
const mission = await this.loadMission(projectPath);
|
|
if (!mission) return [];
|
|
|
|
const tasksFile = path.isAbsolute(mission.tasksFile)
|
|
? mission.tasksFile
|
|
: path.join(mission.projectPath, mission.tasksFile);
|
|
|
|
try {
|
|
const content = await fs.readFile(tasksFile, 'utf8');
|
|
return parseTasksFile(content);
|
|
} catch {
|
|
return [];
|
|
}
|
|
}
|
|
}
|