@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.
- package/LICENSE +21 -0
- package/dist/container.d.ts +460 -0
- package/dist/container.d.ts.map +1 -0
- package/dist/container.js +657 -0
- package/dist/container.js.map +1 -0
- package/dist/index.d.ts +29 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +31 -0
- package/dist/index.js.map +1 -0
- package/dist/modules/board/BoardService.d.ts +125 -0
- package/dist/modules/board/BoardService.d.ts.map +1 -0
- package/dist/modules/board/BoardService.js +496 -0
- package/dist/modules/board/BoardService.js.map +1 -0
- package/dist/modules/board/board.logic.d.ts +17 -0
- package/dist/modules/board/board.logic.d.ts.map +1 -0
- package/dist/modules/board/board.logic.js +51 -0
- package/dist/modules/board/board.logic.js.map +1 -0
- package/dist/modules/boardScan/BoardScanService.d.ts +35 -0
- package/dist/modules/boardScan/BoardScanService.d.ts.map +1 -0
- package/dist/modules/boardScan/BoardScanService.js +91 -0
- package/dist/modules/boardScan/BoardScanService.js.map +1 -0
- package/dist/modules/boardScan/board-scan.logic.d.ts +10 -0
- package/dist/modules/boardScan/board-scan.logic.d.ts.map +1 -0
- package/dist/modules/boardScan/board-scan.logic.js +26 -0
- package/dist/modules/boardScan/board-scan.logic.js.map +1 -0
- package/dist/modules/bootstrap/BootstrapService.d.ts +114 -0
- package/dist/modules/bootstrap/BootstrapService.d.ts.map +1 -0
- package/dist/modules/bootstrap/BootstrapService.js +516 -0
- package/dist/modules/bootstrap/BootstrapService.js.map +1 -0
- package/dist/modules/clarity/ClarityReviewService.d.ts +48 -0
- package/dist/modules/clarity/ClarityReviewService.d.ts.map +1 -0
- package/dist/modules/clarity/ClarityReviewService.js +63 -0
- package/dist/modules/clarity/ClarityReviewService.js.map +1 -0
- package/dist/modules/clarity/clarity.logic.d.ts +36 -0
- package/dist/modules/clarity/clarity.logic.d.ts.map +1 -0
- package/dist/modules/clarity/clarity.logic.js +98 -0
- package/dist/modules/clarity/clarity.logic.js.map +1 -0
- package/dist/modules/estimation/estimate.logic.d.ts +11 -0
- package/dist/modules/estimation/estimate.logic.d.ts.map +1 -0
- package/dist/modules/estimation/estimate.logic.js +37 -0
- package/dist/modules/estimation/estimate.logic.js.map +1 -0
- package/dist/modules/execution/AgentContextBuilder.d.ts +114 -0
- package/dist/modules/execution/AgentContextBuilder.d.ts.map +1 -0
- package/dist/modules/execution/AgentContextBuilder.js +316 -0
- package/dist/modules/execution/AgentContextBuilder.js.map +1 -0
- package/dist/modules/execution/CompanionController.d.ts +60 -0
- package/dist/modules/execution/CompanionController.d.ts.map +1 -0
- package/dist/modules/execution/CompanionController.js +216 -0
- package/dist/modules/execution/CompanionController.js.map +1 -0
- package/dist/modules/execution/ExecutionService.d.ts +874 -0
- package/dist/modules/execution/ExecutionService.d.ts.map +1 -0
- package/dist/modules/execution/ExecutionService.js +2921 -0
- package/dist/modules/execution/ExecutionService.js.map +1 -0
- package/dist/modules/execution/MergeResolver.d.ts +34 -0
- package/dist/modules/execution/MergeResolver.d.ts.map +1 -0
- package/dist/modules/execution/MergeResolver.js +81 -0
- package/dist/modules/execution/MergeResolver.js.map +1 -0
- package/dist/modules/execution/ReviewGateController.d.ts +163 -0
- package/dist/modules/execution/ReviewGateController.d.ts.map +1 -0
- package/dist/modules/execution/ReviewGateController.js +251 -0
- package/dist/modules/execution/ReviewGateController.js.map +1 -0
- package/dist/modules/execution/TesterController.d.ts +61 -0
- package/dist/modules/execution/TesterController.d.ts.map +1 -0
- package/dist/modules/execution/TesterController.js +215 -0
- package/dist/modules/execution/TesterController.js.map +1 -0
- package/dist/modules/execution/advance.d.ts +84 -0
- package/dist/modules/execution/advance.d.ts.map +1 -0
- package/dist/modules/execution/advance.js +2 -0
- package/dist/modules/execution/advance.js.map +1 -0
- package/dist/modules/execution/artifact-review.logic.d.ts +25 -0
- package/dist/modules/execution/artifact-review.logic.d.ts.map +1 -0
- package/dist/modules/execution/artifact-review.logic.js +39 -0
- package/dist/modules/execution/artifact-review.logic.js.map +1 -0
- package/dist/modules/execution/ci.logic.d.ts +101 -0
- package/dist/modules/execution/ci.logic.d.ts.map +1 -0
- package/dist/modules/execution/ci.logic.js +117 -0
- package/dist/modules/execution/ci.logic.js.map +1 -0
- package/dist/modules/execution/drive.d.ts +47 -0
- package/dist/modules/execution/drive.d.ts.map +1 -0
- package/dist/modules/execution/drive.js +112 -0
- package/dist/modules/execution/drive.js.map +1 -0
- package/dist/modules/execution/gates.d.ts +97 -0
- package/dist/modules/execution/gates.d.ts.map +1 -0
- package/dist/modules/execution/gates.js +2 -0
- package/dist/modules/execution/gates.js.map +1 -0
- package/dist/modules/execution/individualVendors.logic.d.ts +22 -0
- package/dist/modules/execution/individualVendors.logic.d.ts.map +1 -0
- package/dist/modules/execution/individualVendors.logic.js +33 -0
- package/dist/modules/execution/individualVendors.logic.js.map +1 -0
- package/dist/modules/execution/job.logic.d.ts +52 -0
- package/dist/modules/execution/job.logic.d.ts.map +1 -0
- package/dist/modules/execution/job.logic.js +56 -0
- package/dist/modules/execution/job.logic.js.map +1 -0
- package/dist/modules/execution/release.logic.d.ts +43 -0
- package/dist/modules/execution/release.logic.d.ts.map +1 -0
- package/dist/modules/execution/release.logic.js +49 -0
- package/dist/modules/execution/release.logic.js.map +1 -0
- package/dist/modules/execution/retry.logic.d.ts +40 -0
- package/dist/modules/execution/retry.logic.d.ts.map +1 -0
- package/dist/modules/execution/retry.logic.js +83 -0
- package/dist/modules/execution/retry.logic.js.map +1 -0
- package/dist/modules/execution/stepGating.logic.d.ts +15 -0
- package/dist/modules/execution/stepGating.logic.d.ts.map +1 -0
- package/dist/modules/execution/stepGating.logic.js +29 -0
- package/dist/modules/execution/stepGating.logic.js.map +1 -0
- package/dist/modules/execution/stepResolvers.d.ts +41 -0
- package/dist/modules/execution/stepResolvers.d.ts.map +1 -0
- package/dist/modules/execution/stepResolvers.js +2 -0
- package/dist/modules/execution/stepResolvers.js.map +1 -0
- package/dist/modules/execution/tester-infra.logic.d.ts +42 -0
- package/dist/modules/execution/tester-infra.logic.d.ts.map +1 -0
- package/dist/modules/execution/tester-infra.logic.js +46 -0
- package/dist/modules/execution/tester-infra.logic.js.map +1 -0
- package/dist/modules/merge/MergePresetService.d.ts +32 -0
- package/dist/modules/merge/MergePresetService.d.ts.map +1 -0
- package/dist/modules/merge/MergePresetService.js +109 -0
- package/dist/modules/merge/MergePresetService.js.map +1 -0
- package/dist/modules/modelDefaults/ModelDefaultsService.d.ts +22 -0
- package/dist/modules/modelDefaults/ModelDefaultsService.d.ts.map +1 -0
- package/dist/modules/modelDefaults/ModelDefaultsService.js +28 -0
- package/dist/modules/modelDefaults/ModelDefaultsService.js.map +1 -0
- package/dist/modules/notifications/NotificationService.d.ts +74 -0
- package/dist/modules/notifications/NotificationService.d.ts.map +1 -0
- package/dist/modules/notifications/NotificationService.js +131 -0
- package/dist/modules/notifications/NotificationService.js.map +1 -0
- package/dist/modules/observability/LlmObservabilityService.d.ts +121 -0
- package/dist/modules/observability/LlmObservabilityService.d.ts.map +1 -0
- package/dist/modules/observability/LlmObservabilityService.js +140 -0
- package/dist/modules/observability/LlmObservabilityService.js.map +1 -0
- package/dist/modules/observability/observability.logic.d.ts +57 -0
- package/dist/modules/observability/observability.logic.d.ts.map +1 -0
- package/dist/modules/observability/observability.logic.js +186 -0
- package/dist/modules/observability/observability.logic.js.map +1 -0
- package/dist/modules/pipelines/PipelineService.d.ts +54 -0
- package/dist/modules/pipelines/PipelineService.d.ts.map +1 -0
- package/dist/modules/pipelines/PipelineService.js +226 -0
- package/dist/modules/pipelines/PipelineService.js.map +1 -0
- package/dist/modules/pipelines/pipelineShape.d.ts +53 -0
- package/dist/modules/pipelines/pipelineShape.d.ts.map +1 -0
- package/dist/modules/pipelines/pipelineShape.js +74 -0
- package/dist/modules/pipelines/pipelineShape.js.map +1 -0
- package/dist/modules/recurring/RecurringPipelineService.d.ts +76 -0
- package/dist/modules/recurring/RecurringPipelineService.d.ts.map +1 -0
- package/dist/modules/recurring/RecurringPipelineService.js +295 -0
- package/dist/modules/recurring/RecurringPipelineService.js.map +1 -0
- package/dist/modules/recurring/TrackerSettingsService.d.ts +16 -0
- package/dist/modules/recurring/TrackerSettingsService.d.ts.map +1 -0
- package/dist/modules/recurring/TrackerSettingsService.js +30 -0
- package/dist/modules/recurring/TrackerSettingsService.js.map +1 -0
- package/dist/modules/recurring/schedule.logic.d.ts +14 -0
- package/dist/modules/recurring/schedule.logic.d.ts.map +1 -0
- package/dist/modules/recurring/schedule.logic.js +85 -0
- package/dist/modules/recurring/schedule.logic.js.map +1 -0
- package/dist/modules/releaseHealth/ReleaseHealthService.d.ts +38 -0
- package/dist/modules/releaseHealth/ReleaseHealthService.d.ts.map +1 -0
- package/dist/modules/releaseHealth/ReleaseHealthService.js +96 -0
- package/dist/modules/releaseHealth/ReleaseHealthService.js.map +1 -0
- package/dist/modules/requirements/RequirementReviewService.d.ts +48 -0
- package/dist/modules/requirements/RequirementReviewService.d.ts.map +1 -0
- package/dist/modules/requirements/RequirementReviewService.js +83 -0
- package/dist/modules/requirements/RequirementReviewService.js.map +1 -0
- package/dist/modules/requirements/requirements.logic.d.ts +93 -0
- package/dist/modules/requirements/requirements.logic.d.ts.map +1 -0
- package/dist/modules/requirements/requirements.logic.js +203 -0
- package/dist/modules/requirements/requirements.logic.js.map +1 -0
- package/dist/modules/review/IterativeReviewService.d.ts +175 -0
- package/dist/modules/review/IterativeReviewService.d.ts.map +1 -0
- package/dist/modules/review/IterativeReviewService.js +327 -0
- package/dist/modules/review/IterativeReviewService.js.map +1 -0
- package/dist/modules/serviceFragmentDefaults/ServiceFragmentDefaultsService.d.ts +20 -0
- package/dist/modules/serviceFragmentDefaults/ServiceFragmentDefaultsService.d.ts.map +1 -0
- package/dist/modules/serviceFragmentDefaults/ServiceFragmentDefaultsService.js +26 -0
- package/dist/modules/serviceFragmentDefaults/ServiceFragmentDefaultsService.js.map +1 -0
- package/dist/modules/services/ServiceMountService.d.ts +48 -0
- package/dist/modules/services/ServiceMountService.d.ts.map +1 -0
- package/dist/modules/services/ServiceMountService.js +90 -0
- package/dist/modules/services/ServiceMountService.js.map +1 -0
- package/dist/modules/settings/WorkspaceSettingsService.d.ts +22 -0
- package/dist/modules/settings/WorkspaceSettingsService.d.ts.map +1 -0
- package/dist/modules/settings/WorkspaceSettingsService.js +50 -0
- package/dist/modules/settings/WorkspaceSettingsService.js.map +1 -0
- 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
|