@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,105 @@
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 Result } from '../shared/result.js';
5
+ export type PipelineStatus = 'idle' | 'running' | 'stopping' | 'error';
6
+ export interface ProjectSummary {
7
+ readonly name: string;
8
+ readonly repoDir: string | null;
9
+ readonly pmBackend: string;
10
+ readonly agentProvider: string;
11
+ readonly cards: {
12
+ total: number;
13
+ inprogress: number;
14
+ done: number;
15
+ };
16
+ readonly workers: {
17
+ total: number;
18
+ active: number;
19
+ };
20
+ readonly pipelineStatus: PipelineStatus;
21
+ readonly lastActivityAt: string | null;
22
+ }
23
+ export interface ConfContent {
24
+ readonly content: string;
25
+ readonly etag: string;
26
+ }
27
+ export interface ProjectInitExecutor {
28
+ /**
29
+ * 由 Phase 3 的 delivery 层注入。默认 container 未注入时 create() 会返 external 错误。
30
+ * 拆出 port 是因为:
31
+ * - executeProjectInit 目前深度依赖 process.exit / 交互 readline,短期迁不进来
32
+ * - 重构期间保留命令层调 Service,Service 再回调命令层的 port 实现
33
+ */
34
+ init(project: string, opts: ProjectInitOpts): Promise<void>;
35
+ }
36
+ export interface ProjectInitOpts {
37
+ projectDir: string;
38
+ mergeBranch: string;
39
+ maxWorkers: string;
40
+ gitlabProject?: string;
41
+ gitlabProjectId?: string;
42
+ matrixRoomId?: string;
43
+ }
44
+ export interface CreateProjectInput extends ProjectInitOpts {
45
+ name: string;
46
+ }
47
+ export interface DeleteProjectOpts {
48
+ includeClaudeDir?: boolean;
49
+ }
50
+ export interface DeleteProjectReport {
51
+ readonly name: string;
52
+ readonly claudeRemoved: Array<{
53
+ path: string;
54
+ ok: boolean;
55
+ error?: string;
56
+ }>;
57
+ }
58
+ export interface ProjectServiceDeps {
59
+ readonly fs: FileSystem;
60
+ readonly clock: Clock;
61
+ readonly events: DomainEventBus;
62
+ readonly initExecutor?: ProjectInitExecutor;
63
+ }
64
+ export declare class ProjectService {
65
+ private readonly deps;
66
+ constructor(deps: ProjectServiceDeps);
67
+ /** 列出 ~/.coral/projects/ 下所有项目的概览。 */
68
+ list(): Promise<Result<ProjectSummary[]>>;
69
+ /** 获取单个项目概览。找不到返 not-found。 */
70
+ get(name: string): Promise<Result<ProjectSummary>>;
71
+ /**
72
+ * 创建项目。需要 ProjectInitExecutor 注入。
73
+ * 已存在返 conflict。
74
+ */
75
+ create(input: CreateProjectInput): Promise<Result<ProjectSummary>>;
76
+ /**
77
+ * 删除项目。pipeline 在跑时拒绝(conflict)。
78
+ * opts.includeClaudeDir 默认 true,也会删对应 repo 的 .claude/。
79
+ */
80
+ delete(name: string, opts?: DeleteProjectOpts): Promise<Result<DeleteProjectReport>>;
81
+ /** 读 conf 文件 —— 返回 content + etag(SHA-256 前 16 位)。 */
82
+ readConf(name: string): Promise<Result<ConfContent>>;
83
+ /**
84
+ * 写 conf —— etag 乐观锁。mismatch 返 conflict;内容相同 etag 不变。
85
+ * 文件权限保持 0600(conf 可能含 secret)。
86
+ */
87
+ writeConf(name: string, content: string, etag: string): Promise<Result<{
88
+ etag: string;
89
+ }>>;
90
+ private isValidName;
91
+ private readSummary;
92
+ private parseConf;
93
+ /**
94
+ * 卡片计数 —— 遍历 cards/<state>/*.md 子目录。
95
+ * v0.49.15 修过同一个坑,现在统一走 runtimePaths + 在 service 层单点实现。
96
+ */
97
+ private countCards;
98
+ /**
99
+ * Worker marker 计数 —— 匹配双前缀 + 老单前缀两种格式(v0.49.16 之前遗留)。
100
+ * 活跃判定:marker 最近 5 分钟内更新。
101
+ */
102
+ private countWorkers;
103
+ private isPipelineRunning;
104
+ }
105
+ //# sourceMappingURL=ProjectService.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ProjectService.d.ts","sourceRoot":"","sources":["../../src/services/ProjectService.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,346 @@
1
+ /**
2
+ * @module services/ProjectService
3
+ * @description 项目生命周期 service —— list / get / create / delete / conf CRUD
4
+ *
5
+ * @layer services
6
+ *
7
+ * 职责:
8
+ * - 扫 ~/.coral/projects/ 汇总每项目的概览(cards / workers / pipelineStatus)
9
+ * - 通过 executeProjectInit 创建新项目(CLI 和 Console 共用同一条路径)
10
+ * - conf 文件读写 + etag 乐观锁
11
+ * - 删项目(可选同时删 repo 的 .claude/)
12
+ *
13
+ * 不直接触发 executeProjectInit —— 保留为 Phase 3 才接 CLI 命令层迁移时注入的
14
+ * 钩子,这里先用 fs 原语实现 conf 读写,项目创建接一个 ProjectInitExecutor port。
15
+ */
16
+ import { createHash } 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 { cardsDir, projectConfFile, projectDir, projectsDir, runtimeDir, slotFromMarkerFilename, supervisorPidFile, WorkerMarkerFilenameRe, } from '../shared/runtimePaths.js';
21
+ export class ProjectService {
22
+ deps;
23
+ constructor(deps) {
24
+ this.deps = deps;
25
+ }
26
+ /** 列出 ~/.coral/projects/ 下所有项目的概览。 */
27
+ async list() {
28
+ const base = projectsDir();
29
+ if (!this.deps.fs.exists(base)) {
30
+ return ok([]);
31
+ }
32
+ let entries;
33
+ try {
34
+ entries = this.deps.fs.readDir(base);
35
+ }
36
+ catch (cause) {
37
+ return err(domainError('internal', 'PROJECTS_DIR_READ_FAIL', '无法读取项目目录', { cause }));
38
+ }
39
+ const names = entries.filter((e) => e.isDirectory).map((e) => e.name).sort();
40
+ const summaries = [];
41
+ for (const name of names) {
42
+ const r = this.readSummary(name);
43
+ if (r)
44
+ summaries.push(r);
45
+ }
46
+ return ok(summaries);
47
+ }
48
+ /** 获取单个项目概览。找不到返 not-found。 */
49
+ async get(name) {
50
+ if (!this.isValidName(name)) {
51
+ return err(invalidName());
52
+ }
53
+ const dir = projectDir(name);
54
+ if (!this.deps.fs.exists(dir)) {
55
+ return err(projectNotFound(name));
56
+ }
57
+ const summary = this.readSummary(name);
58
+ if (!summary) {
59
+ return err(projectNotFound(name));
60
+ }
61
+ return ok(summary);
62
+ }
63
+ /**
64
+ * 创建项目。需要 ProjectInitExecutor 注入。
65
+ * 已存在返 conflict。
66
+ */
67
+ async create(input) {
68
+ if (!this.isValidName(input.name)) {
69
+ return err(invalidName());
70
+ }
71
+ if (this.deps.fs.exists(projectDir(input.name))) {
72
+ return err(domainError('conflict', 'PROJECT_EXISTS', `项目 ${input.name} 已存在`, {
73
+ details: { name: input.name },
74
+ }));
75
+ }
76
+ if (!this.deps.initExecutor) {
77
+ return err(domainError('internal', 'INIT_EXECUTOR_MISSING', '项目创建需要 ProjectInitExecutor 注入(Phase 3 task)'));
78
+ }
79
+ try {
80
+ await this.deps.initExecutor.init(input.name, input);
81
+ }
82
+ catch (cause) {
83
+ return err(domainError('external', 'PROJECT_INIT_FAIL', '项目初始化失败', {
84
+ cause,
85
+ details: { message: cause instanceof Error ? cause.message : String(cause) },
86
+ }));
87
+ }
88
+ const summary = this.readSummary(input.name);
89
+ if (!summary) {
90
+ return err(domainError('internal', 'PROJECT_INIT_POST_READ_FAIL', '初始化完成但读不到项目概览'));
91
+ }
92
+ return ok(summary);
93
+ }
94
+ /**
95
+ * 删除项目。pipeline 在跑时拒绝(conflict)。
96
+ * opts.includeClaudeDir 默认 true,也会删对应 repo 的 .claude/。
97
+ */
98
+ async delete(name, opts = {}) {
99
+ if (!this.isValidName(name)) {
100
+ return err(invalidName());
101
+ }
102
+ const dir = projectDir(name);
103
+ if (!this.deps.fs.exists(dir)) {
104
+ return err(projectNotFound(name));
105
+ }
106
+ if (this.isPipelineRunning(name)) {
107
+ return err(domainError('conflict', 'PIPELINE_RUNNING', '项目 pipeline 正在运行,先停止再删除', {
108
+ details: { project: name },
109
+ }));
110
+ }
111
+ const includeClaude = opts.includeClaudeDir !== false;
112
+ let repoDirPath = null;
113
+ if (includeClaude) {
114
+ try {
115
+ const conf = this.deps.fs.readFile(projectConfFile(name));
116
+ const match = conf.match(/export\s+PROJECT_DIR=["']?([^"'\n]+)/);
117
+ repoDirPath = match?.[1]?.trim() || null;
118
+ }
119
+ catch {
120
+ // conf 丢了就不处理 claude/
121
+ }
122
+ }
123
+ try {
124
+ this.deps.fs.rm(dir, { recursive: true, force: true });
125
+ }
126
+ catch (cause) {
127
+ return err(domainError('internal', 'PROJECT_DELETE_FAIL', '项目目录删除失败', { cause }));
128
+ }
129
+ const claudeRemoved = [];
130
+ if (includeClaude && repoDirPath) {
131
+ const claudePath = resolve(repoDirPath, '.claude');
132
+ if (this.deps.fs.exists(claudePath)) {
133
+ try {
134
+ this.deps.fs.rm(claudePath, { recursive: true, force: true });
135
+ claudeRemoved.push({ path: claudePath, ok: true });
136
+ }
137
+ catch (cause) {
138
+ claudeRemoved.push({
139
+ path: claudePath,
140
+ ok: false,
141
+ error: cause instanceof Error ? cause.message : String(cause),
142
+ });
143
+ }
144
+ }
145
+ }
146
+ return ok({ name, claudeRemoved });
147
+ }
148
+ /** 读 conf 文件 —— 返回 content + etag(SHA-256 前 16 位)。 */
149
+ async readConf(name) {
150
+ if (!this.isValidName(name))
151
+ return err(invalidName());
152
+ const confPath = projectConfFile(name);
153
+ if (!this.deps.fs.exists(confPath)) {
154
+ return err(domainError('not-found', 'CONF_NOT_FOUND', `项目 ${name} 的 conf 文件不存在`));
155
+ }
156
+ try {
157
+ const content = this.deps.fs.readFile(confPath);
158
+ return ok({ content, etag: hashEtag(content) });
159
+ }
160
+ catch (cause) {
161
+ return err(domainError('internal', 'CONF_READ_FAIL', 'conf 读取失败', { cause }));
162
+ }
163
+ }
164
+ /**
165
+ * 写 conf —— etag 乐观锁。mismatch 返 conflict;内容相同 etag 不变。
166
+ * 文件权限保持 0600(conf 可能含 secret)。
167
+ */
168
+ async writeConf(name, content, etag) {
169
+ if (!this.isValidName(name))
170
+ return err(invalidName());
171
+ const confPath = projectConfFile(name);
172
+ if (!this.deps.fs.exists(confPath)) {
173
+ return err(domainError('not-found', 'CONF_NOT_FOUND', `项目 ${name} 的 conf 文件不存在`));
174
+ }
175
+ if (!etag || typeof etag !== 'string') {
176
+ return err(domainError('validation', 'ETAG_REQUIRED', 'etag 必填 —— 避免并发覆盖'));
177
+ }
178
+ let current;
179
+ try {
180
+ current = this.deps.fs.readFile(confPath);
181
+ }
182
+ catch (cause) {
183
+ return err(domainError('internal', 'CONF_READ_FAIL', 'conf 读取失败', { cause }));
184
+ }
185
+ const currentEtag = hashEtag(current);
186
+ if (etag !== currentEtag) {
187
+ return err(domainError('conflict', 'CONF_ETAG_MISMATCH', 'conf 已被其它编辑修改,请重新加载', { details: { currentEtag } }));
188
+ }
189
+ try {
190
+ this.deps.fs.writeFileAtomic(confPath, content);
191
+ }
192
+ catch (cause) {
193
+ return err(domainError('internal', 'CONF_WRITE_FAIL', 'conf 写入失败', { cause }));
194
+ }
195
+ return ok({ etag: hashEtag(content) });
196
+ }
197
+ // ─── 内部 helpers ────────────────────────────────────────────────
198
+ isValidName(name) {
199
+ return typeof name === 'string' && /^[a-zA-Z0-9_-]+$/.test(name);
200
+ }
201
+ readSummary(name) {
202
+ const dir = projectDir(name);
203
+ if (!this.deps.fs.exists(dir))
204
+ return null;
205
+ const conf = this.parseConf(name);
206
+ const cards = this.countCards(name);
207
+ const workers = this.countWorkers(name);
208
+ const pipelineStatus = this.isPipelineRunning(name) ? 'running' : 'idle';
209
+ const lastActivityAt = (() => {
210
+ const st = this.deps.fs.stat(runtimeDir(name));
211
+ return st ? new Date(st.mtimeMs).toISOString() : null;
212
+ })();
213
+ return {
214
+ name,
215
+ repoDir: conf.PROJECT_DIR ?? conf.REPO_DIR ?? null,
216
+ pmBackend: conf.PM_TOOL ?? 'markdown',
217
+ agentProvider: conf.AGENT_PROVIDER ?? 'claude',
218
+ cards,
219
+ workers,
220
+ pipelineStatus,
221
+ lastActivityAt,
222
+ };
223
+ }
224
+ parseConf(name) {
225
+ const path = projectConfFile(name);
226
+ if (!this.deps.fs.exists(path))
227
+ return {};
228
+ const out = {};
229
+ try {
230
+ const text = this.deps.fs.readFile(path);
231
+ for (const line of text.split('\n')) {
232
+ const trimmed = line.trim();
233
+ if (!trimmed || trimmed.startsWith('#'))
234
+ continue;
235
+ const m = trimmed.match(/^(?:export\s+)?([A-Z_][A-Z0-9_]*)=["']?(.*?)["']?\s*$/);
236
+ if (m)
237
+ out[m[1]] = m[2];
238
+ }
239
+ }
240
+ catch {
241
+ /* silently empty */
242
+ }
243
+ return out;
244
+ }
245
+ /**
246
+ * 卡片计数 —— 遍历 cards/<state>/*.md 子目录。
247
+ * v0.49.15 修过同一个坑,现在统一走 runtimePaths + 在 service 层单点实现。
248
+ */
249
+ countCards(name) {
250
+ const dir = cardsDir(name);
251
+ if (!this.deps.fs.exists(dir))
252
+ return { total: 0, inprogress: 0, done: 0 };
253
+ let total = 0;
254
+ let inprogress = 0;
255
+ let done = 0;
256
+ try {
257
+ for (const entry of this.deps.fs.readDir(dir)) {
258
+ if (!entry.isDirectory)
259
+ continue;
260
+ const sub = resolve(dir, entry.name);
261
+ const dirLower = entry.name.toLowerCase();
262
+ let files;
263
+ try {
264
+ files = this.deps.fs.readDir(sub).filter((e) => e.isFile && /^\d+.*\.md$/.test(e.name));
265
+ }
266
+ catch {
267
+ continue;
268
+ }
269
+ total += files.length;
270
+ if (dirLower === 'inprogress')
271
+ inprogress += files.length;
272
+ else if (dirLower === 'done')
273
+ done += files.length;
274
+ }
275
+ }
276
+ catch {
277
+ /* ignore */
278
+ }
279
+ return { total, inprogress, done };
280
+ }
281
+ /**
282
+ * Worker marker 计数 —— 匹配双前缀 + 老单前缀两种格式(v0.49.16 之前遗留)。
283
+ * 活跃判定:marker 最近 5 分钟内更新。
284
+ */
285
+ countWorkers(name) {
286
+ const dir = runtimeDir(name);
287
+ if (!this.deps.fs.exists(dir))
288
+ return { total: 0, active: 0 };
289
+ let total = 0;
290
+ let active = 0;
291
+ const now = this.deps.clock.now();
292
+ try {
293
+ for (const entry of this.deps.fs.readDir(dir)) {
294
+ if (!entry.isFile)
295
+ continue;
296
+ if (!WorkerMarkerFilenameRe.test(entry.name))
297
+ continue;
298
+ total++;
299
+ const slot = slotFromMarkerFilename(entry.name);
300
+ if (slot === null)
301
+ continue;
302
+ const stat = this.deps.fs.stat(resolve(dir, entry.name));
303
+ if (stat && now - stat.mtimeMs < 5 * 60 * 1000)
304
+ active++;
305
+ }
306
+ }
307
+ catch {
308
+ /* ignore */
309
+ }
310
+ return { total, active };
311
+ }
312
+ isPipelineRunning(name) {
313
+ const pidPath = supervisorPidFile(name);
314
+ if (!this.deps.fs.exists(pidPath))
315
+ return false;
316
+ try {
317
+ const raw = this.deps.fs.readFile(pidPath);
318
+ const pid = Number.parseInt(raw.trim(), 10);
319
+ if (!Number.isFinite(pid) || pid <= 0)
320
+ return false;
321
+ try {
322
+ process.kill(pid, 0);
323
+ return true;
324
+ }
325
+ catch {
326
+ return false;
327
+ }
328
+ }
329
+ catch {
330
+ return false;
331
+ }
332
+ }
333
+ }
334
+ // ─── Error factories ──────────────────────────────────────────────
335
+ function projectNotFound(name) {
336
+ return domainError('not-found', 'PROJECT_NOT_FOUND', `项目 ${name} 不存在`, {
337
+ details: { name },
338
+ });
339
+ }
340
+ function invalidName() {
341
+ return domainError('validation', 'INVALID_PROJECT_NAME', '项目名非法 —— 只允许字母、数字、_ 和 -');
342
+ }
343
+ function hashEtag(content) {
344
+ return createHash('sha256').update(content).digest('hex').slice(0, 16);
345
+ }
346
+ //# sourceMappingURL=ProjectService.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ProjectService.js","sourceRoot":"","sources":["../../src/services/ProjectService.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,38 @@
1
+ import type { DomainEventBus } from '../shared/domainEvents.js';
2
+ import { type DomainError } from '../shared/errors.js';
3
+ import { type Result } from '../shared/result.js';
4
+ export type SkillCategory = 'language' | 'end' | 'persona' | 'workflow' | 'other';
5
+ export type SkillLinkState = 'absent' | 'linked' | 'frozen';
6
+ export interface SkillSummary {
7
+ readonly name: string;
8
+ readonly category: SkillCategory;
9
+ readonly description: string;
10
+ readonly origin: string;
11
+ readonly linkedProjects: string[];
12
+ /** 当 opts.project 提供时附 */
13
+ readonly stateInProject?: SkillLinkState;
14
+ }
15
+ export interface SkillDetail extends SkillSummary {
16
+ readonly body: string;
17
+ readonly references: Array<{
18
+ name: string;
19
+ lines: number;
20
+ }>;
21
+ readonly linkedProjects: string[];
22
+ }
23
+ export interface SkillServiceDeps {
24
+ readonly events: DomainEventBus;
25
+ }
26
+ export declare class SkillService {
27
+ private readonly deps;
28
+ constructor(deps: SkillServiceDeps);
29
+ /** 列出 user-level skills。可选带 project 参数以得到 stateInProject。 */
30
+ list(project?: string): Promise<Result<SkillSummary[], DomainError>>;
31
+ get(name: string): Promise<Result<SkillDetail, DomainError>>;
32
+ sync(): Promise<Result<void, DomainError>>;
33
+ link(skill: string, project: string): Promise<Result<void, DomainError>>;
34
+ unlink(skill: string, project: string): Promise<Result<void, DomainError>>;
35
+ freeze(skill: string, project: string): Promise<Result<void, DomainError>>;
36
+ unfreeze(skill: string, project: string): Promise<Result<void, DomainError>>;
37
+ }
38
+ //# sourceMappingURL=SkillService.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SkillService.d.ts","sourceRoot":"","sources":["../../src/services/SkillService.ts"],"names":[],"mappings":"AAeA,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,MAAM,aAAa,GAAG,UAAU,GAAG,KAAK,GAAG,SAAS,GAAG,UAAU,GAAG,OAAO,CAAC;AAClF,MAAM,MAAM,cAAc,GAAG,QAAQ,GAAG,QAAQ,GAAG,QAAQ,CAAC;AAE5D,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,QAAQ,EAAE,aAAa,CAAC;IACjC,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,cAAc,EAAE,MAAM,EAAE,CAAC;IAClC,0BAA0B;IAC1B,QAAQ,CAAC,cAAc,CAAC,EAAE,cAAc,CAAC;CAC1C;AAED,MAAM,WAAW,WAAY,SAAQ,YAAY;IAC/C,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,UAAU,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAC5D,QAAQ,CAAC,cAAc,EAAE,MAAM,EAAE,CAAC;CACnC;AAED,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,MAAM,EAAE,cAAc,CAAC;CACjC;AAED,qBAAa,YAAY;IACX,OAAO,CAAC,QAAQ,CAAC,IAAI;gBAAJ,IAAI,EAAE,gBAAgB;IAEnD,6DAA6D;IACvD,IAAI,CAAC,OAAO,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,YAAY,EAAE,EAAE,WAAW,CAAC,CAAC;IAwBpE,GAAG,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,WAAW,EAAE,WAAW,CAAC,CAAC;IA+B5D,IAAI,IAAI,OAAO,CAAC,MAAM,CAAC,IAAI,EAAE,WAAW,CAAC,CAAC;IAiB1C,IAAI,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,IAAI,EAAE,WAAW,CAAC,CAAC;IAyBxE,MAAM,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,IAAI,EAAE,WAAW,CAAC,CAAC;IAiB1E,MAAM,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,IAAI,EAAE,WAAW,CAAC,CAAC;IAY1E,QAAQ,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,IAAI,EAAE,WAAW,CAAC,CAAC;CAWnF"}