@cat-factory/orchestration 0.6.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 (182) hide show
  1. package/LICENSE +21 -0
  2. package/dist/container.d.ts +460 -0
  3. package/dist/container.d.ts.map +1 -0
  4. package/dist/container.js +657 -0
  5. package/dist/container.js.map +1 -0
  6. package/dist/index.d.ts +29 -0
  7. package/dist/index.d.ts.map +1 -0
  8. package/dist/index.js +31 -0
  9. package/dist/index.js.map +1 -0
  10. package/dist/modules/board/BoardService.d.ts +125 -0
  11. package/dist/modules/board/BoardService.d.ts.map +1 -0
  12. package/dist/modules/board/BoardService.js +496 -0
  13. package/dist/modules/board/BoardService.js.map +1 -0
  14. package/dist/modules/board/board.logic.d.ts +17 -0
  15. package/dist/modules/board/board.logic.d.ts.map +1 -0
  16. package/dist/modules/board/board.logic.js +51 -0
  17. package/dist/modules/board/board.logic.js.map +1 -0
  18. package/dist/modules/boardScan/BoardScanService.d.ts +35 -0
  19. package/dist/modules/boardScan/BoardScanService.d.ts.map +1 -0
  20. package/dist/modules/boardScan/BoardScanService.js +91 -0
  21. package/dist/modules/boardScan/BoardScanService.js.map +1 -0
  22. package/dist/modules/boardScan/board-scan.logic.d.ts +10 -0
  23. package/dist/modules/boardScan/board-scan.logic.d.ts.map +1 -0
  24. package/dist/modules/boardScan/board-scan.logic.js +26 -0
  25. package/dist/modules/boardScan/board-scan.logic.js.map +1 -0
  26. package/dist/modules/bootstrap/BootstrapService.d.ts +114 -0
  27. package/dist/modules/bootstrap/BootstrapService.d.ts.map +1 -0
  28. package/dist/modules/bootstrap/BootstrapService.js +516 -0
  29. package/dist/modules/bootstrap/BootstrapService.js.map +1 -0
  30. package/dist/modules/clarity/ClarityReviewService.d.ts +48 -0
  31. package/dist/modules/clarity/ClarityReviewService.d.ts.map +1 -0
  32. package/dist/modules/clarity/ClarityReviewService.js +63 -0
  33. package/dist/modules/clarity/ClarityReviewService.js.map +1 -0
  34. package/dist/modules/clarity/clarity.logic.d.ts +36 -0
  35. package/dist/modules/clarity/clarity.logic.d.ts.map +1 -0
  36. package/dist/modules/clarity/clarity.logic.js +98 -0
  37. package/dist/modules/clarity/clarity.logic.js.map +1 -0
  38. package/dist/modules/estimation/estimate.logic.d.ts +11 -0
  39. package/dist/modules/estimation/estimate.logic.d.ts.map +1 -0
  40. package/dist/modules/estimation/estimate.logic.js +37 -0
  41. package/dist/modules/estimation/estimate.logic.js.map +1 -0
  42. package/dist/modules/execution/AgentContextBuilder.d.ts +114 -0
  43. package/dist/modules/execution/AgentContextBuilder.d.ts.map +1 -0
  44. package/dist/modules/execution/AgentContextBuilder.js +316 -0
  45. package/dist/modules/execution/AgentContextBuilder.js.map +1 -0
  46. package/dist/modules/execution/CompanionController.d.ts +60 -0
  47. package/dist/modules/execution/CompanionController.d.ts.map +1 -0
  48. package/dist/modules/execution/CompanionController.js +216 -0
  49. package/dist/modules/execution/CompanionController.js.map +1 -0
  50. package/dist/modules/execution/ExecutionService.d.ts +874 -0
  51. package/dist/modules/execution/ExecutionService.d.ts.map +1 -0
  52. package/dist/modules/execution/ExecutionService.js +2921 -0
  53. package/dist/modules/execution/ExecutionService.js.map +1 -0
  54. package/dist/modules/execution/MergeResolver.d.ts +34 -0
  55. package/dist/modules/execution/MergeResolver.d.ts.map +1 -0
  56. package/dist/modules/execution/MergeResolver.js +81 -0
  57. package/dist/modules/execution/MergeResolver.js.map +1 -0
  58. package/dist/modules/execution/ReviewGateController.d.ts +163 -0
  59. package/dist/modules/execution/ReviewGateController.d.ts.map +1 -0
  60. package/dist/modules/execution/ReviewGateController.js +251 -0
  61. package/dist/modules/execution/ReviewGateController.js.map +1 -0
  62. package/dist/modules/execution/TesterController.d.ts +61 -0
  63. package/dist/modules/execution/TesterController.d.ts.map +1 -0
  64. package/dist/modules/execution/TesterController.js +215 -0
  65. package/dist/modules/execution/TesterController.js.map +1 -0
  66. package/dist/modules/execution/advance.d.ts +84 -0
  67. package/dist/modules/execution/advance.d.ts.map +1 -0
  68. package/dist/modules/execution/advance.js +2 -0
  69. package/dist/modules/execution/advance.js.map +1 -0
  70. package/dist/modules/execution/artifact-review.logic.d.ts +25 -0
  71. package/dist/modules/execution/artifact-review.logic.d.ts.map +1 -0
  72. package/dist/modules/execution/artifact-review.logic.js +39 -0
  73. package/dist/modules/execution/artifact-review.logic.js.map +1 -0
  74. package/dist/modules/execution/ci.logic.d.ts +101 -0
  75. package/dist/modules/execution/ci.logic.d.ts.map +1 -0
  76. package/dist/modules/execution/ci.logic.js +117 -0
  77. package/dist/modules/execution/ci.logic.js.map +1 -0
  78. package/dist/modules/execution/drive.d.ts +47 -0
  79. package/dist/modules/execution/drive.d.ts.map +1 -0
  80. package/dist/modules/execution/drive.js +112 -0
  81. package/dist/modules/execution/drive.js.map +1 -0
  82. package/dist/modules/execution/gates.d.ts +97 -0
  83. package/dist/modules/execution/gates.d.ts.map +1 -0
  84. package/dist/modules/execution/gates.js +2 -0
  85. package/dist/modules/execution/gates.js.map +1 -0
  86. package/dist/modules/execution/individualVendors.logic.d.ts +22 -0
  87. package/dist/modules/execution/individualVendors.logic.d.ts.map +1 -0
  88. package/dist/modules/execution/individualVendors.logic.js +33 -0
  89. package/dist/modules/execution/individualVendors.logic.js.map +1 -0
  90. package/dist/modules/execution/job.logic.d.ts +52 -0
  91. package/dist/modules/execution/job.logic.d.ts.map +1 -0
  92. package/dist/modules/execution/job.logic.js +56 -0
  93. package/dist/modules/execution/job.logic.js.map +1 -0
  94. package/dist/modules/execution/release.logic.d.ts +43 -0
  95. package/dist/modules/execution/release.logic.d.ts.map +1 -0
  96. package/dist/modules/execution/release.logic.js +49 -0
  97. package/dist/modules/execution/release.logic.js.map +1 -0
  98. package/dist/modules/execution/retry.logic.d.ts +40 -0
  99. package/dist/modules/execution/retry.logic.d.ts.map +1 -0
  100. package/dist/modules/execution/retry.logic.js +83 -0
  101. package/dist/modules/execution/retry.logic.js.map +1 -0
  102. package/dist/modules/execution/stepGating.logic.d.ts +15 -0
  103. package/dist/modules/execution/stepGating.logic.d.ts.map +1 -0
  104. package/dist/modules/execution/stepGating.logic.js +29 -0
  105. package/dist/modules/execution/stepGating.logic.js.map +1 -0
  106. package/dist/modules/execution/stepResolvers.d.ts +41 -0
  107. package/dist/modules/execution/stepResolvers.d.ts.map +1 -0
  108. package/dist/modules/execution/stepResolvers.js +2 -0
  109. package/dist/modules/execution/stepResolvers.js.map +1 -0
  110. package/dist/modules/execution/tester-infra.logic.d.ts +42 -0
  111. package/dist/modules/execution/tester-infra.logic.d.ts.map +1 -0
  112. package/dist/modules/execution/tester-infra.logic.js +46 -0
  113. package/dist/modules/execution/tester-infra.logic.js.map +1 -0
  114. package/dist/modules/merge/MergePresetService.d.ts +32 -0
  115. package/dist/modules/merge/MergePresetService.d.ts.map +1 -0
  116. package/dist/modules/merge/MergePresetService.js +109 -0
  117. package/dist/modules/merge/MergePresetService.js.map +1 -0
  118. package/dist/modules/modelDefaults/ModelDefaultsService.d.ts +22 -0
  119. package/dist/modules/modelDefaults/ModelDefaultsService.d.ts.map +1 -0
  120. package/dist/modules/modelDefaults/ModelDefaultsService.js +28 -0
  121. package/dist/modules/modelDefaults/ModelDefaultsService.js.map +1 -0
  122. package/dist/modules/notifications/NotificationService.d.ts +74 -0
  123. package/dist/modules/notifications/NotificationService.d.ts.map +1 -0
  124. package/dist/modules/notifications/NotificationService.js +131 -0
  125. package/dist/modules/notifications/NotificationService.js.map +1 -0
  126. package/dist/modules/observability/LlmObservabilityService.d.ts +121 -0
  127. package/dist/modules/observability/LlmObservabilityService.d.ts.map +1 -0
  128. package/dist/modules/observability/LlmObservabilityService.js +140 -0
  129. package/dist/modules/observability/LlmObservabilityService.js.map +1 -0
  130. package/dist/modules/observability/observability.logic.d.ts +57 -0
  131. package/dist/modules/observability/observability.logic.d.ts.map +1 -0
  132. package/dist/modules/observability/observability.logic.js +186 -0
  133. package/dist/modules/observability/observability.logic.js.map +1 -0
  134. package/dist/modules/pipelines/PipelineService.d.ts +54 -0
  135. package/dist/modules/pipelines/PipelineService.d.ts.map +1 -0
  136. package/dist/modules/pipelines/PipelineService.js +226 -0
  137. package/dist/modules/pipelines/PipelineService.js.map +1 -0
  138. package/dist/modules/pipelines/pipelineShape.d.ts +53 -0
  139. package/dist/modules/pipelines/pipelineShape.d.ts.map +1 -0
  140. package/dist/modules/pipelines/pipelineShape.js +74 -0
  141. package/dist/modules/pipelines/pipelineShape.js.map +1 -0
  142. package/dist/modules/recurring/RecurringPipelineService.d.ts +76 -0
  143. package/dist/modules/recurring/RecurringPipelineService.d.ts.map +1 -0
  144. package/dist/modules/recurring/RecurringPipelineService.js +295 -0
  145. package/dist/modules/recurring/RecurringPipelineService.js.map +1 -0
  146. package/dist/modules/recurring/TrackerSettingsService.d.ts +16 -0
  147. package/dist/modules/recurring/TrackerSettingsService.d.ts.map +1 -0
  148. package/dist/modules/recurring/TrackerSettingsService.js +30 -0
  149. package/dist/modules/recurring/TrackerSettingsService.js.map +1 -0
  150. package/dist/modules/recurring/schedule.logic.d.ts +14 -0
  151. package/dist/modules/recurring/schedule.logic.d.ts.map +1 -0
  152. package/dist/modules/recurring/schedule.logic.js +85 -0
  153. package/dist/modules/recurring/schedule.logic.js.map +1 -0
  154. package/dist/modules/releaseHealth/ReleaseHealthService.d.ts +38 -0
  155. package/dist/modules/releaseHealth/ReleaseHealthService.d.ts.map +1 -0
  156. package/dist/modules/releaseHealth/ReleaseHealthService.js +96 -0
  157. package/dist/modules/releaseHealth/ReleaseHealthService.js.map +1 -0
  158. package/dist/modules/requirements/RequirementReviewService.d.ts +48 -0
  159. package/dist/modules/requirements/RequirementReviewService.d.ts.map +1 -0
  160. package/dist/modules/requirements/RequirementReviewService.js +83 -0
  161. package/dist/modules/requirements/RequirementReviewService.js.map +1 -0
  162. package/dist/modules/requirements/requirements.logic.d.ts +93 -0
  163. package/dist/modules/requirements/requirements.logic.d.ts.map +1 -0
  164. package/dist/modules/requirements/requirements.logic.js +203 -0
  165. package/dist/modules/requirements/requirements.logic.js.map +1 -0
  166. package/dist/modules/review/IterativeReviewService.d.ts +175 -0
  167. package/dist/modules/review/IterativeReviewService.d.ts.map +1 -0
  168. package/dist/modules/review/IterativeReviewService.js +327 -0
  169. package/dist/modules/review/IterativeReviewService.js.map +1 -0
  170. package/dist/modules/serviceFragmentDefaults/ServiceFragmentDefaultsService.d.ts +20 -0
  171. package/dist/modules/serviceFragmentDefaults/ServiceFragmentDefaultsService.d.ts.map +1 -0
  172. package/dist/modules/serviceFragmentDefaults/ServiceFragmentDefaultsService.js +26 -0
  173. package/dist/modules/serviceFragmentDefaults/ServiceFragmentDefaultsService.js.map +1 -0
  174. package/dist/modules/services/ServiceMountService.d.ts +48 -0
  175. package/dist/modules/services/ServiceMountService.d.ts.map +1 -0
  176. package/dist/modules/services/ServiceMountService.js +90 -0
  177. package/dist/modules/services/ServiceMountService.js.map +1 -0
  178. package/dist/modules/settings/WorkspaceSettingsService.d.ts +22 -0
  179. package/dist/modules/settings/WorkspaceSettingsService.d.ts.map +1 -0
  180. package/dist/modules/settings/WorkspaceSettingsService.js +50 -0
  181. package/dist/modules/settings/WorkspaceSettingsService.js.map +1 -0
  182. package/package.json +41 -0
@@ -0,0 +1,496 @@
1
+ import { assertFound, ValidationError } from '@cat-factory/kernel';
2
+ import { BLOCK_TYPE_LABEL } from '@cat-factory/kernel';
3
+ import { registerServiceForFrame, requireWorkspace } from '@cat-factory/kernel';
4
+ import { canReparent, descendantIds, gridSlot, serviceOf, tasksOf } from './board.logic.js';
5
+ /**
6
+ * Board mutations: frames, modules, tasks and the dependency edges between them.
7
+ * Mirrors the operations the frontend's board store performs locally, but
8
+ * against the persistence ports. Each method loads only what it needs, applies
9
+ * the pure board logic, then writes back.
10
+ */
11
+ export class BoardService {
12
+ workspaceRepository;
13
+ blockRepository;
14
+ executionRepository;
15
+ idGenerator;
16
+ clock;
17
+ repoProjectionRepository;
18
+ serviceRepository;
19
+ workspaceMountRepository;
20
+ serviceFragmentDefaultsRepository;
21
+ constructor({ workspaceRepository, blockRepository, executionRepository, idGenerator, clock, repoProjectionRepository, serviceRepository, workspaceMountRepository, serviceFragmentDefaultsRepository, }) {
22
+ this.workspaceRepository = workspaceRepository;
23
+ this.blockRepository = blockRepository;
24
+ this.executionRepository = executionRepository;
25
+ this.idGenerator = idGenerator;
26
+ this.clock = clock;
27
+ this.repoProjectionRepository = repoProjectionRepository;
28
+ this.serviceRepository = serviceRepository;
29
+ this.workspaceMountRepository = workspaceMountRepository;
30
+ this.serviceFragmentDefaultsRepository = serviceFragmentDefaultsRepository;
31
+ }
32
+ /**
33
+ * The workspace's default service-fragment selection that a NEW service frame
34
+ * inherits. Empty when the defaults repo isn't wired or none is set; never throws so
35
+ * frame creation isn't blocked by a defaults read.
36
+ */
37
+ async defaultServiceFragmentIds(workspaceId) {
38
+ if (!this.serviceFragmentDefaultsRepository)
39
+ return [];
40
+ try {
41
+ return await this.serviceFragmentDefaultsRepository.get(workspaceId);
42
+ }
43
+ catch {
44
+ return [];
45
+ }
46
+ }
47
+ /**
48
+ * Register a newly created top-level frame as an account-owned service and mount it
49
+ * onto the creating workspace (in-org sharing). Returns the new service id so the
50
+ * frame block can be stamped with it (the block is `listByService`-discoverable on
51
+ * every workspace that mounts the service). The frame's board position is carried on
52
+ * the mount (the per-workspace layout override). No-op (returns undefined) when the
53
+ * service repositories aren't wired.
54
+ */
55
+ registerService(workspaceId, frame, repo) {
56
+ return registerServiceForFrame({
57
+ serviceRepository: this.serviceRepository,
58
+ workspaceMountRepository: this.workspaceMountRepository,
59
+ workspaceRepository: this.workspaceRepository,
60
+ idGenerator: this.idGenerator,
61
+ clock: this.clock,
62
+ }, workspaceId, frame, repo);
63
+ }
64
+ /**
65
+ * The service id a block being added under `container` belongs to: the service of the
66
+ * container's enclosing frame. Undefined when the service repos aren't wired or the
67
+ * frame isn't a registered service (legacy/seeded frame) — the block is then plain
68
+ * workspace-local.
69
+ */
70
+ async serviceForContainer(blocks, container) {
71
+ if (!this.serviceRepository)
72
+ return undefined;
73
+ const frame = container.level === 'frame' ? container : serviceOf(blocks, container);
74
+ if (!frame)
75
+ return undefined;
76
+ return (await this.serviceRepository.getByFrameBlock(frame.id))?.id;
77
+ }
78
+ requireWorkspace(workspaceId) {
79
+ return requireWorkspace(this.workspaceRepository, workspaceId);
80
+ }
81
+ /**
82
+ * Resolve a block the requesting workspace is allowed to mutate, returning the block plus
83
+ * the workspace that physically homes it. A block created locally resolves to this
84
+ * workspace; a block belonging to a service this workspace MOUNTS (in-org sharing) resolves
85
+ * to the service's home workspace, so a shared board is fully interactive — edits, moves,
86
+ * adds and deletes act on the one shared copy. Throws NotFound when the workspace neither
87
+ * homes the block nor mounts its service (or sharing isn't wired and it isn't local).
88
+ */
89
+ async resolveBlock(workspaceId, id) {
90
+ const local = await this.blockRepository.get(workspaceId, id);
91
+ if (local)
92
+ return { homeWorkspaceId: workspaceId, block: local };
93
+ if (this.serviceRepository && this.workspaceMountRepository) {
94
+ const found = await this.blockRepository.findById(id);
95
+ if (found?.serviceId &&
96
+ (await this.workspaceMountRepository.get(workspaceId, found.serviceId))) {
97
+ return { homeWorkspaceId: found.workspaceId, block: found.block };
98
+ }
99
+ }
100
+ return assertFound(null, 'Block', id);
101
+ }
102
+ /**
103
+ * Resolve the home workspace to run a {@link removeBlock} against. Deletion is idempotent and
104
+ * best-effort, so unlike {@link resolveBlock} this NEVER 404s: a block local to this workspace
105
+ * resolves here; a block belonging to a service this workspace mounts resolves to that service's
106
+ * home (so a shared frame is deleted from any board that mounts it); anything else — a block row
107
+ * that's already gone, or one only another (un-mounted) workspace can see — resolves to THIS
108
+ * workspace, where the caller mops up whatever related rows survive. Every cleanup the caller
109
+ * does is scoped to the returned workspace, so falling back here can only ever touch this
110
+ * workspace's data, never reach across into another's.
111
+ */
112
+ async resolveBlockHomeForRemoval(workspaceId, id) {
113
+ const local = await this.blockRepository.get(workspaceId, id);
114
+ if (local)
115
+ return workspaceId;
116
+ if (this.serviceRepository && this.workspaceMountRepository) {
117
+ const found = await this.blockRepository.findById(id);
118
+ if (found?.serviceId &&
119
+ (await this.workspaceMountRepository.get(workspaceId, found.serviceId))) {
120
+ return found.workspaceId;
121
+ }
122
+ }
123
+ return workspaceId;
124
+ }
125
+ /** Add a top-level frame (service/api/database/…) to the board. */
126
+ async addFrame(workspaceId, input) {
127
+ await this.requireWorkspace(workspaceId);
128
+ const blocks = await this.blockRepository.listByWorkspace(workspaceId);
129
+ const type = input.type;
130
+ const count = blocks.filter((b) => b.type === type).length + 1;
131
+ const serviceFragmentIds = await this.defaultServiceFragmentIds(workspaceId);
132
+ const block = {
133
+ id: this.idGenerator.next('blk'),
134
+ title: `${BLOCK_TYPE_LABEL[type]} ${count}`,
135
+ type,
136
+ description: 'Newly dropped building block. Drag a pipeline onto it to start.',
137
+ position: input.position,
138
+ status: 'planned',
139
+ progress: 0,
140
+ dependsOn: [],
141
+ executionId: null,
142
+ level: 'frame',
143
+ parentId: null,
144
+ ...(serviceFragmentIds.length ? { serviceFragmentIds } : {}),
145
+ };
146
+ const serviceId = await this.registerService(workspaceId, block);
147
+ await this.blockRepository.insert(workspaceId, block, serviceId);
148
+ return block;
149
+ }
150
+ /**
151
+ * Add a service frame backed by an existing GitHub repo the workspace already
152
+ * links (the App is installed and the repo is projected). No container / agent
153
+ * run — the frame is created `ready`, titled after the repo, and the repo
154
+ * projection row is linked to it so execution resolves this repo for tasks
155
+ * dropped on the frame. The frontend's drag-drop path uses {@link addFrame};
156
+ * this is the "import an existing repo as a service" button.
157
+ */
158
+ async addServiceFromRepo(workspaceId, input) {
159
+ await this.requireWorkspace(workspaceId);
160
+ if (!this.repoProjectionRepository) {
161
+ throw new ValidationError('GitHub integration is not configured');
162
+ }
163
+ const repo = assertFound(await this.repoProjectionRepository.get(workspaceId, input.repoGithubId), 'GitHubRepo', String(input.repoGithubId));
164
+ // The monorepo flag is sent with the add request (no separate up-front PATCH).
165
+ // Persist it when provided so it sticks for subsequent adds + the repo picker, then
166
+ // proceed with the guards below reading the now-current flag.
167
+ if (input.isMonorepo !== undefined && input.isMonorepo !== repo.isMonorepo) {
168
+ await this.repoProjectionRepository.setMonorepo(workspaceId, repo.githubId, input.isMonorepo);
169
+ repo.isMonorepo = input.isMonorepo;
170
+ }
171
+ // Normalise the requested service subdirectory to a clean, SAFE relative path:
172
+ // strip slashes/`.` and reject any `..` segment, so a stored directory can never
173
+ // point an agent's cwd outside the checkout (the harness enforces the same — this
174
+ // is defence in depth, and surfaces a clean error before the row is written).
175
+ const directory = normalizeServiceDirectory(input.directory);
176
+ // A monorepo can back SEVERAL service frames (one per subdirectory), so the
177
+ // single-service guard applies only to whole-repo (non-monorepo) repos. A monorepo
178
+ // service MUST name its subdirectory so execution can scope agents to it.
179
+ if (repo.blockId && !repo.isMonorepo) {
180
+ throw new ValidationError('This repository is already linked to a board service');
181
+ }
182
+ if (repo.isMonorepo && !directory) {
183
+ throw new ValidationError('Select a service directory for this monorepo');
184
+ }
185
+ const blocks = await this.blockRepository.listByWorkspace(workspaceId);
186
+ // Each subdirectory of a monorepo backs at most one service — reject a duplicate so
187
+ // two frames don't fight over the same subtree (each resolves to the same repo+dir).
188
+ if (repo.isMonorepo && directory && this.serviceRepository) {
189
+ for (const frame of blocks.filter((b) => b.level === 'frame')) {
190
+ const existing = await this.serviceRepository.getByFrameBlock(frame.id);
191
+ if (existing?.repoGithubId === repo.githubId && existing.directory === directory) {
192
+ throw new ValidationError(`A service for '${directory}' already exists in this repository`);
193
+ }
194
+ }
195
+ }
196
+ const frames = blocks.filter((b) => b.level === 'frame').length;
197
+ const title = directory ? (directory.split('/').pop() ?? repo.name) : repo.name;
198
+ const serviceFragmentIds = await this.defaultServiceFragmentIds(workspaceId);
199
+ const block = {
200
+ id: this.idGenerator.next('blk'),
201
+ title,
202
+ type: 'service',
203
+ description: directory
204
+ ? `Service backed by ${repo.owner}/${repo.name} (${directory}/).`
205
+ : `Service backed by ${repo.owner}/${repo.name}.`,
206
+ position: input.position ?? { x: 80 + (frames % 5) * 48, y: 80 + (frames % 5) * 48 },
207
+ status: 'ready',
208
+ progress: 0,
209
+ dependsOn: [],
210
+ executionId: null,
211
+ level: 'frame',
212
+ parentId: null,
213
+ ...(serviceFragmentIds.length ? { serviceFragmentIds } : {}),
214
+ };
215
+ const serviceId = await this.registerService(workspaceId, block, {
216
+ installationId: repo.installationId,
217
+ githubId: repo.githubId,
218
+ directory: directory ?? null,
219
+ });
220
+ await this.blockRepository.insert(workspaceId, block, serviceId);
221
+ // A monorepo's repo backs several frames, so the projection's single `block_id`
222
+ // link can't represent it — the Service mapping (read by resolveRepoTarget) is
223
+ // authoritative there. Keep the legacy link only for a whole-repo service.
224
+ if (!repo.isMonorepo) {
225
+ await this.repoProjectionRepository.linkBlock(workspaceId, repo.githubId, block.id);
226
+ }
227
+ return block;
228
+ }
229
+ /** Add a task inside a container (a service frame or a module). */
230
+ async addTask(workspaceId, containerId, input, createdBy) {
231
+ await this.requireWorkspace(workspaceId);
232
+ // The container may be a frame/module of a service mounted from another workspace; create
233
+ // the task in that service's home workspace so it joins the one shared subtree.
234
+ const { homeWorkspaceId, block: container } = await this.resolveBlock(workspaceId, containerId);
235
+ if (container.level === 'task') {
236
+ throw new ValidationError('Tasks cannot contain other tasks');
237
+ }
238
+ const blocks = await this.blockRepository.listByWorkspace(homeWorkspaceId);
239
+ const siblings = tasksOf(blocks, containerId).length;
240
+ const service = serviceOf(blocks, container);
241
+ const block = {
242
+ id: this.idGenerator.next('task'),
243
+ title: input.title.trim(),
244
+ type: service?.type ?? container.type,
245
+ description: input.description?.trim() ?? '',
246
+ position: gridSlot(siblings),
247
+ status: 'planned',
248
+ progress: 0,
249
+ dependsOn: [],
250
+ executionId: null,
251
+ level: 'task',
252
+ parentId: containerId,
253
+ // The kind of work, chosen on the create form; defaults to a feature task.
254
+ taskType: input.taskType ?? 'feature',
255
+ };
256
+ // Small per-type form fields (bug severity / repro, spike timebox, …), when given.
257
+ if (input.taskTypeFields && Object.keys(input.taskTypeFields).length) {
258
+ block.taskTypeFields = input.taskTypeFields;
259
+ }
260
+ // The signed-in user who created the task, for "notify the task creator"
261
+ // notification routing. Null with auth disabled (local/dev).
262
+ if (createdBy != null)
263
+ block.createdBy = createdBy;
264
+ // Optional run configuration chosen at creation: which merge policy governs the
265
+ // task's auto-merge, and the pipeline its Run controls default to. Empty strings
266
+ // are treated as "not set" (workspace default preset / no pinned pipeline).
267
+ if (input.mergePresetId)
268
+ block.mergePresetId = input.mergePresetId;
269
+ if (input.pipelineId)
270
+ block.pipelineId = input.pipelineId;
271
+ // Task-level agent-contributed config values (e.g. the Tester's environment),
272
+ // chosen on the creation form from the selected pipeline's contributing agents.
273
+ if (input.agentConfig && Object.keys(input.agentConfig).length) {
274
+ block.agentConfig = input.agentConfig;
275
+ }
276
+ await this.blockRepository.insert(homeWorkspaceId, block, await this.serviceForContainer(blocks, container));
277
+ return block;
278
+ }
279
+ /** Add a module (sub-frame) inside a service. */
280
+ async addModule(workspaceId, serviceId, input) {
281
+ await this.requireWorkspace(workspaceId);
282
+ // The service frame may be mounted from another workspace; create the module in its home.
283
+ const { homeWorkspaceId, block: service } = await this.resolveBlock(workspaceId, serviceId);
284
+ if (service.level !== 'frame') {
285
+ throw new ValidationError('Modules can only be added to a service frame');
286
+ }
287
+ const blocks = await this.blockRepository.listByWorkspace(homeWorkspaceId);
288
+ const n = blocks.filter((b) => b.parentId === serviceId && b.level === 'module').length;
289
+ const block = {
290
+ id: this.idGenerator.next('mod'),
291
+ title: input.name,
292
+ type: service.type,
293
+ description: `Module within ${service.title}.`,
294
+ position: input.position ?? gridSlot(n, 2, 280, 220, 24, 80),
295
+ status: 'planned',
296
+ progress: 0,
297
+ dependsOn: [],
298
+ executionId: null,
299
+ level: 'module',
300
+ parentId: serviceId,
301
+ };
302
+ await this.blockRepository.insert(homeWorkspaceId, block, await this.serviceForContainer(blocks, service));
303
+ return block;
304
+ }
305
+ async moveBlock(workspaceId, id, position) {
306
+ await this.requireWorkspace(workspaceId);
307
+ const { homeWorkspaceId, block } = await this.resolveBlock(workspaceId, id);
308
+ // A service frame's board position is a PER-WORKSPACE layout override carried on the mount
309
+ // (the snapshot renders frames from the mount, so the same shared frame can sit at a
310
+ // different spot on each board). Write it onto THIS workspace's mount — for a home frame as
311
+ // much as one mounted from elsewhere — and leave the shared block untouched.
312
+ if (block.level === 'frame' && this.serviceRepository && this.workspaceMountRepository) {
313
+ const service = await this.serviceRepository.getByFrameBlock(id);
314
+ if (service && (await this.workspaceMountRepository.get(workspaceId, service.id))) {
315
+ await this.workspaceMountRepository.update(workspaceId, service.id, { position });
316
+ return { ...block, position };
317
+ }
318
+ }
319
+ // A non-frame block, or a legacy frame with no mount: move the shared block at its home.
320
+ await this.blockRepository.update(homeWorkspaceId, id, { position });
321
+ return assertFound(await this.blockRepository.get(homeWorkspaceId, id), 'Block', id);
322
+ }
323
+ async updateBlock(workspaceId, id, patch) {
324
+ await this.requireWorkspace(workspaceId);
325
+ const { homeWorkspaceId, block } = await this.resolveBlock(workspaceId, id);
326
+ // `serviceFragmentIds` is a service-level (frame) setting the engine only reads off
327
+ // the owning service frame; ignore it on non-frame blocks so it never persists as
328
+ // dead data (the inspector only exposes the picker on frames anyway).
329
+ let effective = patch;
330
+ if (patch.serviceFragmentIds !== undefined && block.level !== 'frame') {
331
+ const { serviceFragmentIds: _ignored, ...rest } = patch;
332
+ effective = rest;
333
+ }
334
+ await this.blockRepository.update(homeWorkspaceId, id, effective);
335
+ return assertFound(await this.blockRepository.get(homeWorkspaceId, id), 'Block', id);
336
+ }
337
+ /** Move a block into a new container at a new local position. */
338
+ async reparent(workspaceId, id, input) {
339
+ await this.requireWorkspace(workspaceId);
340
+ const { homeWorkspaceId: blockHome, block } = await this.resolveBlock(workspaceId, id);
341
+ if (id === input.parentId)
342
+ throw new ValidationError('A block cannot contain itself');
343
+ const { homeWorkspaceId: parentHome, block: parent } = await this.resolveBlock(workspaceId, input.parentId);
344
+ if (!canReparent(block.level, parent)) {
345
+ throw new ValidationError(`A ${block.level} cannot be placed inside a ${parent.level}`);
346
+ }
347
+ // Same physical home (the common case, incl. two of the workspace's own services): move in
348
+ // place and re-stamp `service_id`, the physical scope key that decides which boards render
349
+ // the subtree and where its events fan out. No-op re-stamp when sharing isn't wired or the
350
+ // destination frame isn't a registered service.
351
+ if (blockHome === parentHome) {
352
+ await this.blockRepository.update(blockHome, id, {
353
+ parentId: input.parentId,
354
+ position: input.position,
355
+ });
356
+ if (this.serviceRepository) {
357
+ const blocks = await this.blockRepository.listByWorkspace(blockHome);
358
+ const destService = await this.serviceForContainer(blocks, parent);
359
+ await this.blockRepository.setService(blockHome, [...descendantIds(blocks, id)], destService ?? null);
360
+ }
361
+ return assertFound(await this.blockRepository.get(blockHome, id), 'Block', id);
362
+ }
363
+ // Cross-home: the block and its new parent belong to two services homed in different
364
+ // workspaces (both mounted on this board). Keep the invariant that a service's blocks live
365
+ // in its home workspace by MOVING the subtree's rows — and any executions on them — to the
366
+ // destination service's home, re-stamped with the destination service.
367
+ const srcBlocks = await this.blockRepository.listByWorkspace(blockHome);
368
+ const ids = [...descendantIds(srcBlocks, id)];
369
+ const subtree = ids
370
+ .map((bid) => srcBlocks.find((b) => b.id === bid))
371
+ .filter((b) => b !== undefined);
372
+ const parentBlocks = await this.blockRepository.listByWorkspace(parentHome);
373
+ const destService = (await this.serviceForContainer(parentBlocks, parent)) ?? null;
374
+ for (const b of subtree) {
375
+ const moved = b.id === id ? { ...b, parentId: input.parentId, position: input.position } : b;
376
+ await this.blockRepository.insert(parentHome, moved, destService);
377
+ const exec = await this.executionRepository.getByBlock(blockHome, b.id);
378
+ if (exec) {
379
+ await this.executionRepository.deleteByBlock(blockHome, b.id);
380
+ await this.executionRepository.upsert(parentHome, exec);
381
+ }
382
+ }
383
+ await this.blockRepository.deleteMany(blockHome, ids);
384
+ // Drop dependency edges in the source workspace that now dangle to the moved subtree.
385
+ const moved = new Set(ids);
386
+ for (const b of srcBlocks) {
387
+ if (moved.has(b.id))
388
+ continue;
389
+ const next = b.dependsOn.filter((d) => !moved.has(d));
390
+ if (next.length !== b.dependsOn.length) {
391
+ await this.blockRepository.update(blockHome, b.id, { dependsOn: next });
392
+ }
393
+ }
394
+ return assertFound(await this.blockRepository.get(parentHome, id), 'Block', id);
395
+ }
396
+ /** Delete a block and all its descendants, dropping dangling dependencies. */
397
+ async removeBlock(workspaceId, id) {
398
+ await this.requireWorkspace(workspaceId);
399
+ // Resolve the block at its home so a shared service's block can be deleted from any board
400
+ // that mounts it (the delete then applies to the one shared copy everywhere). Deletion is
401
+ // best-effort and idempotent: if the block row is already GONE (e.g. a half-deleted service
402
+ // that left a dangling mount/repo-link/execution), we must NOT 404 — a thing not existing
403
+ // can't be allowed to block cleanup of the related entities that do still exist. The resolve
404
+ // never throws; it falls back to this workspace, and every cleanup below is scoped to that
405
+ // home, so we tear down whatever references the id (+ its surviving descendants) without ever
406
+ // touching another workspace's data.
407
+ const homeWorkspaceId = await this.resolveBlockHomeForRemoval(workspaceId, id);
408
+ const blocks = await this.blockRepository.listByWorkspace(homeWorkspaceId);
409
+ const doomed = descendantIds(blocks, id);
410
+ await this.executionRepository.deleteByBlock(homeWorkspaceId, id);
411
+ // Unlink any repo backing a doomed service frame so the repo becomes
412
+ // addable again (otherwise its github_repos.block_id dangles to a deleted
413
+ // block: the repo shows "already on board" yet nothing renders it).
414
+ if (this.repoProjectionRepository) {
415
+ const repos = await this.repoProjectionRepository.list(homeWorkspaceId);
416
+ for (const repo of repos) {
417
+ if (repo.blockId && doomed.has(repo.blockId)) {
418
+ await this.repoProjectionRepository.linkBlock(homeWorkspaceId, repo.githubId, null);
419
+ }
420
+ }
421
+ }
422
+ // Drop the account-owned service (and every workspace's mount of it) for any doomed
423
+ // service frame, so deleting a frame doesn't leave an orphaned service lingering in the
424
+ // org catalog (mountable, badged, yet rendering nothing) on other boards.
425
+ if (this.serviceRepository && this.workspaceMountRepository) {
426
+ const doomedServiceIds = new Set();
427
+ for (const b of blocks) {
428
+ if (!doomed.has(b.id) || b.level !== 'frame' || b.parentId !== null)
429
+ continue;
430
+ const service = await this.serviceRepository.getByFrameBlock(b.id);
431
+ if (service)
432
+ doomedServiceIds.add(service.id);
433
+ }
434
+ // The frame block may already be gone (the dangling case), so it isn't in `blocks` above —
435
+ // look the service up directly by the deleted id too, so the orphaned service + its mounts
436
+ // are still reclaimed rather than lingering in the org catalog forever.
437
+ const danglingService = await this.serviceRepository.getByFrameBlock(id);
438
+ if (danglingService)
439
+ doomedServiceIds.add(danglingService.id);
440
+ if (doomedServiceIds.size > 0) {
441
+ // Batched: clear every board's mount of the doomed services, then delete the services
442
+ // (two queries, not a listByService + per-mount remove + per-service delete loop).
443
+ const ids = [...doomedServiceIds];
444
+ await this.workspaceMountRepository.removeByServices(ids);
445
+ await this.serviceRepository.deleteMany(ids);
446
+ }
447
+ }
448
+ await this.blockRepository.deleteMany(homeWorkspaceId, [...doomed]);
449
+ for (const b of blocks) {
450
+ if (doomed.has(b.id))
451
+ continue;
452
+ const next = b.dependsOn.filter((d) => !doomed.has(d));
453
+ if (next.length !== b.dependsOn.length) {
454
+ await this.blockRepository.update(homeWorkspaceId, b.id, { dependsOn: next });
455
+ }
456
+ }
457
+ }
458
+ /** Toggle a dependency edge: target dependsOn source. */
459
+ async toggleDependency(workspaceId, targetId, sourceId) {
460
+ await this.requireWorkspace(workspaceId);
461
+ if (targetId === sourceId) {
462
+ throw new ValidationError('A block cannot depend on itself');
463
+ }
464
+ const { homeWorkspaceId, block: target } = await this.resolveBlock(workspaceId, targetId);
465
+ // The source need only be visible to this board (it may be homed elsewhere); the edge is
466
+ // stored as an id on the target, which lives at `homeWorkspaceId`.
467
+ await this.resolveBlock(workspaceId, sourceId);
468
+ const i = target.dependsOn.indexOf(sourceId);
469
+ const next = i >= 0 ? target.dependsOn.filter((d) => d !== sourceId) : [...target.dependsOn, sourceId];
470
+ await this.blockRepository.update(homeWorkspaceId, targetId, { dependsOn: next });
471
+ return assertFound(await this.blockRepository.get(homeWorkspaceId, targetId), 'Block', targetId);
472
+ }
473
+ }
474
+ /**
475
+ * Coerce a user-supplied monorepo service subdirectory into a clean, SAFE relative path
476
+ * (or undefined when absent/empty): normalise separators, drop `.`/empty segments, and
477
+ * reject any `..` segment or absolute path so the stored value can never escape the repo
478
+ * checkout when it later becomes an agent's cwd. Mirrors the harness's `sanitizeService
479
+ * Directory`, kept here so a bad value is rejected before the service row is written.
480
+ */
481
+ export function normalizeServiceDirectory(raw) {
482
+ if (!raw)
483
+ return undefined;
484
+ const segments = raw
485
+ .trim()
486
+ .replace(/\\/g, '/')
487
+ .split('/')
488
+ .filter((s) => s !== '' && s !== '.');
489
+ if (segments.length === 0)
490
+ return undefined;
491
+ if (segments.some((s) => s === '..')) {
492
+ throw new ValidationError('Service directory must be a path inside the repository');
493
+ }
494
+ return segments.join('/');
495
+ }
496
+ //# sourceMappingURL=BoardService.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"BoardService.js","sourceRoot":"","sources":["../../../src/modules/board/BoardService.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,17 @@
1
+ import type { Block, BlockLevel, Position } from '@cat-factory/kernel';
2
+ /** Simple grid layout for the Nth child inside a container. */
3
+ export declare function gridSlot(n: number, cols?: number, cw?: number, ch?: number, x0?: number, y0?: number): Position;
4
+ /** Tasks directly inside a container (a service or a module). */
5
+ export declare function tasksOf(blocks: Block[], containerId: string): Block[];
6
+ /** Modules (sub-frames) inside a service. */
7
+ export declare function modulesOf(blocks: Block[], serviceId: string): Block[];
8
+ /** The top-level service a block ultimately belongs to. */
9
+ export declare function serviceOf(blocks: Block[], block: Block): Block | undefined;
10
+ /**
11
+ * Every descendant id of `rootId` (tasks, modules and their tasks), including
12
+ * the root itself — used to cascade a delete.
13
+ */
14
+ export declare function descendantIds(blocks: Block[], rootId: string): Set<string>;
15
+ /** Whether `parent` is a legal container for a block at `childLevel`. */
16
+ export declare function canReparent(childLevel: BlockLevel, parent: Block): boolean;
17
+ //# sourceMappingURL=board.logic.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"board.logic.d.ts","sourceRoot":"","sources":["../../../src/modules/board/board.logic.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAA;AAMtE,+DAA+D;AAC/D,wBAAgB,QAAQ,CAAC,CAAC,EAAE,MAAM,EAAE,IAAI,SAAI,EAAE,EAAE,SAAM,EAAE,EAAE,SAAM,EAAE,EAAE,SAAK,EAAE,EAAE,SAAK,GAAG,QAAQ,CAE5F;AAED,iEAAiE;AACjE,wBAAgB,OAAO,CAAC,MAAM,EAAE,KAAK,EAAE,EAAE,WAAW,EAAE,MAAM,GAAG,KAAK,EAAE,CAErE;AAED,6CAA6C;AAC7C,wBAAgB,SAAS,CAAC,MAAM,EAAE,KAAK,EAAE,EAAE,SAAS,EAAE,MAAM,GAAG,KAAK,EAAE,CAErE;AAED,2DAA2D;AAC3D,wBAAgB,SAAS,CAAC,MAAM,EAAE,KAAK,EAAE,EAAE,KAAK,EAAE,KAAK,GAAG,KAAK,GAAG,SAAS,CAO1E;AAED;;;GAGG;AACH,wBAAgB,aAAa,CAAC,MAAM,EAAE,KAAK,EAAE,EAAE,MAAM,EAAE,MAAM,GAAG,GAAG,CAAC,MAAM,CAAC,CAa1E;AAED,yEAAyE;AACzE,wBAAgB,WAAW,CAAC,UAAU,EAAE,UAAU,EAAE,MAAM,EAAE,KAAK,GAAG,OAAO,CAI1E"}
@@ -0,0 +1,51 @@
1
+ // Pure board computations — no IO, no ports. They operate on plain in-memory
2
+ // block arrays so they can be exhaustively unit-tested and are reused verbatim
3
+ // by the BoardService and the execution engine.
4
+ /** Simple grid layout for the Nth child inside a container. */
5
+ export function gridSlot(n, cols = 2, cw = 200, ch = 170, x0 = 16, y0 = 12) {
6
+ return { x: x0 + (n % cols) * cw, y: y0 + Math.floor(n / cols) * ch };
7
+ }
8
+ /** Tasks directly inside a container (a service or a module). */
9
+ export function tasksOf(blocks, containerId) {
10
+ return blocks.filter((b) => b.parentId === containerId && b.level === 'task');
11
+ }
12
+ /** Modules (sub-frames) inside a service. */
13
+ export function modulesOf(blocks, serviceId) {
14
+ return blocks.filter((b) => b.parentId === serviceId && b.level === 'module');
15
+ }
16
+ /** The top-level service a block ultimately belongs to. */
17
+ export function serviceOf(blocks, block) {
18
+ const byId = new Map(blocks.map((b) => [b.id, b]));
19
+ let cur = block;
20
+ while (cur && cur.level !== 'frame') {
21
+ cur = cur.parentId ? byId.get(cur.parentId) : undefined;
22
+ }
23
+ return cur;
24
+ }
25
+ /**
26
+ * Every descendant id of `rootId` (tasks, modules and their tasks), including
27
+ * the root itself — used to cascade a delete.
28
+ */
29
+ export function descendantIds(blocks, rootId) {
30
+ const doomed = new Set([rootId]);
31
+ let grew = true;
32
+ while (grew) {
33
+ grew = false;
34
+ for (const b of blocks) {
35
+ if (b.parentId && doomed.has(b.parentId) && !doomed.has(b.id)) {
36
+ doomed.add(b.id);
37
+ grew = true;
38
+ }
39
+ }
40
+ }
41
+ return doomed;
42
+ }
43
+ /** Whether `parent` is a legal container for a block at `childLevel`. */
44
+ export function canReparent(childLevel, parent) {
45
+ if (childLevel === 'task')
46
+ return parent.level === 'frame' || parent.level === 'module';
47
+ if (childLevel === 'module')
48
+ return parent.level === 'frame';
49
+ return false; // frames are not nested
50
+ }
51
+ //# sourceMappingURL=board.logic.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"board.logic.js","sourceRoot":"","sources":["../../../src/modules/board/board.logic.ts"],"names":[],"mappings":"AAEA,6EAA6E;AAC7E,+EAA+E;AAC/E,gDAAgD;AAEhD,+DAA+D;AAC/D,MAAM,UAAU,QAAQ,CAAC,CAAS,EAAE,IAAI,GAAG,CAAC,EAAE,EAAE,GAAG,GAAG,EAAE,EAAE,GAAG,GAAG,EAAE,EAAE,GAAG,EAAE,EAAE,EAAE,GAAG,EAAE;IAChF,OAAO,EAAE,CAAC,EAAE,EAAE,GAAG,CAAC,CAAC,GAAG,IAAI,CAAC,GAAG,EAAE,EAAE,CAAC,EAAE,EAAE,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,GAAG,IAAI,CAAC,GAAG,EAAE,EAAE,CAAA;AACvE,CAAC;AAED,iEAAiE;AACjE,MAAM,UAAU,OAAO,CAAC,MAAe,EAAE,WAAmB;IAC1D,OAAO,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,KAAK,WAAW,IAAI,CAAC,CAAC,KAAK,KAAK,MAAM,CAAC,CAAA;AAC/E,CAAC;AAED,6CAA6C;AAC7C,MAAM,UAAU,SAAS,CAAC,MAAe,EAAE,SAAiB;IAC1D,OAAO,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,KAAK,SAAS,IAAI,CAAC,CAAC,KAAK,KAAK,QAAQ,CAAC,CAAA;AAC/E,CAAC;AAED,2DAA2D;AAC3D,MAAM,UAAU,SAAS,CAAC,MAAe,EAAE,KAAY;IACrD,MAAM,IAAI,GAAG,IAAI,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,CAAA;IAClD,IAAI,GAAG,GAAsB,KAAK,CAAA;IAClC,OAAO,GAAG,IAAI,GAAG,CAAC,KAAK,KAAK,OAAO,EAAE,CAAC;QACpC,GAAG,GAAG,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,SAAS,CAAA;IACzD,CAAC;IACD,OAAO,GAAG,CAAA;AACZ,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,aAAa,CAAC,MAAe,EAAE,MAAc;IAC3D,MAAM,MAAM,GAAG,IAAI,GAAG,CAAS,CAAC,MAAM,CAAC,CAAC,CAAA;IACxC,IAAI,IAAI,GAAG,IAAI,CAAA;IACf,OAAO,IAAI,EAAE,CAAC;QACZ,IAAI,GAAG,KAAK,CAAA;QACZ,KAAK,MAAM,CAAC,IAAI,MAAM,EAAE,CAAC;YACvB,IAAI,CAAC,CAAC,QAAQ,IAAI,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC;gBAC9D,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAA;gBAChB,IAAI,GAAG,IAAI,CAAA;YACb,CAAC;QACH,CAAC;IACH,CAAC;IACD,OAAO,MAAM,CAAA;AACf,CAAC;AAED,yEAAyE;AACzE,MAAM,UAAU,WAAW,CAAC,UAAsB,EAAE,MAAa;IAC/D,IAAI,UAAU,KAAK,MAAM;QAAE,OAAO,MAAM,CAAC,KAAK,KAAK,OAAO,IAAI,MAAM,CAAC,KAAK,KAAK,QAAQ,CAAA;IACvF,IAAI,UAAU,KAAK,QAAQ;QAAE,OAAO,MAAM,CAAC,KAAK,KAAK,OAAO,CAAA;IAC5D,OAAO,KAAK,CAAA,CAAC,wBAAwB;AACvC,CAAC"}
@@ -0,0 +1,35 @@
1
+ import type { BlueprintService, BoardScanSpawnResult } from '@cat-factory/kernel';
2
+ import type { BlockRepository } from '@cat-factory/kernel';
3
+ import type { BoardService } from '../board/BoardService.js';
4
+ export interface BoardScanServiceDependencies {
5
+ boardService: BoardService;
6
+ /** Read board blocks directly, to reconcile a blueprint onto an existing frame. */
7
+ blockRepository: BlockRepository;
8
+ }
9
+ export declare class BoardScanService {
10
+ private readonly deps;
11
+ constructor(deps: BoardScanServiceDependencies);
12
+ /**
13
+ * Materialise a blueprint onto the board: one service frame and a module per
14
+ * blueprint module — each carrying the node's summary and codebase references in
15
+ * its description, so the board mirrors the map. Tasks are authored by people, so
16
+ * the spawn never creates them. Used as the fallback when a reconcile target frame
17
+ * can't be resolved.
18
+ */
19
+ private spawnBlueprint;
20
+ /**
21
+ * Reconcile a blueprint onto an **existing** service frame, in place and without
22
+ * deleting anything: the frame's modules are matched to the blueprint by name
23
+ * (case-insensitive), missing modules are added, and matched modules have their
24
+ * summary/code-reference description refreshed. Human-added blocks and the tasks
25
+ * inside modules are left untouched — so re-running the Blueprinter after each
26
+ * implementation keeps the map current without clobbering authored work.
27
+ *
28
+ * When `frameId` does not resolve to a frame (e.g. the repo isn't on the board
29
+ * yet) it falls back to {@link spawnBlueprint}, creating a fresh structure.
30
+ */
31
+ reconcileBlueprint(workspaceId: string, frameId: string | null, service: BlueprintService): Promise<BoardScanSpawnResult>;
32
+ /** Convenience for callers/tests: the module count a blueprint implies. */
33
+ static moduleCount(service: BlueprintService): number;
34
+ }
35
+ //# sourceMappingURL=BoardScanService.d.ts.map