@coralai/sps-cli 0.49.15 → 0.50.0

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.
Files changed (175) hide show
  1. package/dist/commands/cardAdd.d.ts.map +1 -1
  2. package/dist/commands/cardAdd.js +47 -67
  3. package/dist/commands/cardAdd.js.map +1 -1
  4. package/dist/commands/cardMarkComplete.js +1 -1
  5. package/dist/commands/cardMarkComplete.js.map +1 -1
  6. package/dist/commands/cardMarkStarted.js +1 -1
  7. package/dist/commands/cardMarkStarted.js.map +1 -1
  8. package/dist/commands/consoleCommand.js +3 -3
  9. package/dist/commands/consoleCommand.js.map +1 -1
  10. package/dist/commands/hookCommand.d.ts +25 -0
  11. package/dist/commands/hookCommand.d.ts.map +1 -1
  12. package/dist/commands/hookCommand.js +2 -2
  13. package/dist/commands/hookCommand.js.map +1 -1
  14. package/dist/console/index.d.ts +15 -0
  15. package/dist/console/index.d.ts.map +1 -0
  16. package/dist/console/index.js +177 -0
  17. package/dist/console/index.js.map +1 -0
  18. package/dist/console/lib/lockFile.d.ts +17 -0
  19. package/dist/console/lib/lockFile.d.ts.map +1 -0
  20. package/dist/console/lib/lockFile.js +61 -0
  21. package/dist/console/lib/lockFile.js.map +1 -0
  22. package/dist/console/lib/portPicker.d.ts +3 -0
  23. package/dist/console/lib/portPicker.d.ts.map +1 -0
  24. package/dist/console/lib/portPicker.js +25 -0
  25. package/dist/console/lib/portPicker.js.map +1 -0
  26. package/dist/console/lib/resultToJson.d.ts +18 -0
  27. package/dist/console/lib/resultToJson.d.ts.map +1 -0
  28. package/dist/console/lib/resultToJson.js +19 -0
  29. package/dist/console/lib/resultToJson.js.map +1 -0
  30. package/dist/console/routes/cards.d.ts +26 -0
  31. package/dist/console/routes/cards.d.ts.map +1 -0
  32. package/dist/console/routes/cards.js +85 -0
  33. package/dist/console/routes/cards.js.map +1 -0
  34. package/dist/console/routes/chat.d.ts +36 -0
  35. package/dist/console/routes/chat.d.ts.map +1 -0
  36. package/dist/console/routes/chat.js +458 -0
  37. package/dist/console/routes/chat.js.map +1 -0
  38. package/dist/console/routes/logs.d.ts +17 -0
  39. package/dist/console/routes/logs.d.ts.map +1 -0
  40. package/dist/console/routes/logs.js +159 -0
  41. package/dist/console/routes/logs.js.map +1 -0
  42. package/dist/console/routes/pipeline.d.ts +10 -0
  43. package/dist/console/routes/pipeline.d.ts.map +1 -0
  44. package/dist/console/routes/pipeline.js +39 -0
  45. package/dist/console/routes/pipeline.js.map +1 -0
  46. package/dist/console/routes/projects.d.ts +15 -0
  47. package/dist/console/routes/projects.d.ts.map +1 -0
  48. package/dist/console/routes/projects.js +132 -0
  49. package/dist/console/routes/projects.js.map +1 -0
  50. package/dist/console/routes/skills.d.ts +4 -0
  51. package/dist/console/routes/skills.d.ts.map +1 -0
  52. package/dist/console/routes/skills.js +91 -0
  53. package/dist/console/routes/skills.js.map +1 -0
  54. package/dist/console/routes/system.d.ts +7 -0
  55. package/dist/console/routes/system.d.ts.map +1 -0
  56. package/dist/console/routes/system.js +288 -0
  57. package/dist/console/routes/system.js.map +1 -0
  58. package/dist/console/routes/workers.d.ts +5 -0
  59. package/dist/console/routes/workers.d.ts.map +1 -0
  60. package/dist/console/routes/workers.js +149 -0
  61. package/dist/console/routes/workers.js.map +1 -0
  62. package/dist/console/sse/eventBus.d.ts +25 -0
  63. package/dist/console/sse/eventBus.d.ts.map +1 -0
  64. package/dist/console/sse/eventBus.js +32 -0
  65. package/dist/console/sse/eventBus.js.map +1 -0
  66. package/dist/console/sse/projectStream.d.ts +13 -0
  67. package/dist/console/sse/projectStream.d.ts.map +1 -0
  68. package/dist/console/sse/projectStream.js +84 -0
  69. package/dist/console/sse/projectStream.js.map +1 -0
  70. package/dist/console-server/routes/projects.d.ts.map +1 -1
  71. package/dist/console-server/routes/projects.js +2 -1
  72. package/dist/console-server/routes/projects.js.map +1 -1
  73. package/dist/console-server/routes/system.js +1 -1
  74. package/dist/console-server/routes/system.js.map +1 -1
  75. package/dist/console-server/routes/workers.d.ts.map +1 -1
  76. package/dist/console-server/routes/workers.js +14 -5
  77. package/dist/console-server/routes/workers.js.map +1 -1
  78. package/dist/console-server/watchers/markerWatcher.d.ts.map +1 -1
  79. package/dist/console-server/watchers/markerWatcher.js +4 -2
  80. package/dist/console-server/watchers/markerWatcher.js.map +1 -1
  81. package/dist/infra/chokidarWatchers.d.ts +38 -0
  82. package/dist/infra/chokidarWatchers.d.ts.map +1 -0
  83. package/dist/infra/chokidarWatchers.js +213 -0
  84. package/dist/infra/chokidarWatchers.js.map +1 -0
  85. package/dist/infra/clock.d.ts +35 -0
  86. package/dist/infra/clock.d.ts.map +1 -0
  87. package/dist/infra/clock.js +45 -0
  88. package/dist/infra/clock.js.map +1 -0
  89. package/dist/infra/filesystem.d.ts +89 -0
  90. package/dist/infra/filesystem.d.ts.map +1 -0
  91. package/dist/infra/filesystem.js +247 -0
  92. package/dist/infra/filesystem.js.map +1 -0
  93. package/dist/infra/spawn.d.ts +67 -0
  94. package/dist/infra/spawn.d.ts.map +1 -0
  95. package/dist/infra/spawn.js +116 -0
  96. package/dist/infra/spawn.js.map +1 -0
  97. package/dist/infra/sseBus.d.ts +36 -0
  98. package/dist/infra/sseBus.d.ts.map +1 -0
  99. package/dist/infra/sseBus.js +72 -0
  100. package/dist/infra/sseBus.js.map +1 -0
  101. package/dist/interfaces/ACPClient.d.ts +1 -1
  102. package/dist/interfaces/ACPClient.d.ts.map +1 -1
  103. package/dist/main.js +1 -1
  104. package/dist/main.js.map +1 -1
  105. package/dist/providers/LocalACPClient.d.ts +1 -1
  106. package/dist/providers/LocalACPClient.d.ts.map +1 -1
  107. package/dist/services/CardService.d.ts +86 -0
  108. package/dist/services/CardService.d.ts.map +1 -0
  109. package/dist/services/CardService.js +313 -0
  110. package/dist/services/CardService.js.map +1 -0
  111. package/dist/services/ChatService.d.ts +62 -0
  112. package/dist/services/ChatService.d.ts.map +1 -0
  113. package/dist/services/ChatService.js +157 -0
  114. package/dist/services/ChatService.js.map +1 -0
  115. package/dist/services/LogService.d.ts +46 -0
  116. package/dist/services/LogService.d.ts.map +1 -0
  117. package/dist/services/LogService.js +185 -0
  118. package/dist/services/LogService.js.map +1 -0
  119. package/dist/services/PipelineService.d.ts +71 -0
  120. package/dist/services/PipelineService.d.ts.map +1 -0
  121. package/dist/services/PipelineService.js +349 -0
  122. package/dist/services/PipelineService.js.map +1 -0
  123. package/dist/services/ProjectService.d.ts +105 -0
  124. package/dist/services/ProjectService.d.ts.map +1 -0
  125. package/dist/services/ProjectService.js +346 -0
  126. package/dist/services/ProjectService.js.map +1 -0
  127. package/dist/services/SkillService.d.ts +38 -0
  128. package/dist/services/SkillService.d.ts.map +1 -0
  129. package/dist/services/SkillService.js +301 -0
  130. package/dist/services/SkillService.js.map +1 -0
  131. package/dist/services/WorkerService.d.ts +83 -0
  132. package/dist/services/WorkerService.d.ts.map +1 -0
  133. package/dist/services/WorkerService.js +262 -0
  134. package/dist/services/WorkerService.js.map +1 -0
  135. package/dist/services/container.d.ts +47 -0
  136. package/dist/services/container.d.ts.map +1 -0
  137. package/dist/services/container.js +77 -0
  138. package/dist/services/container.js.map +1 -0
  139. package/dist/services/defaults.d.ts +15 -0
  140. package/dist/services/defaults.d.ts.map +1 -0
  141. package/dist/services/defaults.js +11 -0
  142. package/dist/services/defaults.js.map +1 -0
  143. package/dist/services/executors.d.ts +38 -0
  144. package/dist/services/executors.d.ts.map +1 -0
  145. package/dist/services/executors.js +157 -0
  146. package/dist/services/executors.js.map +1 -0
  147. package/dist/services/ports.d.ts +17 -0
  148. package/dist/services/ports.d.ts.map +1 -0
  149. package/dist/services/ports.js +2 -0
  150. package/dist/services/ports.js.map +1 -0
  151. package/dist/shared/domainEvents.d.ts +118 -0
  152. package/dist/shared/domainEvents.d.ts.map +1 -0
  153. package/dist/shared/domainEvents.js +40 -0
  154. package/dist/shared/domainEvents.js.map +1 -0
  155. package/dist/shared/errors.d.ts +59 -0
  156. package/dist/shared/errors.d.ts.map +1 -0
  157. package/dist/shared/errors.js +79 -0
  158. package/dist/shared/errors.js.map +1 -0
  159. package/dist/shared/result.d.ts +51 -0
  160. package/dist/shared/result.d.ts.map +1 -0
  161. package/dist/shared/result.js +48 -0
  162. package/dist/shared/result.js.map +1 -0
  163. package/dist/shared/runtimePaths.d.ts +78 -0
  164. package/dist/shared/runtimePaths.d.ts.map +1 -0
  165. package/dist/shared/runtimePaths.js +179 -0
  166. package/dist/shared/runtimePaths.js.map +1 -0
  167. package/dist/shared/runtimeSchemas.d.ts +324 -0
  168. package/dist/shared/runtimeSchemas.d.ts.map +1 -0
  169. package/dist/shared/runtimeSchemas.js +124 -0
  170. package/dist/shared/runtimeSchemas.js.map +1 -0
  171. package/dist/shared/types.d.ts +12 -0
  172. package/dist/shared/types.d.ts.map +1 -0
  173. package/dist/shared/types.js +2 -0
  174. package/dist/shared/types.js.map +1 -0
  175. package/package.json +1 -1
@@ -0,0 +1,313 @@
1
+ import { domainError } from '../shared/errors.js';
2
+ import { err, ok } from '../shared/result.js';
3
+ // 合法 state 白名单(和 Console PATCH 侧保持一致;Phase 3 归并到 shared)
4
+ const ALLOWED_STATES = [
5
+ 'Planning',
6
+ 'Backlog',
7
+ 'Todo',
8
+ 'Inprogress',
9
+ 'Review',
10
+ 'QA',
11
+ 'Done',
12
+ 'Canceled',
13
+ ];
14
+ export class CardService {
15
+ deps;
16
+ constructor(deps) {
17
+ this.deps = deps;
18
+ }
19
+ /** 列出卡片(可选 state 过滤)。按 seq 倒序(新卡在前)。 */
20
+ async list(project, filter = {}) {
21
+ if (!isValidProject(project))
22
+ return err(invalidProject());
23
+ const backend = await this.backendOr404(project);
24
+ if (!backend.ok)
25
+ return backend;
26
+ const cards = filter.state
27
+ ? await backend.value.listByState(filter.state)
28
+ : await backend.value.listAll();
29
+ const summaries = cards
30
+ .map(toCardSummary)
31
+ .sort((a, b) => b.seq - a.seq);
32
+ return ok(summaries);
33
+ }
34
+ /** 获取单卡详情(含 body + checklist)。 */
35
+ async get(project, seq) {
36
+ if (!isValidProject(project))
37
+ return err(invalidProject());
38
+ if (!Number.isInteger(seq) || seq <= 0)
39
+ return err(invalidSeq());
40
+ const backend = await this.backendOr404(project);
41
+ if (!backend.ok)
42
+ return backend;
43
+ const card = await backend.value.getBySeq(String(seq));
44
+ if (!card)
45
+ return err(cardNotFound(seq));
46
+ return ok(toCardDetail(card));
47
+ }
48
+ /** 新建卡片。state 缺省 'Planning'。 */
49
+ async create(project, input) {
50
+ if (!isValidProject(project))
51
+ return err(invalidProject());
52
+ const title = input.title?.trim();
53
+ if (!title)
54
+ return err(invalidTitle());
55
+ const state = input.initialState ?? 'Planning';
56
+ if (!ALLOWED_STATES.includes(state))
57
+ return err(invalidState(state));
58
+ const backend = await this.backendOr404(project);
59
+ if (!backend.ok)
60
+ return backend;
61
+ let created;
62
+ try {
63
+ created = await backend.value.create(title, (input.description ?? '').trim(), state);
64
+ }
65
+ catch (cause) {
66
+ return err(domainError('internal', 'CARD_CREATE_FAIL', '卡片创建失败', { cause }));
67
+ }
68
+ if (input.skills && input.skills.length > 0) {
69
+ try {
70
+ await backend.value.setSkills(created.seq, sanitizeSkills(input.skills));
71
+ }
72
+ catch {
73
+ /* skills 写失败不阻塞 create */
74
+ }
75
+ }
76
+ const summary = toCardSummary({
77
+ ...created,
78
+ skills: input.skills ?? [],
79
+ });
80
+ this.deps.events.emit({
81
+ type: 'card.created',
82
+ project,
83
+ seq: summary.seq,
84
+ card: created,
85
+ ts: this.deps.clock.now(),
86
+ });
87
+ return ok(summary);
88
+ }
89
+ /**
90
+ * 更新卡片 —— 任意字段子集。
91
+ * 字段相互独立应用,最后 emit 单次 card.updated + 如 state 变则额外 card.moved。
92
+ */
93
+ async update(project, seq, patch) {
94
+ if (!isValidProject(project))
95
+ return err(invalidProject());
96
+ if (!Number.isInteger(seq) || seq <= 0)
97
+ return err(invalidSeq());
98
+ if (Object.keys(patch).length === 0) {
99
+ return err(domainError('validation', 'PATCH_EMPTY', '没有字段可更新'));
100
+ }
101
+ if (patch.state !== undefined && !ALLOWED_STATES.includes(patch.state)) {
102
+ return err(invalidState(patch.state));
103
+ }
104
+ if (patch.title !== undefined && !patch.title.trim()) {
105
+ return err(invalidTitle());
106
+ }
107
+ if (patch.skills !== undefined && !Array.isArray(patch.skills)) {
108
+ return err(domainError('validation', 'SKILLS_NOT_ARRAY', 'skills 必须是数组'));
109
+ }
110
+ if (patch.labels !== undefined && !Array.isArray(patch.labels)) {
111
+ return err(domainError('validation', 'LABELS_NOT_ARRAY', 'labels 必须是数组'));
112
+ }
113
+ const backend = await this.backendOr404(project);
114
+ if (!backend.ok)
115
+ return backend;
116
+ const existing = await backend.value.getBySeq(String(seq));
117
+ if (!existing)
118
+ return err(cardNotFound(seq));
119
+ // 快照旧值 —— 后续 move 会改 backend 内部对象,existing.state 会被改;
120
+ // 提前取值避免事件判断依赖可变引用。
121
+ const oldState = existing.state;
122
+ const seqStr = String(seq);
123
+ try {
124
+ if (patch.title !== undefined)
125
+ await backend.value.setTitle(seqStr, patch.title);
126
+ if (patch.description !== undefined)
127
+ await backend.value.setDescription(seqStr, patch.description);
128
+ if (patch.skills !== undefined)
129
+ await backend.value.setSkills(seqStr, sanitizeSkills(patch.skills));
130
+ if (patch.labels !== undefined)
131
+ await backend.value.setLabels(seqStr, sanitizeLabels(patch.labels));
132
+ if (patch.state !== undefined && patch.state !== oldState) {
133
+ await backend.value.move(seqStr, patch.state);
134
+ }
135
+ }
136
+ catch (cause) {
137
+ return err(domainError('internal', 'CARD_UPDATE_FAIL', '卡片更新失败', { cause }));
138
+ }
139
+ const fresh = await backend.value.getBySeq(seqStr);
140
+ if (!fresh)
141
+ return err(cardNotFound(seq));
142
+ const summary = toCardSummary(fresh);
143
+ const now = this.deps.clock.now();
144
+ this.deps.events.emit({
145
+ type: 'card.updated',
146
+ project,
147
+ seq,
148
+ patch,
149
+ ts: now,
150
+ });
151
+ if (patch.state !== undefined && patch.state !== oldState) {
152
+ this.deps.events.emit({
153
+ type: 'card.moved',
154
+ project,
155
+ seq,
156
+ from: oldState,
157
+ to: patch.state,
158
+ ts: now,
159
+ });
160
+ }
161
+ return ok(summary);
162
+ }
163
+ /** 仅状态变更(无其它字段)。等价于 update({state}) 但更语义化。 */
164
+ async move(project, seq, newState) {
165
+ return this.update(project, seq, { state: newState });
166
+ }
167
+ /** 删除卡片。Inprogress 拒绝(前置条件) */
168
+ async delete(project, seq) {
169
+ if (!isValidProject(project))
170
+ return err(invalidProject());
171
+ if (!Number.isInteger(seq) || seq <= 0)
172
+ return err(invalidSeq());
173
+ const backend = await this.backendOr404(project);
174
+ if (!backend.ok)
175
+ return backend;
176
+ const card = await backend.value.getBySeq(String(seq));
177
+ if (!card)
178
+ return err(cardNotFound(seq));
179
+ if (card.state === 'Inprogress') {
180
+ return err(domainError('precondition', 'CARD_IN_PROGRESS', '卡片正在运行,请先 kill worker 或移出 Inprogress', { details: { seq, state: card.state } }));
181
+ }
182
+ try {
183
+ await backend.value.delete(String(seq));
184
+ }
185
+ catch (cause) {
186
+ return err(domainError('internal', 'CARD_DELETE_FAIL', '卡片删除失败', { cause }));
187
+ }
188
+ this.deps.events.emit({
189
+ type: 'card.deleted',
190
+ project,
191
+ seq,
192
+ ts: this.deps.clock.now(),
193
+ });
194
+ return ok(undefined);
195
+ }
196
+ /**
197
+ * 重置卡片 —— 清 frontmatter 运行字段(claimed_by / claimed_at / retry_count)
198
+ * 同时清掉系统 labels(`AI-PIPELINE`、`STARTED-<stage>`、`COMPLETED-<stage>`、`NEEDS-FIX`)
199
+ * 并移回初始态(Planning)。调用方负责先 kill 对应 worker。
200
+ */
201
+ async reset(project, seq) {
202
+ if (!isValidProject(project))
203
+ return err(invalidProject());
204
+ if (!Number.isInteger(seq) || seq <= 0)
205
+ return err(invalidSeq());
206
+ const backend = await this.backendOr404(project);
207
+ if (!backend.ok)
208
+ return backend;
209
+ const card = await backend.value.getBySeq(String(seq));
210
+ if (!card)
211
+ return err(cardNotFound(seq));
212
+ const oldState = card.state; // 同 update:snapshot 避免 move 后回读失真
213
+ const seqStr = String(seq);
214
+ try {
215
+ // 清 labels —— 只保留用户自定义(非系统 label)
216
+ const cleanLabels = (card.labels ?? []).filter((l) => l !== 'AI-PIPELINE' &&
217
+ l !== 'NEEDS-FIX' &&
218
+ l !== 'CLAIMED' &&
219
+ !l.startsWith('STARTED-') &&
220
+ !l.startsWith('COMPLETED-'));
221
+ await backend.value.setLabels(seqStr, cleanLabels);
222
+ await backend.value.releaseClaim(seqStr);
223
+ await backend.value.resetRetryCount(seqStr);
224
+ if (oldState !== 'Planning') {
225
+ await backend.value.move(seqStr, 'Planning');
226
+ }
227
+ }
228
+ catch (cause) {
229
+ return err(domainError('internal', 'CARD_RESET_FAIL', '卡片重置失败', { cause }));
230
+ }
231
+ const fresh = await backend.value.getBySeq(seqStr);
232
+ if (!fresh)
233
+ return err(cardNotFound(seq));
234
+ const now = this.deps.clock.now();
235
+ this.deps.events.emit({
236
+ type: 'card.updated',
237
+ project,
238
+ seq,
239
+ patch: { state: 'Planning' },
240
+ ts: now,
241
+ });
242
+ if (oldState !== 'Planning') {
243
+ this.deps.events.emit({
244
+ type: 'card.moved',
245
+ project,
246
+ seq,
247
+ from: oldState,
248
+ to: 'Planning',
249
+ ts: now,
250
+ });
251
+ }
252
+ return ok(toCardSummary(fresh));
253
+ }
254
+ // ─── 内部 ─────────────────────────────────────────────────────────
255
+ async backendOr404(project) {
256
+ try {
257
+ return ok(await this.deps.backendFactory.for(project));
258
+ }
259
+ catch (cause) {
260
+ return err(domainError('not-found', 'PROJECT_NOT_FOUND', `项目 ${project} 不存在`, { cause, details: { project } }));
261
+ }
262
+ }
263
+ }
264
+ // ─── Helpers ──────────────────────────────────────────────────────
265
+ function toCardSummary(card) {
266
+ return {
267
+ seq: Number.parseInt(card.seq, 10),
268
+ title: card.title,
269
+ state: card.state,
270
+ skills: card.skills ?? [],
271
+ labels: card.labels ?? [],
272
+ branch: card.meta?.branch ?? null,
273
+ createdAt: card.meta?.createdAt ?? null,
274
+ updatedAt: card.meta?.updatedAt ?? null,
275
+ };
276
+ }
277
+ function toCardDetail(card) {
278
+ return {
279
+ ...toCardSummary(card),
280
+ body: card.desc ?? '',
281
+ checklist: card.checklist ?? { total: 0, done: 0, percent: 0, items: [] },
282
+ activeWorkerSlot: null, // 组合 WorkerService 时再填
283
+ };
284
+ }
285
+ function sanitizeSkills(skills) {
286
+ return [...new Set(skills.map((s) => String(s).trim()).filter(Boolean))];
287
+ }
288
+ function sanitizeLabels(labels) {
289
+ return [...new Set(labels.map((l) => String(l).trim()).filter(Boolean))];
290
+ }
291
+ function isValidProject(project) {
292
+ return typeof project === 'string' && /^[a-zA-Z0-9_-]+$/.test(project);
293
+ }
294
+ function invalidProject() {
295
+ return domainError('validation', 'INVALID_PROJECT_NAME', '项目名非法');
296
+ }
297
+ function invalidSeq() {
298
+ return domainError('validation', 'INVALID_SEQ', 'seq 必须是正整数');
299
+ }
300
+ function invalidTitle() {
301
+ return domainError('validation', 'INVALID_TITLE', '卡片标题不能为空');
302
+ }
303
+ function invalidState(state) {
304
+ return domainError('validation', 'INVALID_STATE', `state 非法:${state}`, {
305
+ details: { allowed: ALLOWED_STATES },
306
+ });
307
+ }
308
+ function cardNotFound(seq) {
309
+ return domainError('not-found', 'CARD_NOT_FOUND', `卡片 #${seq} 不存在`, {
310
+ details: { seq },
311
+ });
312
+ }
313
+ //# sourceMappingURL=CardService.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"CardService.js","sourceRoot":"","sources":["../../src/services/CardService.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,62 @@
1
+ import type { Clock } from '../infra/clock.js';
2
+ import type { FileSystem } from '../infra/filesystem.js';
3
+ import type { DomainEventBus } from '../shared/domainEvents.js';
4
+ import { type DomainError } from '../shared/errors.js';
5
+ import { type Result } from '../shared/result.js';
6
+ export interface ChatMessage {
7
+ readonly id: string;
8
+ readonly role: 'user' | 'assistant' | 'system' | 'error';
9
+ readonly content: string;
10
+ readonly ts: string;
11
+ readonly blocks?: unknown[];
12
+ }
13
+ export interface ChatSession {
14
+ readonly id: string;
15
+ readonly createdAt: string;
16
+ readonly lastMessageAt: string | null;
17
+ readonly title: string;
18
+ readonly project: string | null;
19
+ readonly messageCount: number;
20
+ readonly messages: ChatMessage[];
21
+ }
22
+ export interface ChatSessionSummary {
23
+ readonly id: string;
24
+ readonly createdAt: string;
25
+ readonly lastMessageAt: string | null;
26
+ readonly title: string;
27
+ readonly project: string | null;
28
+ readonly messageCount: number;
29
+ }
30
+ export interface CreateSessionInput {
31
+ title?: string;
32
+ project?: string | null;
33
+ }
34
+ export interface ChatExecutor {
35
+ /** 停止会话对应的 daemon worker(Delete 时清理) */
36
+ stopSession(sessionId: string): Promise<void>;
37
+ /** 中断正在进行的 assistant turn */
38
+ cancelRun(sessionId: string): Promise<void>;
39
+ }
40
+ export interface ChatServiceDeps {
41
+ readonly fs: FileSystem;
42
+ readonly clock: Clock;
43
+ readonly events: DomainEventBus;
44
+ readonly executor?: ChatExecutor;
45
+ }
46
+ export declare class ChatService {
47
+ private readonly deps;
48
+ constructor(deps: ChatServiceDeps);
49
+ list(): Promise<Result<ChatSessionSummary[], DomainError>>;
50
+ create(input?: CreateSessionInput): Promise<Result<ChatSessionSummary, DomainError>>;
51
+ get(id: string): Promise<Result<ChatSession, DomainError>>;
52
+ /** 返回 since 之后的消息(供 SSE 重连补偿)。since 缺省返回全部。 */
53
+ getMessages(id: string, since?: string): Promise<Result<{
54
+ data: ChatMessage[];
55
+ total: number;
56
+ }, DomainError>>;
57
+ delete(id: string): Promise<Result<void, DomainError>>;
58
+ interrupt(id: string): Promise<Result<void, DomainError>>;
59
+ private sessionPath;
60
+ private summarize;
61
+ }
62
+ //# sourceMappingURL=ChatService.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ChatService.d.ts","sourceRoot":"","sources":["../../src/services/ChatService.ts"],"names":[],"mappings":"AAiBA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,mBAAmB,CAAC;AAC/C,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAC;AACzD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAChE,OAAO,EAAE,KAAK,WAAW,EAAe,MAAM,qBAAqB,CAAC;AACpE,OAAO,EAAW,KAAK,MAAM,EAAE,MAAM,qBAAqB,CAAC;AAG3D,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,WAAW,GAAG,QAAQ,GAAG,OAAO,CAAC;IACzD,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,MAAM,CAAC,EAAE,OAAO,EAAE,CAAC;CAC7B;AAED,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;IACtC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,QAAQ,EAAE,WAAW,EAAE,CAAC;CAClC;AAED,MAAM,WAAW,kBAAkB;IACjC,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;IACtC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;CAC/B;AAED,MAAM,WAAW,kBAAkB;IACjC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CACzB;AAED,MAAM,WAAW,YAAY;IAC3B,wCAAwC;IACxC,WAAW,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC9C,6BAA6B;IAC7B,SAAS,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CAC7C;AAED,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,EAAE,EAAE,UAAU,CAAC;IACxB,QAAQ,CAAC,KAAK,EAAE,KAAK,CAAC;IACtB,QAAQ,CAAC,MAAM,EAAE,cAAc,CAAC;IAChC,QAAQ,CAAC,QAAQ,CAAC,EAAE,YAAY,CAAC;CAClC;AAED,qBAAa,WAAW;IACV,OAAO,CAAC,QAAQ,CAAC,IAAI;gBAAJ,IAAI,EAAE,eAAe;IAE5C,IAAI,IAAI,OAAO,CAAC,MAAM,CAAC,kBAAkB,EAAE,EAAE,WAAW,CAAC,CAAC;IA4B1D,MAAM,CAAC,KAAK,GAAE,kBAAuB,GAAG,OAAO,CAAC,MAAM,CAAC,kBAAkB,EAAE,WAAW,CAAC,CAAC;IAmBxF,GAAG,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,WAAW,EAAE,WAAW,CAAC,CAAC;IAchE,+CAA+C;IACzC,WAAW,CACf,EAAE,EAAE,MAAM,EACV,KAAK,CAAC,EAAE,MAAM,GACb,OAAO,CAAC,MAAM,CAAC;QAAE,IAAI,EAAE,WAAW,EAAE,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,EAAE,WAAW,CAAC,CAAC;IAQjE,MAAM,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,IAAI,EAAE,WAAW,CAAC,CAAC;IAqBtD,SAAS,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,IAAI,EAAE,WAAW,CAAC,CAAC;IAmB/D,OAAO,CAAC,WAAW;IAInB,OAAO,CAAC,SAAS;CAUlB"}
@@ -0,0 +1,157 @@
1
+ /**
2
+ * @module services/ChatService
3
+ * @description Chat 会话 CRUD service
4
+ *
5
+ * @layer services
6
+ *
7
+ * Phase 2 范围:
8
+ * - session 生命周期(list / create / get / delete)
9
+ * - messages diff 查询
10
+ *
11
+ * Phase 3 追加:
12
+ * - sendMessage(走 daemon IPC + SSE 流式推送)—— 通过注入 ChatExecutor port
13
+ *
14
+ * 本 service 隐藏 chat session JSON 文件的存储细节,使用 FileSystem port。
15
+ */
16
+ import { randomUUID } from 'node:crypto';
17
+ import { resolve } from 'node:path';
18
+ import { domainError } from '../shared/errors.js';
19
+ import { err, ok } from '../shared/result.js';
20
+ import { chatSessionsDir } from '../shared/runtimePaths.js';
21
+ export class ChatService {
22
+ deps;
23
+ constructor(deps) {
24
+ this.deps = deps;
25
+ }
26
+ async list() {
27
+ const dir = chatSessionsDir();
28
+ if (!this.deps.fs.exists(dir))
29
+ return ok([]);
30
+ let files;
31
+ try {
32
+ files = this.deps.fs.readDir(dir).filter((e) => e.isFile && e.name.endsWith('.json'));
33
+ }
34
+ catch (cause) {
35
+ return err(domainError('internal', 'CHAT_LIST_FAIL', '会话列表读取失败', { cause }));
36
+ }
37
+ const summaries = [];
38
+ for (const entry of files) {
39
+ const path = resolve(dir, entry.name);
40
+ try {
41
+ const raw = this.deps.fs.readFile(path);
42
+ const session = JSON.parse(raw);
43
+ summaries.push(this.summarize(session));
44
+ }
45
+ catch {
46
+ /* 跳过坏 session */
47
+ }
48
+ }
49
+ summaries.sort((a, b) => {
50
+ const ta = a.lastMessageAt ?? a.createdAt;
51
+ const tb = b.lastMessageAt ?? b.createdAt;
52
+ return Date.parse(tb) - Date.parse(ta);
53
+ });
54
+ return ok(summaries);
55
+ }
56
+ async create(input = {}) {
57
+ const id = randomUUID();
58
+ const session = {
59
+ id,
60
+ createdAt: this.deps.clock.nowIso(),
61
+ lastMessageAt: null,
62
+ title: input.title?.trim() || '新对话',
63
+ project: input.project ?? null,
64
+ messageCount: 0,
65
+ messages: [],
66
+ };
67
+ try {
68
+ this.deps.fs.writeFileAtomic(this.sessionPath(id), JSON.stringify(session));
69
+ }
70
+ catch (cause) {
71
+ return err(domainError('internal', 'CHAT_CREATE_FAIL', '会话创建失败', { cause }));
72
+ }
73
+ return ok(this.summarize(session));
74
+ }
75
+ async get(id) {
76
+ if (!isValidSessionId(id))
77
+ return err(invalidId());
78
+ const path = this.sessionPath(id);
79
+ if (!this.deps.fs.exists(path)) {
80
+ return err(domainError('not-found', 'CHAT_SESSION_NOT_FOUND', '会话不存在'));
81
+ }
82
+ try {
83
+ const raw = this.deps.fs.readFile(path);
84
+ return ok(JSON.parse(raw));
85
+ }
86
+ catch (cause) {
87
+ return err(domainError('internal', 'CHAT_READ_FAIL', '会话读取失败', { cause }));
88
+ }
89
+ }
90
+ /** 返回 since 之后的消息(供 SSE 重连补偿)。since 缺省返回全部。 */
91
+ async getMessages(id, since) {
92
+ const sessionR = await this.get(id);
93
+ if (!sessionR.ok)
94
+ return sessionR;
95
+ const session = sessionR.value;
96
+ const messages = since ? session.messages.filter((m) => m.ts > since) : session.messages;
97
+ return ok({ data: messages, total: session.messages.length });
98
+ }
99
+ async delete(id) {
100
+ if (!isValidSessionId(id))
101
+ return err(invalidId());
102
+ const path = this.sessionPath(id);
103
+ if (this.deps.fs.exists(path)) {
104
+ try {
105
+ this.deps.fs.unlink(path);
106
+ }
107
+ catch (cause) {
108
+ return err(domainError('internal', 'CHAT_DELETE_FAIL', '会话删除失败', { cause }));
109
+ }
110
+ }
111
+ // best effort 停止 daemon worker
112
+ if (this.deps.executor) {
113
+ try {
114
+ await this.deps.executor.stopSession(id);
115
+ }
116
+ catch {
117
+ /* 不阻塞删除 */
118
+ }
119
+ }
120
+ return ok(undefined);
121
+ }
122
+ async interrupt(id) {
123
+ if (!isValidSessionId(id))
124
+ return err(invalidId());
125
+ if (!this.deps.executor) {
126
+ return err(domainError('internal', 'EXECUTOR_MISSING', 'ChatExecutor 未注入'));
127
+ }
128
+ try {
129
+ await this.deps.executor.cancelRun(id);
130
+ }
131
+ catch (cause) {
132
+ return err(domainError('external', 'CHAT_CANCEL_FAIL', '中断会话失败', { cause }));
133
+ }
134
+ return ok(undefined);
135
+ }
136
+ // ─── helpers ──────────────────────────────────────────────────────
137
+ sessionPath(id) {
138
+ return resolve(chatSessionsDir(), `${id}.json`);
139
+ }
140
+ summarize(s) {
141
+ return {
142
+ id: s.id,
143
+ createdAt: s.createdAt,
144
+ lastMessageAt: s.lastMessageAt,
145
+ title: s.title,
146
+ project: s.project,
147
+ messageCount: s.messageCount,
148
+ };
149
+ }
150
+ }
151
+ function isValidSessionId(id) {
152
+ return typeof id === 'string' && /^[a-zA-Z0-9-]+$/.test(id);
153
+ }
154
+ function invalidId() {
155
+ return domainError('validation', 'INVALID_SESSION_ID', 'session id 非法');
156
+ }
157
+ //# sourceMappingURL=ChatService.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ChatService.js","sourceRoot":"","sources":["../../src/services/ChatService.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,46 @@
1
+ import type { FileSystem } from '../infra/filesystem.js';
2
+ import { type DomainError } from '../shared/errors.js';
3
+ import { type Result } from '../shared/result.js';
4
+ export interface LogLine {
5
+ readonly ts: string | null;
6
+ readonly worker: number | null;
7
+ readonly level: 'debug' | 'info' | 'warn' | 'error' | 'trace';
8
+ readonly msg: string;
9
+ readonly raw: string;
10
+ readonly project?: string;
11
+ }
12
+ export interface LogQueryOpts {
13
+ project: string;
14
+ worker?: number;
15
+ limit?: number;
16
+ /** ISO datetime string —— 只返时间 >= since 的行 */
17
+ since?: string;
18
+ }
19
+ export interface LogQueryResult {
20
+ readonly data: LogLine[];
21
+ readonly file: string | null;
22
+ readonly files: string[];
23
+ }
24
+ export interface AggregateOpts {
25
+ worker?: number;
26
+ limit?: number;
27
+ since?: string;
28
+ }
29
+ export interface AggregateResult {
30
+ readonly data: LogLine[];
31
+ readonly files: string[];
32
+ }
33
+ export interface LogServiceDeps {
34
+ readonly fs: FileSystem;
35
+ }
36
+ export declare class LogService {
37
+ private readonly deps;
38
+ constructor(deps: LogServiceDeps);
39
+ /** 单项目 tail。 */
40
+ tail(opts: LogQueryOpts): Promise<Result<LogQueryResult, DomainError>>;
41
+ /** 跨项目聚合 tail。 */
42
+ aggregate(opts?: AggregateOpts): Promise<Result<AggregateResult, DomainError>>;
43
+ private findLogFiles;
44
+ }
45
+ export declare function parseLogLine(raw: string): LogLine;
46
+ //# sourceMappingURL=LogService.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"LogService.d.ts","sourceRoot":"","sources":["../../src/services/LogService.ts"],"names":[],"mappings":"AAgBA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAC;AACzD,OAAO,EAAE,KAAK,WAAW,EAAe,MAAM,qBAAqB,CAAC;AACpE,OAAO,EAAW,KAAK,MAAM,EAAE,MAAM,qBAAqB,CAAC;AAK3D,MAAM,WAAW,OAAO;IACtB,QAAQ,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IAC/B,QAAQ,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,OAAO,CAAC;IAC9D,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC;CAC3B;AAED,MAAM,WAAW,YAAY;IAC3B,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,8CAA8C;IAC9C,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,IAAI,EAAE,OAAO,EAAE,CAAC;IACzB,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,QAAQ,CAAC,KAAK,EAAE,MAAM,EAAE,CAAC;CAC1B;AAED,MAAM,WAAW,aAAa;IAC5B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,IAAI,EAAE,OAAO,EAAE,CAAC;IACzB,QAAQ,CAAC,KAAK,EAAE,MAAM,EAAE,CAAC;CAC1B;AAED,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,EAAE,EAAE,UAAU,CAAC;CACzB;AAED,qBAAa,UAAU;IACT,OAAO,CAAC,QAAQ,CAAC,IAAI;gBAAJ,IAAI,EAAE,cAAc;IAEjD,gBAAgB;IACV,IAAI,CAAC,IAAI,EAAE,YAAY,GAAG,OAAO,CAAC,MAAM,CAAC,cAAc,EAAE,WAAW,CAAC,CAAC;IAoB5E,kBAAkB;IACZ,SAAS,CAAC,IAAI,GAAE,aAAkB,GAAG,OAAO,CAAC,MAAM,CAAC,eAAe,EAAE,WAAW,CAAC,CAAC;IA2CxF,OAAO,CAAC,YAAY;CAwBrB;AA4BD,wBAAgB,YAAY,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAsBjD"}