feat: harden boss local v1 runtime
This commit is contained in:
@@ -15,7 +15,9 @@ import { chooseAssignmentCandidates } from "./scheduler.js";
|
||||
import { FileStore } from "./store.js";
|
||||
import { createId, now } from "./utils.js";
|
||||
|
||||
const DATA_FILE = resolve(process.cwd(), ".boss-data", "store.json");
|
||||
const DATA_FILE = process.env.BOSS_DATA_FILE
|
||||
? resolve(process.cwd(), process.env.BOSS_DATA_FILE)
|
||||
: resolve(process.cwd(), ".boss-data", "store.json");
|
||||
|
||||
function isActiveTask(task: Task): boolean {
|
||||
return !["completed", "failed", "cancelled"].includes(task.status);
|
||||
@@ -34,6 +36,32 @@ export class BossEngine {
|
||||
return this.getState();
|
||||
}
|
||||
|
||||
resetDemo(preserveWorkers = true): AppState {
|
||||
this.commit((state) => {
|
||||
state.sessions = [];
|
||||
state.messages = [];
|
||||
state.tasks = [];
|
||||
state.approvals = [];
|
||||
state.events = [];
|
||||
|
||||
if (!preserveWorkers) {
|
||||
state.workers = [];
|
||||
return;
|
||||
}
|
||||
|
||||
const timestamp = now();
|
||||
state.workers = state.workers.map((worker) => ({
|
||||
...worker,
|
||||
currentTaskId: null,
|
||||
load: 0,
|
||||
status: worker.status === "offline" ? "offline" : "idle",
|
||||
updatedAt: timestamp,
|
||||
}));
|
||||
});
|
||||
|
||||
return this.getState();
|
||||
}
|
||||
|
||||
createSession(title?: string): SessionDetails {
|
||||
const timestamp = now();
|
||||
const session: Session = {
|
||||
@@ -134,6 +162,29 @@ export class BossEngine {
|
||||
return this.getSession(sessionId);
|
||||
}
|
||||
|
||||
restoreSession(sessionId: string): SessionDetails {
|
||||
this.commit((state, addEvent) => {
|
||||
const session = state.sessions.find((candidate) => candidate.id === sessionId);
|
||||
if (!session) {
|
||||
throw new Error(`Session not found: ${sessionId}`);
|
||||
}
|
||||
|
||||
const timestamp = now();
|
||||
session.status = "active";
|
||||
session.updatedAt = timestamp;
|
||||
|
||||
addEvent({
|
||||
sessionId,
|
||||
taskId: null,
|
||||
source: "system",
|
||||
type: "session.restored",
|
||||
payload: { sessionId },
|
||||
});
|
||||
});
|
||||
|
||||
return this.getSession(sessionId);
|
||||
}
|
||||
|
||||
addMessage(sessionId: string, content: string, channel = "web"): SessionDetails {
|
||||
const session = this.getSession(sessionId).session;
|
||||
if (session.status === "archived") {
|
||||
@@ -415,6 +466,10 @@ export class BossEngine {
|
||||
if (task.status === "assigned") {
|
||||
task.status = "running";
|
||||
}
|
||||
worker.status = "busy";
|
||||
worker.currentTaskId = task.id;
|
||||
worker.updatedAt = task.updatedAt;
|
||||
worker.lastSeenAt = task.updatedAt;
|
||||
|
||||
addEvent({
|
||||
sessionId: task.sessionId,
|
||||
@@ -649,6 +704,7 @@ export class BossEngine {
|
||||
const timestamp = now();
|
||||
|
||||
this.commit((state, addEvent) => {
|
||||
const pausedTaskIds: string[] = [];
|
||||
const mutableSession = state.sessions.find((candidate) => candidate.id === session.id);
|
||||
if (!mutableSession) {
|
||||
throw new Error(`Session not found: ${session.id}`);
|
||||
@@ -676,6 +732,7 @@ export class BossEngine {
|
||||
reason: "replan",
|
||||
},
|
||||
});
|
||||
pausedTaskIds.push(task.id);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -717,6 +774,7 @@ export class BossEngine {
|
||||
payload: {
|
||||
summary: result.summary,
|
||||
taskIds: tasks.map((task) => task.id),
|
||||
pausedTaskIds,
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user