session-weaver 1.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +227 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +401 -0
- package/dist/index.js.map +1 -0
- package/dist/managers/context.d.ts +15 -0
- package/dist/managers/context.d.ts.map +1 -0
- package/dist/managers/context.js +209 -0
- package/dist/managers/context.js.map +1 -0
- package/dist/managers/delete.d.ts +12 -0
- package/dist/managers/delete.d.ts.map +1 -0
- package/dist/managers/delete.js +135 -0
- package/dist/managers/delete.js.map +1 -0
- package/dist/managers/handoff.d.ts +32 -0
- package/dist/managers/handoff.d.ts.map +1 -0
- package/dist/managers/handoff.js +239 -0
- package/dist/managers/handoff.js.map +1 -0
- package/dist/managers/module.d.ts +12 -0
- package/dist/managers/module.d.ts.map +1 -0
- package/dist/managers/module.js +88 -0
- package/dist/managers/module.js.map +1 -0
- package/dist/managers/pitfall.d.ts +12 -0
- package/dist/managers/pitfall.d.ts.map +1 -0
- package/dist/managers/pitfall.js +70 -0
- package/dist/managers/pitfall.js.map +1 -0
- package/dist/managers/session.d.ts +16 -0
- package/dist/managers/session.d.ts.map +1 -0
- package/dist/managers/session.js +248 -0
- package/dist/managers/session.js.map +1 -0
- package/dist/managers/storage.d.ts +46 -0
- package/dist/managers/storage.d.ts.map +1 -0
- package/dist/managers/storage.js +166 -0
- package/dist/managers/storage.js.map +1 -0
- package/dist/types.d.ts +238 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +6 -0
- package/dist/types.js.map +1 -0
- package/dist/utils/format.d.ts +39 -0
- package/dist/utils/format.d.ts.map +1 -0
- package/dist/utils/format.js +442 -0
- package/dist/utils/format.js.map +1 -0
- package/package.json +54 -0
|
@@ -0,0 +1,248 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Session Manager - 会话管理
|
|
3
|
+
*/
|
|
4
|
+
import { nanoid } from 'nanoid';
|
|
5
|
+
import { StorageManager } from './storage.js';
|
|
6
|
+
import { formatSessionToMarkdown } from '../utils/format.js';
|
|
7
|
+
const VERSION = '2.0.0';
|
|
8
|
+
export class SessionManager {
|
|
9
|
+
storage;
|
|
10
|
+
constructor(storage) {
|
|
11
|
+
this.storage = storage || new StorageManager();
|
|
12
|
+
}
|
|
13
|
+
async saveSession(input) {
|
|
14
|
+
const sessionId = nanoid(12);
|
|
15
|
+
const createdAt = new Date().toISOString();
|
|
16
|
+
// 确定关联的模块
|
|
17
|
+
let moduleName = input.module;
|
|
18
|
+
if (!moduleName) {
|
|
19
|
+
// 自动使用当前模块
|
|
20
|
+
moduleName = await this.storage.getCurrentModule(input.project) || undefined;
|
|
21
|
+
}
|
|
22
|
+
// 处理传入的 pitfalls,保存为独立的 Pitfall 记录
|
|
23
|
+
const pitfallRefs = [];
|
|
24
|
+
if (input.pitfalls && input.pitfalls.length > 0) {
|
|
25
|
+
for (const pitfallInput of input.pitfalls) {
|
|
26
|
+
const pitfallId = nanoid(12);
|
|
27
|
+
const pitfall = {
|
|
28
|
+
pitfallId,
|
|
29
|
+
project: input.project,
|
|
30
|
+
module: moduleName, // 关联到模块
|
|
31
|
+
problem: pitfallInput.problem,
|
|
32
|
+
solution: pitfallInput.solution,
|
|
33
|
+
tags: pitfallInput.tags || [],
|
|
34
|
+
sessionId,
|
|
35
|
+
createdAt
|
|
36
|
+
};
|
|
37
|
+
await this.storage.savePitfall(pitfall);
|
|
38
|
+
pitfallRefs.push({ pitfallId, problem: pitfallInput.problem });
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
// 根据待办事项状态决定会话状态
|
|
42
|
+
const todos = input.todos || [];
|
|
43
|
+
const pendingTodos = todos.filter(t => !t.done);
|
|
44
|
+
let status = 'active';
|
|
45
|
+
if (pendingTodos.length === 0 && todos.length > 0) {
|
|
46
|
+
status = 'completed';
|
|
47
|
+
}
|
|
48
|
+
const session = {
|
|
49
|
+
sessionId,
|
|
50
|
+
project: input.project,
|
|
51
|
+
module: moduleName,
|
|
52
|
+
createdAt,
|
|
53
|
+
summary: input.summary,
|
|
54
|
+
techStack: input.techStack || [],
|
|
55
|
+
codeState: input.codeState || {
|
|
56
|
+
modifiedFiles: [],
|
|
57
|
+
currentBranch: '',
|
|
58
|
+
uncommittedChanges: ''
|
|
59
|
+
},
|
|
60
|
+
decisions: input.decisions || [],
|
|
61
|
+
pitfalls: pitfallRefs,
|
|
62
|
+
todos: todos,
|
|
63
|
+
status,
|
|
64
|
+
metadata: {
|
|
65
|
+
aiTool: input.aiTool || 'unknown',
|
|
66
|
+
version: VERSION
|
|
67
|
+
}
|
|
68
|
+
};
|
|
69
|
+
await this.storage.saveSession(session);
|
|
70
|
+
// 自动更新关联模块的 summary 和 updatedAt
|
|
71
|
+
if (moduleName && input.updateModule !== false) {
|
|
72
|
+
const module = await this.storage.getModule(input.project, moduleName);
|
|
73
|
+
if (module) {
|
|
74
|
+
module.summary = input.summary;
|
|
75
|
+
module.updatedAt = createdAt;
|
|
76
|
+
await this.storage.saveModule(input.project, module);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
return {
|
|
80
|
+
sessionId,
|
|
81
|
+
module: moduleName,
|
|
82
|
+
savedAt: createdAt,
|
|
83
|
+
path: this.storage.getBaseDir()
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
async loadSession(input) {
|
|
87
|
+
let session = null;
|
|
88
|
+
if (input.sessionId) {
|
|
89
|
+
// 扫描所有项目查找 session(因为不知道项目名)
|
|
90
|
+
const projects = await this.storage.listProjects();
|
|
91
|
+
for (const project of projects) {
|
|
92
|
+
session = await this.storage.loadSession(project, input.sessionId);
|
|
93
|
+
if (session)
|
|
94
|
+
break;
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
else if (input.project) {
|
|
98
|
+
// 加载项目的最新 session
|
|
99
|
+
session = await this.storage.loadLatestSession(input.project);
|
|
100
|
+
}
|
|
101
|
+
if (!session) {
|
|
102
|
+
return null;
|
|
103
|
+
}
|
|
104
|
+
// 加载关联的模块数据
|
|
105
|
+
let moduleData;
|
|
106
|
+
if (session.module) {
|
|
107
|
+
moduleData = await this.storage.getModule(session.project, session.module) || undefined;
|
|
108
|
+
}
|
|
109
|
+
// 加载关联的 pitfall 详情
|
|
110
|
+
const pitfalls = await Promise.all(session.pitfalls.map(async (ref) => {
|
|
111
|
+
// 从项目中查找 pitfall
|
|
112
|
+
const projectFile = await this.storage.loadProjectFile(session.project);
|
|
113
|
+
return projectFile?.pitfalls.find(p => p.pitfallId === ref.pitfallId) || null;
|
|
114
|
+
}));
|
|
115
|
+
const validPitfalls = pitfalls.filter((p) => p !== null);
|
|
116
|
+
const markdownPreview = formatSessionToMarkdown(session, validPitfalls, moduleData);
|
|
117
|
+
return {
|
|
118
|
+
session,
|
|
119
|
+
module: moduleData || undefined,
|
|
120
|
+
markdownPreview
|
|
121
|
+
};
|
|
122
|
+
}
|
|
123
|
+
async listSessions(input) {
|
|
124
|
+
if (!input.project) {
|
|
125
|
+
// 列出所有项目的 sessions
|
|
126
|
+
const projects = await this.storage.listProjects();
|
|
127
|
+
let allSessions = [];
|
|
128
|
+
for (const project of projects) {
|
|
129
|
+
const sessions = await this.storage.listSessions(project, {
|
|
130
|
+
module: input.module,
|
|
131
|
+
limit: input.limit,
|
|
132
|
+
includeArchived: input.includeArchived
|
|
133
|
+
});
|
|
134
|
+
allSessions.push(...sessions);
|
|
135
|
+
}
|
|
136
|
+
// 按时间倒序排序
|
|
137
|
+
allSessions.sort((a, b) => new Date(b.createdAt).getTime() - new Date(a.createdAt).getTime());
|
|
138
|
+
const limit = input.limit || 20;
|
|
139
|
+
allSessions = allSessions.slice(0, limit);
|
|
140
|
+
const summaries = allSessions.map(s => ({
|
|
141
|
+
sessionId: s.sessionId,
|
|
142
|
+
project: s.project,
|
|
143
|
+
module: s.module,
|
|
144
|
+
summary: s.summary,
|
|
145
|
+
createdAt: s.createdAt,
|
|
146
|
+
status: s.status
|
|
147
|
+
}));
|
|
148
|
+
return {
|
|
149
|
+
sessions: summaries,
|
|
150
|
+
total: summaries.length
|
|
151
|
+
};
|
|
152
|
+
}
|
|
153
|
+
// 列出指定项目的 sessions
|
|
154
|
+
const sessions = await this.storage.listSessions(input.project, {
|
|
155
|
+
module: input.module,
|
|
156
|
+
limit: input.limit,
|
|
157
|
+
includeArchived: input.includeArchived
|
|
158
|
+
});
|
|
159
|
+
const summaries = sessions.map(s => ({
|
|
160
|
+
sessionId: s.sessionId,
|
|
161
|
+
project: s.project,
|
|
162
|
+
module: s.module,
|
|
163
|
+
summary: s.summary,
|
|
164
|
+
createdAt: s.createdAt,
|
|
165
|
+
status: s.status
|
|
166
|
+
}));
|
|
167
|
+
return {
|
|
168
|
+
sessions: summaries,
|
|
169
|
+
total: summaries.length
|
|
170
|
+
};
|
|
171
|
+
}
|
|
172
|
+
async deleteSession(input) {
|
|
173
|
+
// 查找 session 所属项目
|
|
174
|
+
let projectName = null;
|
|
175
|
+
const projects = await this.storage.listProjects();
|
|
176
|
+
for (const project of projects) {
|
|
177
|
+
const session = await this.storage.loadSession(project, input.sessionId);
|
|
178
|
+
if (session) {
|
|
179
|
+
projectName = project;
|
|
180
|
+
break;
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
if (!projectName) {
|
|
184
|
+
return {
|
|
185
|
+
success: false,
|
|
186
|
+
message: `会话 ${input.sessionId} 不存在`
|
|
187
|
+
};
|
|
188
|
+
}
|
|
189
|
+
const success = await this.storage.deleteSession(projectName, input.sessionId);
|
|
190
|
+
return {
|
|
191
|
+
success,
|
|
192
|
+
message: success
|
|
193
|
+
? `会话 ${input.sessionId} 已删除`
|
|
194
|
+
: `删除会话 ${input.sessionId} 失败`
|
|
195
|
+
};
|
|
196
|
+
}
|
|
197
|
+
async archiveSession(input) {
|
|
198
|
+
// 查找 session 所属项目
|
|
199
|
+
let projectName = null;
|
|
200
|
+
const projects = await this.storage.listProjects();
|
|
201
|
+
for (const project of projects) {
|
|
202
|
+
const session = await this.storage.loadSession(project, input.sessionId);
|
|
203
|
+
if (session) {
|
|
204
|
+
projectName = project;
|
|
205
|
+
break;
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
if (!projectName) {
|
|
209
|
+
return {
|
|
210
|
+
success: false,
|
|
211
|
+
message: `会话 ${input.sessionId} 不存在`
|
|
212
|
+
};
|
|
213
|
+
}
|
|
214
|
+
const success = await this.storage.archiveSession(projectName, input.sessionId);
|
|
215
|
+
return {
|
|
216
|
+
success,
|
|
217
|
+
message: success
|
|
218
|
+
? `会话 ${input.sessionId} 已归档`
|
|
219
|
+
: `会话 ${input.sessionId} 不存在`
|
|
220
|
+
};
|
|
221
|
+
}
|
|
222
|
+
async unarchiveSession(input) {
|
|
223
|
+
// 查找 session 所属项目
|
|
224
|
+
let projectName = null;
|
|
225
|
+
const projects = await this.storage.listProjects();
|
|
226
|
+
for (const project of projects) {
|
|
227
|
+
const session = await this.storage.loadSession(project, input.sessionId);
|
|
228
|
+
if (session) {
|
|
229
|
+
projectName = project;
|
|
230
|
+
break;
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
if (!projectName) {
|
|
234
|
+
return {
|
|
235
|
+
success: false,
|
|
236
|
+
message: `会话 ${input.sessionId} 不存在`
|
|
237
|
+
};
|
|
238
|
+
}
|
|
239
|
+
const success = await this.storage.unarchiveSession(projectName, input.sessionId);
|
|
240
|
+
return {
|
|
241
|
+
success,
|
|
242
|
+
message: success
|
|
243
|
+
? `会话 ${input.sessionId} 已取消归档`
|
|
244
|
+
: `会话 ${input.sessionId} 不存在`
|
|
245
|
+
};
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
//# sourceMappingURL=session.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"session.js","sourceRoot":"","sources":["../../src/managers/session.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAoBhC,OAAO,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAC9C,OAAO,EAAE,uBAAuB,EAAE,MAAM,oBAAoB,CAAC;AAE7D,MAAM,OAAO,GAAG,OAAO,CAAC;AAExB,MAAM,OAAO,cAAc;IACjB,OAAO,CAAiB;IAEhC,YAAY,OAAwB;QAClC,IAAI,CAAC,OAAO,GAAG,OAAO,IAAI,IAAI,cAAc,EAAE,CAAC;IACjD,CAAC;IAED,KAAK,CAAC,WAAW,CAAC,KAAuB;QACvC,MAAM,SAAS,GAAG,MAAM,CAAC,EAAE,CAAC,CAAC;QAC7B,MAAM,SAAS,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;QAE3C,UAAU;QACV,IAAI,UAAU,GAAG,KAAK,CAAC,MAAM,CAAC;QAC9B,IAAI,CAAC,UAAU,EAAE,CAAC;YAChB,WAAW;YACX,UAAU,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC,gBAAgB,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,SAAS,CAAC;QAC/E,CAAC;QAED,mCAAmC;QACnC,MAAM,WAAW,GAA6C,EAAE,CAAC;QACjE,IAAI,KAAK,CAAC,QAAQ,IAAI,KAAK,CAAC,QAAQ,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAChD,KAAK,MAAM,YAAY,IAAI,KAAK,CAAC,QAAQ,EAAE,CAAC;gBAC1C,MAAM,SAAS,GAAG,MAAM,CAAC,EAAE,CAAC,CAAC;gBAC7B,MAAM,OAAO,GAAY;oBACvB,SAAS;oBACT,OAAO,EAAE,KAAK,CAAC,OAAO;oBACtB,MAAM,EAAE,UAAU,EAAG,QAAQ;oBAC7B,OAAO,EAAE,YAAY,CAAC,OAAO;oBAC7B,QAAQ,EAAE,YAAY,CAAC,QAAQ;oBAC/B,IAAI,EAAE,YAAY,CAAC,IAAI,IAAI,EAAE;oBAC7B,SAAS;oBACT,SAAS;iBACV,CAAC;gBACF,MAAM,IAAI,CAAC,OAAO,CAAC,WAAW,CAAC,OAAO,CAAC,CAAC;gBACxC,WAAW,CAAC,IAAI,CAAC,EAAE,SAAS,EAAE,OAAO,EAAE,YAAY,CAAC,OAAO,EAAE,CAAC,CAAC;YACjE,CAAC;QACH,CAAC;QAED,iBAAiB;QACjB,MAAM,KAAK,GAAG,KAAK,CAAC,KAAK,IAAI,EAAE,CAAC;QAChC,MAAM,YAAY,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;QAChD,IAAI,MAAM,GAAsB,QAAQ,CAAC;QACzC,IAAI,YAAY,CAAC,MAAM,KAAK,CAAC,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAClD,MAAM,GAAG,WAAW,CAAC;QACvB,CAAC;QAED,MAAM,OAAO,GAAY;YACvB,SAAS;YACT,OAAO,EAAE,KAAK,CAAC,OAAO;YACtB,MAAM,EAAE,UAAU;YAClB,SAAS;YACT,OAAO,EAAE,KAAK,CAAC,OAAO;YACtB,SAAS,EAAE,KAAK,CAAC,SAAS,IAAI,EAAE;YAChC,SAAS,EAAE,KAAK,CAAC,SAAS,IAAI;gBAC5B,aAAa,EAAE,EAAE;gBACjB,aAAa,EAAE,EAAE;gBACjB,kBAAkB,EAAE,EAAE;aACvB;YACD,SAAS,EAAE,KAAK,CAAC,SAAS,IAAI,EAAE;YAChC,QAAQ,EAAE,WAAW;YACrB,KAAK,EAAE,KAAK;YACZ,MAAM;YACN,QAAQ,EAAE;gBACR,MAAM,EAAE,KAAK,CAAC,MAAM,IAAI,SAAS;gBACjC,OAAO,EAAE,OAAO;aACjB;SACF,CAAC;QAEF,MAAM,IAAI,CAAC,OAAO,CAAC,WAAW,CAAC,OAAO,CAAC,CAAC;QAExC,gCAAgC;QAChC,IAAI,UAAU,IAAI,KAAK,CAAC,YAAY,KAAK,KAAK,EAAE,CAAC;YAC/C,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC,SAAS,CAAC,KAAK,CAAC,OAAO,EAAE,UAAU,CAAC,CAAC;YACvE,IAAI,MAAM,EAAE,CAAC;gBACX,MAAM,CAAC,OAAO,GAAG,KAAK,CAAC,OAAO,CAAC;gBAC/B,MAAM,CAAC,SAAS,GAAG,SAAS,CAAC;gBAC7B,MAAM,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,KAAK,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;YACvD,CAAC;QACH,CAAC;QAED,OAAO;YACL,SAAS;YACT,MAAM,EAAE,UAAU;YAClB,OAAO,EAAE,SAAS;YAClB,IAAI,EAAE,IAAI,CAAC,OAAO,CAAC,UAAU,EAAE;SAChC,CAAC;IACJ,CAAC;IAED,KAAK,CAAC,WAAW,CAAC,KAAuB;QACvC,IAAI,OAAO,GAAmB,IAAI,CAAC;QAEnC,IAAI,KAAK,CAAC,SAAS,EAAE,CAAC;YACpB,6BAA6B;YAC7B,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC,YAAY,EAAE,CAAC;YACnD,KAAK,MAAM,OAAO,IAAI,QAAQ,EAAE,CAAC;gBAC/B,OAAO,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC,WAAW,CAAC,OAAO,EAAE,KAAK,CAAC,SAAS,CAAC,CAAC;gBACnE,IAAI,OAAO;oBAAE,MAAM;YACrB,CAAC;QACH,CAAC;aAAM,IAAI,KAAK,CAAC,OAAO,EAAE,CAAC;YACzB,kBAAkB;YAClB,OAAO,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC,iBAAiB,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;QAChE,CAAC;QAED,IAAI,CAAC,OAAO,EAAE,CAAC;YACb,OAAO,IAAI,CAAC;QACd,CAAC;QAED,YAAY;QACZ,IAAI,UAA8B,CAAC;QACnC,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC;YACnB,UAAU,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC,SAAS,CAAC,OAAO,CAAC,OAAO,EAAE,OAAO,CAAC,MAAM,CAAC,IAAI,SAAS,CAAC;QAC1F,CAAC;QAED,mBAAmB;QACnB,MAAM,QAAQ,GAAG,MAAM,OAAO,CAAC,GAAG,CAChC,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAC,KAAK,EAAE,GAAG,EAAE,EAAE;YACjC,iBAAiB;YACjB,MAAM,WAAW,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC,eAAe,CAAC,OAAQ,CAAC,OAAO,CAAC,CAAC;YACzE,OAAO,WAAW,EAAE,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,SAAS,KAAK,GAAG,CAAC,SAAS,CAAC,IAAI,IAAI,CAAC;QAChF,CAAC,CAAC,CACH,CAAC;QACF,MAAM,aAAa,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,EAAgB,EAAE,CAAC,CAAC,KAAK,IAAI,CAAC,CAAC;QAEvE,MAAM,eAAe,GAAG,uBAAuB,CAAC,OAAO,EAAE,aAAa,EAAE,UAAU,CAAC,CAAC;QAEpF,OAAO;YACL,OAAO;YACP,MAAM,EAAE,UAAU,IAAI,SAAS;YAC/B,eAAe;SAChB,CAAC;IACJ,CAAC;IAED,KAAK,CAAC,YAAY,CAAC,KAAwB;QACzC,IAAI,CAAC,KAAK,CAAC,OAAO,EAAE,CAAC;YACnB,mBAAmB;YACnB,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC,YAAY,EAAE,CAAC;YACnD,IAAI,WAAW,GAAU,EAAE,CAAC;YAE5B,KAAK,MAAM,OAAO,IAAI,QAAQ,EAAE,CAAC;gBAC/B,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC,YAAY,CAAC,OAAO,EAAE;oBACxD,MAAM,EAAE,KAAK,CAAC,MAAM;oBACpB,KAAK,EAAE,KAAK,CAAC,KAAK;oBAClB,eAAe,EAAE,KAAK,CAAC,eAAe;iBACvC,CAAC,CAAC;gBACH,WAAW,CAAC,IAAI,CAAC,GAAG,QAAQ,CAAC,CAAC;YAChC,CAAC;YAED,UAAU;YACV,WAAW,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,IAAI,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,OAAO,EAAE,GAAG,IAAI,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC;YAE9F,MAAM,KAAK,GAAG,KAAK,CAAC,KAAK,IAAI,EAAE,CAAC;YAChC,WAAW,GAAG,WAAW,CAAC,KAAK,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC;YAE1C,MAAM,SAAS,GAAG,WAAW,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;gBACtC,SAAS,EAAE,CAAC,CAAC,SAAS;gBACtB,OAAO,EAAE,CAAC,CAAC,OAAO;gBAClB,MAAM,EAAE,CAAC,CAAC,MAAM;gBAChB,OAAO,EAAE,CAAC,CAAC,OAAO;gBAClB,SAAS,EAAE,CAAC,CAAC,SAAS;gBACtB,MAAM,EAAE,CAAC,CAAC,MAAM;aACjB,CAAC,CAAC,CAAC;YAEJ,OAAO;gBACL,QAAQ,EAAE,SAAS;gBACnB,KAAK,EAAE,SAAS,CAAC,MAAM;aACxB,CAAC;QACJ,CAAC;QAED,mBAAmB;QACnB,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC,YAAY,CAAC,KAAK,CAAC,OAAO,EAAE;YAC9D,MAAM,EAAE,KAAK,CAAC,MAAM;YACpB,KAAK,EAAE,KAAK,CAAC,KAAK;YAClB,eAAe,EAAE,KAAK,CAAC,eAAe;SACvC,CAAC,CAAC;QAEH,MAAM,SAAS,GAAG,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;YACnC,SAAS,EAAE,CAAC,CAAC,SAAS;YACtB,OAAO,EAAE,CAAC,CAAC,OAAO;YAClB,MAAM,EAAE,CAAC,CAAC,MAAM;YAChB,OAAO,EAAE,CAAC,CAAC,OAAO;YAClB,SAAS,EAAE,CAAC,CAAC,SAAS;YACtB,MAAM,EAAE,CAAC,CAAC,MAAM;SACjB,CAAC,CAAC,CAAC;QAEJ,OAAO;YACL,QAAQ,EAAE,SAAS;YACnB,KAAK,EAAE,SAAS,CAAC,MAAM;SACxB,CAAC;IACJ,CAAC;IAED,KAAK,CAAC,aAAa,CAAC,KAAyB;QAC3C,kBAAkB;QAClB,IAAI,WAAW,GAAkB,IAAI,CAAC;QACtC,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC,YAAY,EAAE,CAAC;QAEnD,KAAK,MAAM,OAAO,IAAI,QAAQ,EAAE,CAAC;YAC/B,MAAM,OAAO,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC,WAAW,CAAC,OAAO,EAAE,KAAK,CAAC,SAAS,CAAC,CAAC;YACzE,IAAI,OAAO,EAAE,CAAC;gBACZ,WAAW,GAAG,OAAO,CAAC;gBACtB,MAAM;YACR,CAAC;QACH,CAAC;QAED,IAAI,CAAC,WAAW,EAAE,CAAC;YACjB,OAAO;gBACL,OAAO,EAAE,KAAK;gBACd,OAAO,EAAE,MAAM,KAAK,CAAC,SAAS,MAAM;aACrC,CAAC;QACJ,CAAC;QAED,MAAM,OAAO,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC,aAAa,CAAC,WAAW,EAAE,KAAK,CAAC,SAAS,CAAC,CAAC;QAE/E,OAAO;YACL,OAAO;YACP,OAAO,EAAE,OAAO;gBACd,CAAC,CAAC,MAAM,KAAK,CAAC,SAAS,MAAM;gBAC7B,CAAC,CAAC,QAAQ,KAAK,CAAC,SAAS,KAAK;SACjC,CAAC;IACJ,CAAC;IAED,KAAK,CAAC,cAAc,CAAC,KAA0B;QAC7C,kBAAkB;QAClB,IAAI,WAAW,GAAkB,IAAI,CAAC;QACtC,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC,YAAY,EAAE,CAAC;QAEnD,KAAK,MAAM,OAAO,IAAI,QAAQ,EAAE,CAAC;YAC/B,MAAM,OAAO,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC,WAAW,CAAC,OAAO,EAAE,KAAK,CAAC,SAAS,CAAC,CAAC;YACzE,IAAI,OAAO,EAAE,CAAC;gBACZ,WAAW,GAAG,OAAO,CAAC;gBACtB,MAAM;YACR,CAAC;QACH,CAAC;QAED,IAAI,CAAC,WAAW,EAAE,CAAC;YACjB,OAAO;gBACL,OAAO,EAAE,KAAK;gBACd,OAAO,EAAE,MAAM,KAAK,CAAC,SAAS,MAAM;aACrC,CAAC;QACJ,CAAC;QAED,MAAM,OAAO,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC,cAAc,CAAC,WAAW,EAAE,KAAK,CAAC,SAAS,CAAC,CAAC;QAEhF,OAAO;YACL,OAAO;YACP,OAAO,EAAE,OAAO;gBACd,CAAC,CAAC,MAAM,KAAK,CAAC,SAAS,MAAM;gBAC7B,CAAC,CAAC,MAAM,KAAK,CAAC,SAAS,MAAM;SAChC,CAAC;IACJ,CAAC;IAED,KAAK,CAAC,gBAAgB,CAAC,KAA4B;QACjD,kBAAkB;QAClB,IAAI,WAAW,GAAkB,IAAI,CAAC;QACtC,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC,YAAY,EAAE,CAAC;QAEnD,KAAK,MAAM,OAAO,IAAI,QAAQ,EAAE,CAAC;YAC/B,MAAM,OAAO,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC,WAAW,CAAC,OAAO,EAAE,KAAK,CAAC,SAAS,CAAC,CAAC;YACzE,IAAI,OAAO,EAAE,CAAC;gBACZ,WAAW,GAAG,OAAO,CAAC;gBACtB,MAAM;YACR,CAAC;QACH,CAAC;QAED,IAAI,CAAC,WAAW,EAAE,CAAC;YACjB,OAAO;gBACL,OAAO,EAAE,KAAK;gBACd,OAAO,EAAE,MAAM,KAAK,CAAC,SAAS,MAAM;aACrC,CAAC;QACJ,CAAC;QAED,MAAM,OAAO,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC,gBAAgB,CAAC,WAAW,EAAE,KAAK,CAAC,SAAS,CAAC,CAAC;QAElF,OAAO;YACL,OAAO;YACP,OAAO,EAAE,OAAO;gBACd,CAAC,CAAC,MAAM,KAAK,CAAC,SAAS,QAAQ;gBAC/B,CAAC,CAAC,MAAM,KAAK,CAAC,SAAS,MAAM;SAChC,CAAC;IACJ,CAAC;CACF"}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Storage Manager - 单文件项目存储
|
|
3
|
+
* 支持原子写入:先写临时文件,再重命名
|
|
4
|
+
* ~/.session-handoff/projects/{project}.json
|
|
5
|
+
*/
|
|
6
|
+
import type { ProjectFile } from '../types.js';
|
|
7
|
+
export declare class StorageManager {
|
|
8
|
+
private baseDir;
|
|
9
|
+
constructor(customPath?: string);
|
|
10
|
+
getBaseDir(): string;
|
|
11
|
+
private getProjectsDir;
|
|
12
|
+
private getProjectPath;
|
|
13
|
+
private getHandoffsDir;
|
|
14
|
+
private getHandoffPath;
|
|
15
|
+
private ensureDir;
|
|
16
|
+
/**
|
|
17
|
+
* 原子写入文件
|
|
18
|
+
* 1. 写入临时文件
|
|
19
|
+
* 2. 重命名为目标文件
|
|
20
|
+
* 保证写入操作的原子性
|
|
21
|
+
*/
|
|
22
|
+
private atomicWrite;
|
|
23
|
+
loadProjectFile(project: string): Promise<ProjectFile | null>;
|
|
24
|
+
/**
|
|
25
|
+
* 原子保存项目文件
|
|
26
|
+
* 使用临时文件+重命名保证原子性
|
|
27
|
+
*/
|
|
28
|
+
saveProjectFile(projectFile: ProjectFile): Promise<void>;
|
|
29
|
+
createProjectFile(project: string): Promise<ProjectFile>;
|
|
30
|
+
ensureProjectFile(project: string): Promise<ProjectFile>;
|
|
31
|
+
deleteProjectFile(project: string): Promise<boolean>;
|
|
32
|
+
listProjects(): Promise<Array<{
|
|
33
|
+
name: string;
|
|
34
|
+
modifiedAt: Date;
|
|
35
|
+
}>>;
|
|
36
|
+
/**
|
|
37
|
+
* 原子保存交接文档
|
|
38
|
+
*/
|
|
39
|
+
saveHandoff(handoffId: string, markdown: string): Promise<string>;
|
|
40
|
+
loadHandoff(handoffId: string): Promise<string | null>;
|
|
41
|
+
listHandoffs(limit?: number): Promise<Array<{
|
|
42
|
+
handoffId: string;
|
|
43
|
+
createdAt: string;
|
|
44
|
+
}>>;
|
|
45
|
+
}
|
|
46
|
+
//# sourceMappingURL=storage.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"storage.d.ts","sourceRoot":"","sources":["../../src/managers/storage.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAMH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAI/C,qBAAa,cAAc;IACzB,OAAO,CAAC,OAAO,CAAS;gBAEZ,UAAU,CAAC,EAAE,MAAM;IAI/B,UAAU,IAAI,MAAM;IAIpB,OAAO,CAAC,cAAc;IAItB,OAAO,CAAC,cAAc;IAItB,OAAO,CAAC,cAAc;IAItB,OAAO,CAAC,cAAc;YAIR,SAAS;IAMvB;;;;;OAKG;YACW,WAAW;IA4BnB,eAAe,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC;IAUnE;;;OAGG;IACG,eAAe,CAAC,WAAW,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC;IAUxD,iBAAiB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC;IAkBxD,iBAAiB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC;IAQxD,iBAAiB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IASpD,YAAY,IAAI,OAAO,CAAC,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE,IAAI,CAAA;KAAE,CAAC,CAAC;IAoBxE;;OAEG;IACG,WAAW,CAAC,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAMjE,WAAW,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;IAMtD,YAAY,CAAC,KAAK,GAAE,MAAW,GAAG,OAAO,CAAC,KAAK,CAAC;QAAE,SAAS,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CAqBjG"}
|
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Storage Manager - 单文件项目存储
|
|
3
|
+
* 支持原子写入:先写临时文件,再重命名
|
|
4
|
+
* ~/.session-handoff/projects/{project}.json
|
|
5
|
+
*/
|
|
6
|
+
import { mkdir, writeFile, readFile, readdir, unlink, rename, stat } from 'fs/promises';
|
|
7
|
+
import { existsSync } from 'fs';
|
|
8
|
+
import { join, dirname } from 'path';
|
|
9
|
+
import { homedir } from 'os';
|
|
10
|
+
const VERSION = '2.0.0';
|
|
11
|
+
export class StorageManager {
|
|
12
|
+
baseDir;
|
|
13
|
+
constructor(customPath) {
|
|
14
|
+
this.baseDir = customPath || join(homedir(), '.session-handoff');
|
|
15
|
+
}
|
|
16
|
+
getBaseDir() {
|
|
17
|
+
return this.baseDir;
|
|
18
|
+
}
|
|
19
|
+
getProjectsDir() {
|
|
20
|
+
return join(this.baseDir, 'projects');
|
|
21
|
+
}
|
|
22
|
+
getProjectPath(project) {
|
|
23
|
+
return join(this.getProjectsDir(), `${project}.json`);
|
|
24
|
+
}
|
|
25
|
+
getHandoffsDir() {
|
|
26
|
+
return join(this.baseDir, 'handoffs');
|
|
27
|
+
}
|
|
28
|
+
getHandoffPath(handoffId) {
|
|
29
|
+
return join(this.getHandoffsDir(), `${handoffId}.md`);
|
|
30
|
+
}
|
|
31
|
+
async ensureDir(dir) {
|
|
32
|
+
await mkdir(dir, { recursive: true });
|
|
33
|
+
}
|
|
34
|
+
// ============ 原子文件写入 ============
|
|
35
|
+
/**
|
|
36
|
+
* 原子写入文件
|
|
37
|
+
* 1. 写入临时文件
|
|
38
|
+
* 2. 重命名为目标文件
|
|
39
|
+
* 保证写入操作的原子性
|
|
40
|
+
*/
|
|
41
|
+
async atomicWrite(filePath, content) {
|
|
42
|
+
const dir = dirname(filePath);
|
|
43
|
+
const tempPath = join(dir, `.tmp_${Date.now()}_${Math.random().toString(36).slice(2)}`);
|
|
44
|
+
try {
|
|
45
|
+
// 1. 确保目录存在
|
|
46
|
+
await this.ensureDir(dir);
|
|
47
|
+
// 2. 写入临时文件
|
|
48
|
+
await writeFile(tempPath, content, 'utf-8');
|
|
49
|
+
// 3. 原子重命名
|
|
50
|
+
await rename(tempPath, filePath);
|
|
51
|
+
}
|
|
52
|
+
catch (error) {
|
|
53
|
+
// 清理临时文件
|
|
54
|
+
try {
|
|
55
|
+
if (existsSync(tempPath)) {
|
|
56
|
+
await unlink(tempPath);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
catch {
|
|
60
|
+
// 忽略清理错误
|
|
61
|
+
}
|
|
62
|
+
throw error;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
// ============ 项目文件操作 ============
|
|
66
|
+
async loadProjectFile(project) {
|
|
67
|
+
const filePath = this.getProjectPath(project);
|
|
68
|
+
if (!existsSync(filePath)) {
|
|
69
|
+
return null;
|
|
70
|
+
}
|
|
71
|
+
const content = await readFile(filePath, 'utf-8');
|
|
72
|
+
return JSON.parse(content);
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* 原子保存项目文件
|
|
76
|
+
* 使用临时文件+重命名保证原子性
|
|
77
|
+
*/
|
|
78
|
+
async saveProjectFile(projectFile) {
|
|
79
|
+
const filePath = this.getProjectPath(projectFile.project);
|
|
80
|
+
// 更新元数据
|
|
81
|
+
projectFile.metadata.updatedAt = new Date().toISOString();
|
|
82
|
+
// 原子写入
|
|
83
|
+
await this.atomicWrite(filePath, JSON.stringify(projectFile, null, 2));
|
|
84
|
+
}
|
|
85
|
+
async createProjectFile(project) {
|
|
86
|
+
const now = new Date().toISOString();
|
|
87
|
+
const projectFile = {
|
|
88
|
+
project,
|
|
89
|
+
metadata: {
|
|
90
|
+
createdAt: now,
|
|
91
|
+
updatedAt: now,
|
|
92
|
+
version: VERSION
|
|
93
|
+
},
|
|
94
|
+
modules: {},
|
|
95
|
+
sessions: [],
|
|
96
|
+
pitfalls: []
|
|
97
|
+
};
|
|
98
|
+
await this.saveProjectFile(projectFile);
|
|
99
|
+
return projectFile;
|
|
100
|
+
}
|
|
101
|
+
async ensureProjectFile(project) {
|
|
102
|
+
let projectFile = await this.loadProjectFile(project);
|
|
103
|
+
if (!projectFile) {
|
|
104
|
+
projectFile = await this.createProjectFile(project);
|
|
105
|
+
}
|
|
106
|
+
return projectFile;
|
|
107
|
+
}
|
|
108
|
+
async deleteProjectFile(project) {
|
|
109
|
+
const filePath = this.getProjectPath(project);
|
|
110
|
+
if (!existsSync(filePath))
|
|
111
|
+
return false;
|
|
112
|
+
await unlink(filePath);
|
|
113
|
+
return true;
|
|
114
|
+
}
|
|
115
|
+
// ============ 项目列表 ============
|
|
116
|
+
async listProjects() {
|
|
117
|
+
const projectsDir = this.getProjectsDir();
|
|
118
|
+
if (!existsSync(projectsDir))
|
|
119
|
+
return [];
|
|
120
|
+
const files = await readdir(projectsDir);
|
|
121
|
+
const projects = [];
|
|
122
|
+
for (const file of files) {
|
|
123
|
+
if (file.endsWith('.json')) {
|
|
124
|
+
const name = file.replace('.json', '');
|
|
125
|
+
const statInfo = await stat(join(projectsDir, file));
|
|
126
|
+
projects.push({ name, modifiedAt: statInfo.mtime });
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
return projects.sort((a, b) => b.modifiedAt.getTime() - a.modifiedAt.getTime());
|
|
130
|
+
}
|
|
131
|
+
// ============ Handoff 操作 ============
|
|
132
|
+
/**
|
|
133
|
+
* 原子保存交接文档
|
|
134
|
+
*/
|
|
135
|
+
async saveHandoff(handoffId, markdown) {
|
|
136
|
+
const filePath = this.getHandoffPath(handoffId);
|
|
137
|
+
await this.atomicWrite(filePath, markdown);
|
|
138
|
+
return filePath;
|
|
139
|
+
}
|
|
140
|
+
async loadHandoff(handoffId) {
|
|
141
|
+
const filePath = this.getHandoffPath(handoffId);
|
|
142
|
+
if (!existsSync(filePath))
|
|
143
|
+
return null;
|
|
144
|
+
return readFile(filePath, 'utf-8');
|
|
145
|
+
}
|
|
146
|
+
async listHandoffs(limit = 20) {
|
|
147
|
+
const handoffsDir = this.getHandoffsDir();
|
|
148
|
+
if (!existsSync(handoffsDir))
|
|
149
|
+
return [];
|
|
150
|
+
const files = await readdir(handoffsDir);
|
|
151
|
+
const handoffs = [];
|
|
152
|
+
for (const file of files) {
|
|
153
|
+
if (file.endsWith('.md')) {
|
|
154
|
+
const handoffId = file.replace('.md', '');
|
|
155
|
+
const statInfo = await stat(join(handoffsDir, file));
|
|
156
|
+
handoffs.push({
|
|
157
|
+
handoffId,
|
|
158
|
+
createdAt: statInfo.ctime.toISOString()
|
|
159
|
+
});
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
handoffs.sort((a, b) => new Date(b.createdAt).getTime() - new Date(a.createdAt).getTime());
|
|
163
|
+
return handoffs.slice(0, limit);
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
//# sourceMappingURL=storage.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"storage.js","sourceRoot":"","sources":["../../src/managers/storage.ts"],"names":[],"mappings":"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"}
|