-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathboulder-state.ts
More file actions
197 lines (176 loc) · 4.9 KB
/
Copy pathboulder-state.ts
File metadata and controls
197 lines (176 loc) · 4.9 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
/**
* Boulder 状态管理
* 对标 oh-my-opencode boulder-state
*
* 管理持久化的 boulder 计划状态:
* - 活跃计划跟踪
* - 会话 ID 收集
* - 任务会话状态
*/
import * as fs from 'fs';
import * as path from 'path';
import * as os from 'os';
import { getCurrentProvider } from './provider-init.js';
const BOULDER_DIR = path.join(getCurrentProvider().getStateDir(), 'boulder');
const BOULDER_STATE_PATH = path.join(BOULDER_DIR, 'state.json');
const LINEAGE_PATH = path.join(BOULDER_DIR, 'lineage.jsonl');
export interface TaskSessionState {
taskId: string;
sessionId: string;
status: 'pending' | 'running' | 'completed' | 'error';
description: string;
agent: string;
createdAt: string;
completedAt?: string;
}
export interface BoulderState {
activePlan: string | null;
planName: string;
startedAt: string;
sessionIds: string[];
sessionOrigins: Record<string, 'direct' | 'appended'>;
taskSessions: Record<string, TaskSessionState>;
totalTasks: number;
completedTasks: number;
finalWaveApproved: boolean;
}
function ensureDir(): void {
if (!fs.existsSync(BOULDER_DIR)) {
fs.mkdirSync(BOULDER_DIR, { recursive: true });
}
}
function createDefaultState(planName?: string): BoulderState {
return {
activePlan: planName || null,
planName: planName || 'unnamed',
startedAt: new Date().toISOString(),
sessionIds: [],
sessionOrigins: {},
taskSessions: {},
totalTasks: 0,
completedTasks: 0,
finalWaveApproved: false,
};
}
/** 读取 boulder 状态 */
function readBoulderState(): BoulderState {
ensureDir();
try {
if (fs.existsSync(BOULDER_STATE_PATH)) {
return JSON.parse(fs.readFileSync(BOULDER_STATE_PATH, 'utf-8')) as BoulderState;
}
} catch {
// return default
}
return createDefaultState();
}
/** 写入 boulder 状态 */
function writeBoulderState(state: BoulderState): void {
ensureDir();
fs.writeFileSync(BOULDER_STATE_PATH, JSON.stringify(state, null, 2));
}
/** 开始新的 boulder 计划 */
function startPlan(planName: string): BoulderState {
const state = createDefaultState(planName);
writeBoulderState(state);
return state;
}
/** 添加会话到 boulder */
function appendSession(sessionId: string, origin: 'direct' | 'appended' = 'direct'): BoulderState {
const state = readBoulderState();
if (!state.sessionIds.includes(sessionId)) {
state.sessionIds.push(sessionId);
state.sessionOrigins[sessionId] = origin;
writeBoulderState(state);
}
return state;
}
/** 添加/更新任务会话 */
function upsertTaskSession(taskState: TaskSessionState): BoulderState {
const state = readBoulderState();
const prevStatus = state.taskSessions[taskState.taskId]?.status;
state.taskSessions[taskState.taskId] = taskState;
// 更新计数
if (prevStatus !== 'completed' && taskState.status === 'completed') {
state.completedTasks += 1;
}
if (!prevStatus) {
state.totalTasks += 1;
}
writeBoulderState(state);
return state;
}
/** 检查是否所有任务已完成 */
function isPlanComplete(): boolean {
const state = readBoulderState();
return state.totalTasks > 0 && state.completedTasks >= state.totalTasks;
}
/** 获取计划进度 */
function getPlanProgress(): { completed: number; total: number; percent: number } {
const state = readBoulderState();
const percent = state.totalTasks > 0
? Math.round((state.completedTasks / state.totalTasks) * 100)
: 0;
return { completed: state.completedTasks, total: state.totalTasks, percent };
}
/** 设置最终波次审批 */
function approveFinalWave(): BoulderState {
const state = readBoulderState();
state.finalWaveApproved = true;
writeBoulderState(state);
return state;
}
/** 追加会话谱系条目 */
function appendLineage(entry: {
sessionId: string;
parentSessionId?: string;
planName: string;
event: 'created' | 'completed' | 'error' | 'appended';
timestamp?: string;
}): void {
ensureDir();
const line = JSON.stringify({
...entry,
timestamp: entry.timestamp || new Date().toISOString(),
});
fs.appendFileSync(LINEAGE_PATH, line + '\n');
}
/** 读取会话谱系 */
function readLineage(): Array<Record<string, unknown>> {
ensureDir();
try {
if (fs.existsSync(LINEAGE_PATH)) {
return fs.readFileSync(LINEAGE_PATH, 'utf-8')
.trim()
.split('\n')
.filter(Boolean)
.map(line => JSON.parse(line));
}
} catch {
// ignore
}
return [];
}
/** 清除 boulder 状态 */
function clearBoulderState(): void {
try {
if (fs.existsSync(BOULDER_STATE_PATH)) fs.unlinkSync(BOULDER_STATE_PATH);
if (fs.existsSync(LINEAGE_PATH)) fs.unlinkSync(LINEAGE_PATH);
} catch {
// ignore
}
}
export const BoulderStateManager = {
readBoulderState,
writeBoulderState,
startPlan,
appendSession,
upsertTaskSession,
isPlanComplete,
getPlanProgress,
approveFinalWave,
appendLineage,
readLineage,
clearBoulderState,
BOULDER_DIR,
};