feat: harden boss local v1 runtime

This commit is contained in:
Codex
2026-03-23 13:17:11 +08:00
parent 515ce72d0d
commit 47c29c723a
13 changed files with 1281 additions and 178 deletions

View File

@@ -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,
},
});
});