fix(services): guard getters, use counter for memory, deduplicate listEntities
This commit is contained in:
parent
908a89d772
commit
a0af702344
@ -1,6 +1,8 @@
|
|||||||
|
import { loadConfig } from '../../core/config.js';
|
||||||
import { suggestDelegation, autoDelegate } from '../../core/services/delegateService.js';
|
import { suggestDelegation, autoDelegate } from '../../core/services/delegateService.js';
|
||||||
|
|
||||||
export async function delegate(cwd: string, options: { auto?: boolean } = {}): Promise<void> {
|
export async function delegate(cwd: string, options: { auto?: boolean } = {}): Promise<void> {
|
||||||
|
const config = loadConfig(cwd);
|
||||||
const suggestion = suggestDelegation(cwd);
|
const suggestion = suggestDelegation(cwd);
|
||||||
if (!suggestion) {
|
if (!suggestion) {
|
||||||
console.log('No open tasks to delegate.');
|
console.log('No open tasks to delegate.');
|
||||||
@ -12,7 +14,7 @@ export async function delegate(cwd: string, options: { auto?: boolean } = {}): P
|
|||||||
console.log(` Role: ${suggestion.role}`);
|
console.log(` Role: ${suggestion.role}`);
|
||||||
console.log(` Preferred agent: ${suggestion.preferredAgent}`);
|
console.log(` Preferred agent: ${suggestion.preferredAgent}`);
|
||||||
|
|
||||||
if (options.auto) {
|
if (config.delegationMode === 'auto' || options.auto) {
|
||||||
autoDelegate(cwd);
|
autoDelegate(cwd);
|
||||||
console.log('Handoff created automatically.');
|
console.log('Handoff created automatically.');
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@ -46,6 +46,7 @@ export function listDecisions(cwd: string): ReturnType<Index['list']> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function getDecision(cwd: string, id: string): { decision: Decision; body: string; filePath: string } {
|
export function getDecision(cwd: string, id: string): { decision: Decision; body: string; filePath: string } {
|
||||||
|
if (!id) throw new Error('Decision ID is required');
|
||||||
const filePath = join(getEntityDir(cwd, 'decisions'), `${id}.md`);
|
const filePath = join(getEntityDir(cwd, 'decisions'), `${id}.md`);
|
||||||
const { frontmatter, body } = readEntity(filePath);
|
const { frontmatter, body } = readEntity(filePath);
|
||||||
return { decision: DecisionSchema.parse(frontmatter), body, filePath };
|
return { decision: DecisionSchema.parse(frontmatter), body, filePath };
|
||||||
|
|||||||
@ -48,6 +48,7 @@ export function listHandoffs(cwd: string): ReturnType<Index['list']> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function getHandoff(cwd: string, id: string): { handoff: Handoff; body: string; filePath: string } {
|
export function getHandoff(cwd: string, id: string): { handoff: Handoff; body: string; filePath: string } {
|
||||||
|
if (!id) throw new Error('Handoff ID is required');
|
||||||
const filePath = join(getEntityDir(cwd, 'handoffs'), `${id}.md`);
|
const filePath = join(getEntityDir(cwd, 'handoffs'), `${id}.md`);
|
||||||
const { frontmatter, body } = readEntity(filePath);
|
const { frontmatter, body } = readEntity(filePath);
|
||||||
return { handoff: HandoffSchema.parse(frontmatter), body, filePath };
|
return { handoff: HandoffSchema.parse(frontmatter), body, filePath };
|
||||||
|
|||||||
@ -1,12 +1,13 @@
|
|||||||
import { join } from 'path';
|
import { join } from 'path';
|
||||||
import { getEntityDir } from '../paths.js';
|
import { getEntityDir } from '../paths.js';
|
||||||
|
import { getNextId } from '../counter.js';
|
||||||
import { writeEntity } from '../files.js';
|
import { writeEntity } from '../files.js';
|
||||||
import { MemorySchema, type Memory } from '../schema.js';
|
import { MemorySchema, type Memory } from '../schema.js';
|
||||||
import { Index } from '../index.js';
|
import { Index } from '../index.js';
|
||||||
|
|
||||||
export function addMemory(cwd: string, options: Partial<Memory> = {}): Memory {
|
export function addMemory(cwd: string, options: Partial<Memory> = {}): Memory {
|
||||||
const now = new Date().toISOString();
|
const now = new Date().toISOString();
|
||||||
const id = `MEM-${Date.now()}`;
|
const id = getNextId(cwd, 'memory');
|
||||||
const memory: Memory = MemorySchema.parse({
|
const memory: Memory = MemorySchema.parse({
|
||||||
id,
|
id,
|
||||||
title: options.title ?? 'Memory',
|
title: options.title ?? 'Memory',
|
||||||
|
|||||||
@ -37,6 +37,7 @@ export function listTasks(cwd: string, filters?: { status?: string; role?: strin
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function getTask(cwd: string, id: string): { task: Task; body: string; filePath: string } {
|
export function getTask(cwd: string, id: string): { task: Task; body: string; filePath: string } {
|
||||||
|
if (!id) throw new Error('Task ID is required');
|
||||||
const filePath = join(getEntityDir(cwd, 'tasks'), `${id}.md`);
|
const filePath = join(getEntityDir(cwd, 'tasks'), `${id}.md`);
|
||||||
const { frontmatter, body } = readEntity(filePath);
|
const { frontmatter, body } = readEntity(filePath);
|
||||||
return { task: TaskSchema.parse(frontmatter), body, filePath };
|
return { task: TaskSchema.parse(frontmatter), body, filePath };
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
import { readFileSync, writeFileSync, mkdirSync, existsSync, readdirSync } from 'fs';
|
import { writeFileSync, mkdirSync, existsSync } from 'fs';
|
||||||
import { join } from 'path';
|
import { join } from 'path';
|
||||||
import { getEntityDir, getStatusPath } from './paths.js';
|
import { getEntityDir, getStatusPath } from './paths.js';
|
||||||
import { readEntity, writeEntity } from './files.js';
|
import { readEntity, writeEntity, listEntities } from './files.js';
|
||||||
import { StatusSchema } from './schema.js';
|
import { StatusSchema } from './schema.js';
|
||||||
|
|
||||||
export function generateStatus(cwd: string) {
|
export function generateStatus(cwd: string) {
|
||||||
@ -13,7 +13,7 @@ export function generateStatus(cwd: string) {
|
|||||||
const blockedTasks: string[] = [];
|
const blockedTasks: string[] = [];
|
||||||
|
|
||||||
if (existsSync(taskDir)) {
|
if (existsSync(taskDir)) {
|
||||||
for (const file of listMdFiles(taskDir)) {
|
for (const file of listEntities(taskDir)) {
|
||||||
const { frontmatter } = readEntity(file);
|
const { frontmatter } = readEntity(file);
|
||||||
if (frontmatter.status === 'open' || frontmatter.status === 'in_progress') {
|
if (frontmatter.status === 'open' || frontmatter.status === 'in_progress') {
|
||||||
activeTasks.push(String(frontmatter.id));
|
activeTasks.push(String(frontmatter.id));
|
||||||
@ -42,15 +42,8 @@ export function generateStatus(cwd: string) {
|
|||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
function listMdFiles(dir: string): string[] {
|
|
||||||
if (!existsSync(dir)) return [];
|
|
||||||
return readdirSync(dir)
|
|
||||||
.filter((f) => f.endsWith('.md'))
|
|
||||||
.map((f) => join(dir, f));
|
|
||||||
}
|
|
||||||
|
|
||||||
function recentIds(dir: string, limit: number): string[] {
|
function recentIds(dir: string, limit: number): string[] {
|
||||||
return listMdFiles(dir)
|
return listEntities(dir)
|
||||||
.map((f) => ({ file: f, ...readEntity(f) }))
|
.map((f) => ({ file: f, ...readEntity(f) }))
|
||||||
.sort((a, b) => String(b.frontmatter.createdAt).localeCompare(String(a.frontmatter.createdAt)))
|
.sort((a, b) => String(b.frontmatter.createdAt).localeCompare(String(a.frontmatter.createdAt)))
|
||||||
.slice(0, limit)
|
.slice(0, limit)
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user