@bevel-software/platform-core-backend 0.8.0 → 0.9.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/core/core-ports.d.ts +7 -0
- package/dist/core/core-ports.d.ts.map +1 -1
- package/dist/core/core-ports.js.map +1 -1
- package/dist/core/create-core-server.d.ts.map +1 -1
- package/dist/core/create-core-server.js +24 -11
- package/dist/core/create-core-server.js.map +1 -1
- package/dist/core/create-core-services.d.ts +7 -2
- package/dist/core/create-core-services.d.ts.map +1 -1
- package/dist/core/create-core-services.js +39 -18
- package/dist/core/create-core-services.js.map +1 -1
- package/dist/modules/access/access.routes.d.ts +3 -1
- package/dist/modules/access/access.routes.d.ts.map +1 -1
- package/dist/modules/access/access.routes.js +4 -2
- package/dist/modules/access/access.routes.js.map +1 -1
- package/dist/modules/access/render-roles-yaml.d.ts +22 -0
- package/dist/modules/access/render-roles-yaml.d.ts.map +1 -0
- package/dist/modules/access/render-roles-yaml.js +56 -0
- package/dist/modules/access/render-roles-yaml.js.map +1 -0
- package/dist/modules/access/roles-admin.service.d.ts +15 -1
- package/dist/modules/access/roles-admin.service.d.ts.map +1 -1
- package/dist/modules/access/roles-admin.service.js +30 -15
- package/dist/modules/access/roles-admin.service.js.map +1 -1
- package/dist/modules/settings/setup.routes.d.ts +10 -1
- package/dist/modules/settings/setup.routes.d.ts.map +1 -1
- package/dist/modules/settings/setup.routes.js +111 -6
- package/dist/modules/settings/setup.routes.js.map +1 -1
- package/dist/modules/workspace/startup/kb-git.d.ts +23 -0
- package/dist/modules/workspace/startup/kb-git.d.ts.map +1 -0
- package/dist/modules/workspace/startup/kb-git.js +86 -0
- package/dist/modules/workspace/startup/kb-git.js.map +1 -0
- package/dist/modules/workspace/startup/kb-startup-runner.d.ts +74 -0
- package/dist/modules/workspace/startup/kb-startup-runner.d.ts.map +1 -0
- package/dist/modules/workspace/startup/kb-startup-runner.js +528 -0
- package/dist/modules/workspace/startup/kb-startup-runner.js.map +1 -0
- package/dist/modules/workspace/startup/on-server-start.d.ts +105 -0
- package/dist/modules/workspace/startup/on-server-start.d.ts.map +1 -0
- package/dist/modules/workspace/startup/on-server-start.js +21 -0
- package/dist/modules/workspace/startup/on-server-start.js.map +1 -0
- package/dist/modules/workspace/startup/steps/groups-to-plugins.step.d.ts +46 -0
- package/dist/modules/workspace/startup/steps/groups-to-plugins.step.d.ts.map +1 -0
- package/dist/modules/workspace/startup/steps/groups-to-plugins.step.js +492 -0
- package/dist/modules/workspace/startup/steps/groups-to-plugins.step.js.map +1 -0
- package/dist/modules/workspace/startup/steps/roles-yaml.step.d.ts +23 -0
- package/dist/modules/workspace/startup/steps/roles-yaml.step.d.ts.map +1 -0
- package/dist/modules/workspace/startup/steps/roles-yaml.step.js +69 -0
- package/dist/modules/workspace/startup/steps/roles-yaml.step.js.map +1 -0
- package/dist/modules/workspace/startup/steps/seed-tree.d.ts +17 -0
- package/dist/modules/workspace/startup/steps/seed-tree.d.ts.map +1 -0
- package/dist/modules/workspace/startup/steps/seed-tree.js +109 -0
- package/dist/modules/workspace/startup/steps/seed-tree.js.map +1 -0
- package/dist/modules/workspace/startup/steps/template-files.step.d.ts +103 -0
- package/dist/modules/workspace/startup/steps/template-files.step.d.ts.map +1 -0
- package/dist/modules/workspace/startup/steps/template-files.step.js +337 -0
- package/dist/modules/workspace/startup/steps/template-files.step.js.map +1 -0
- package/dist/modules/workspace/workspace.service.d.ts +0 -35
- package/dist/modules/workspace/workspace.service.d.ts.map +1 -1
- package/dist/modules/workspace/workspace.service.js +2 -101
- package/dist/modules/workspace/workspace.service.js.map +1 -1
- package/kb-template/AGENTS.md +11 -5
- package/kb-template/access.md +40 -30
- package/kb-template/gitignore.template +16 -0
- package/package.json +3 -3
- package/src/core/core-ports.ts +7 -0
- package/src/core/create-core-server.ts +30 -11
- package/src/core/create-core-services.ts +43 -22
- package/src/modules/access/__tests__/roles-admin.service.test.ts +24 -2
- package/src/modules/access/access.routes.ts +3 -0
- package/src/modules/access/render-roles-yaml.ts +65 -0
- package/src/modules/access/roles-admin.service.ts +32 -14
- package/src/modules/settings/__tests__/setup.routes.test.ts +124 -3
- package/src/modules/settings/setup.routes.ts +112 -5
- package/src/modules/workspace/__tests__/workspace.service.test.ts +5 -94
- package/src/modules/workspace/startup/__tests__/kb-startup-runner.test.ts +495 -0
- package/src/modules/workspace/startup/kb-git.ts +94 -0
- package/src/modules/workspace/startup/kb-startup-runner.ts +597 -0
- package/src/modules/workspace/startup/on-server-start.ts +97 -0
- package/src/modules/workspace/startup/steps/__tests__/steps.test.ts +636 -0
- package/src/modules/workspace/{plugins-migration.ts → startup/steps/groups-to-plugins.step.ts} +342 -260
- package/src/modules/workspace/startup/steps/roles-yaml.step.ts +71 -0
- package/src/modules/workspace/startup/steps/seed-tree.ts +115 -0
- package/src/modules/workspace/startup/steps/template-files.step.ts +360 -0
- package/src/modules/workspace/workspace.service.ts +2 -106
- package/src/modules/workspace/__tests__/kb-seed.service.test.ts +0 -512
- package/src/modules/workspace/__tests__/plugins-migration.test.ts +0 -427
- package/src/modules/workspace/kb-seed.interface.ts +0 -36
- package/src/modules/workspace/kb-seed.service.ts +0 -584
|
@@ -9,7 +9,6 @@ import { BevelIgnoreStack } from './bevel-ignore.js';
|
|
|
9
9
|
import { assertValidBranchName } from '../workflow/git/branch-name.js';
|
|
10
10
|
import { cloneTrackingConfigArgs, SAFE_IMPLICIT_FETCH_ARGS } from '../workflow/git/clone-config.js';
|
|
11
11
|
import type { IDiffService } from '../diff/diff.interface.js';
|
|
12
|
-
import type { IKbSeedService } from './kb-seed.interface.js';
|
|
13
12
|
|
|
14
13
|
/**
|
|
15
14
|
* Workspaces are per-branch, not per-user (PLAN §3). One on-disk clone per
|
|
@@ -119,22 +118,6 @@ export class WorkspaceService implements IWorkspaceService {
|
|
|
119
118
|
*/
|
|
120
119
|
private readonly inFlightBootstraps = new Map<string, Promise<void>>();
|
|
121
120
|
|
|
122
|
-
/**
|
|
123
|
-
* Branches whose clone already got this process's scaffolding top-up.
|
|
124
|
-
* Per-process on purpose: each boot of a new build re-offers the top-up
|
|
125
|
-
* once, which is exactly when an upgrade's migrations must run. Cleared
|
|
126
|
-
* wherever `branchDirs` forgets a branch (delete, failed bootstrap), so a
|
|
127
|
-
* re-created clone is offered the top-up again rather than judged by the
|
|
128
|
-
* fate of one that no longer exists.
|
|
129
|
-
*
|
|
130
|
-
* `inFlightTopUps` is the concurrency half: membership in the Set is
|
|
131
|
-
* claimed BEFORE the (slow, file-moving) top-up finishes, so a concurrent
|
|
132
|
-
* caller that finds the branch claimed must still await the in-flight run
|
|
133
|
-
* — returning early would hand out a workspace mid-migration.
|
|
134
|
-
*/
|
|
135
|
-
private readonly toppedUpBranches = new Set<string>();
|
|
136
|
-
private readonly inFlightTopUps = new Map<string, Promise<void>>();
|
|
137
|
-
|
|
138
121
|
/** Per-workspace-dir `git fetch origin` timestamp + in-flight tracker. */
|
|
139
122
|
private readonly lastFetchAt = new Map<string, number>();
|
|
140
123
|
private readonly inFlightFetches = new Map<string, Promise<void>>();
|
|
@@ -145,14 +128,6 @@ export class WorkspaceService implements IWorkspaceService {
|
|
|
145
128
|
*/
|
|
146
129
|
private diffService: IDiffService | null = null;
|
|
147
130
|
|
|
148
|
-
/**
|
|
149
|
-
* Late-bound by the composition root. Awaited once before the first per-branch
|
|
150
|
-
* clone so the KB remote is guaranteed to carry the protected branches + base
|
|
151
|
-
* scaffolding — a fresh (or partially-populated) remote is seeded rather than
|
|
152
|
-
* assumed. Null in tests / setups that pre-provision the remote themselves.
|
|
153
|
-
*/
|
|
154
|
-
private seedService: IKbSeedService | null = null;
|
|
155
|
-
|
|
156
131
|
/**
|
|
157
132
|
* Late-bound by the composition root: notified with the workspace id
|
|
158
133
|
* right after a branch's clone is created. The git layer uses this to
|
|
@@ -187,10 +162,6 @@ export class WorkspaceService implements IWorkspaceService {
|
|
|
187
162
|
this.diffService = diffService;
|
|
188
163
|
}
|
|
189
164
|
|
|
190
|
-
setSeedService(seedService: IKbSeedService): void {
|
|
191
|
-
this.seedService = seedService;
|
|
192
|
-
}
|
|
193
|
-
|
|
194
165
|
setWorkspaceClonedListener(listener: (workspaceId: string) => void): void {
|
|
195
166
|
this.onWorkspaceCloned = listener;
|
|
196
167
|
}
|
|
@@ -354,11 +325,6 @@ export class WorkspaceService implements IWorkspaceService {
|
|
|
354
325
|
// pulls it. Once per branch per process — the cached paths above return
|
|
355
326
|
// before reaching here.
|
|
356
327
|
await this.normalizeCloneTracking(repoDir, branch);
|
|
357
|
-
// Same restart-survivor reasoning for the scaffolding top-up: an
|
|
358
|
-
// UPGRADED deployment reuses this clone, so a top-up bound to fresh
|
|
359
|
-
// clones alone never runs a new build's scaffolding or migrations —
|
|
360
|
-
// the Groups→Plugins rename sat out an upgrade exactly this way.
|
|
361
|
-
await this.topUpScaffolding(repoDir, branch);
|
|
362
328
|
this.branchDirs.set(branch, workspaceDir);
|
|
363
329
|
return this.buildWorkspaceInfo(branch, workspaceDir);
|
|
364
330
|
} catch {
|
|
@@ -384,22 +350,14 @@ export class WorkspaceService implements IWorkspaceService {
|
|
|
384
350
|
this.inFlightBootstraps.set(branch, bootstrap);
|
|
385
351
|
|
|
386
352
|
try {
|
|
387
|
-
//
|
|
388
|
-
//
|
|
389
|
-
// must happen ahead of it. The seed service is single-flight, so this is
|
|
390
|
-
// a cheap already-resolved await on every clone after the first.
|
|
391
|
-
if (this.seedService) {
|
|
392
|
-
await this.seedService.ensureRemoteSeeded();
|
|
393
|
-
}
|
|
353
|
+
// A clone with `-b <branch>` against a never-seeded remote fails
|
|
354
|
+
// naturally; seeding the remote is the KB startup phase's job, at boot.
|
|
394
355
|
await fs.mkdir(workspaceDir, { recursive: true });
|
|
395
356
|
await this.cloneProcessMapForBranch(workspaceDir, branch);
|
|
396
357
|
this.branchDirs.set(branch, workspaceDir);
|
|
397
358
|
resolveBootstrap();
|
|
398
359
|
} catch (err) {
|
|
399
360
|
this.branchDirs.delete(branch);
|
|
400
|
-
// The clone was rolled back, and any top-up claim belonged to it — a
|
|
401
|
-
// retried bootstrap must be offered the top-up afresh.
|
|
402
|
-
this.toppedUpBranches.delete(branch);
|
|
403
361
|
rejectBootstrap(err);
|
|
404
362
|
throw err;
|
|
405
363
|
} finally {
|
|
@@ -444,7 +402,6 @@ export class WorkspaceService implements IWorkspaceService {
|
|
|
444
402
|
await pending;
|
|
445
403
|
} catch (err) {
|
|
446
404
|
this.branchDirs.delete(branch);
|
|
447
|
-
this.toppedUpBranches.delete(branch);
|
|
448
405
|
throw err;
|
|
449
406
|
}
|
|
450
407
|
}
|
|
@@ -475,44 +432,6 @@ export class WorkspaceService implements IWorkspaceService {
|
|
|
475
432
|
}
|
|
476
433
|
}
|
|
477
434
|
|
|
478
|
-
/**
|
|
479
|
-
* The ONE spelling of the best-effort scaffolding top-up (three call sites:
|
|
480
|
-
* the restart-survivor path in `getOrCreateForBranch`, and the
|
|
481
|
-
* already-cloned / fresh-clone paths in `cloneProcessMapForBranch`). Once
|
|
482
|
-
* per branch per process, and SINGLE-FLIGHT: the branch is claimed in
|
|
483
|
-
* `toppedUpBranches` before the run starts, so a concurrent caller that
|
|
484
|
-
* finds it claimed awaits the in-flight run instead of returning a
|
|
485
|
-
* workspace the migration is still moving files under. Never throws — a
|
|
486
|
-
* failed top-up costs the upgrade, not the clone.
|
|
487
|
-
*/
|
|
488
|
-
private async topUpScaffolding(repoDir: string, branch: string): Promise<void> {
|
|
489
|
-
const seedService = this.seedService;
|
|
490
|
-
if (!seedService) return;
|
|
491
|
-
if (this.toppedUpBranches.has(branch)) {
|
|
492
|
-
await this.inFlightTopUps.get(branch);
|
|
493
|
-
return;
|
|
494
|
-
}
|
|
495
|
-
this.toppedUpBranches.add(branch);
|
|
496
|
-
const run = (async () => {
|
|
497
|
-
try {
|
|
498
|
-
await seedService.topUpWorkspace(repoDir, branch);
|
|
499
|
-
} catch (topUpErr) {
|
|
500
|
-
console.error(
|
|
501
|
-
`[workspace] scaffolding top-up failed for branch "${branch}" (clone kept):`,
|
|
502
|
-
redactError(topUpErr),
|
|
503
|
-
);
|
|
504
|
-
}
|
|
505
|
-
})();
|
|
506
|
-
this.inFlightTopUps.set(branch, run);
|
|
507
|
-
try {
|
|
508
|
-
await run;
|
|
509
|
-
} finally {
|
|
510
|
-
if (this.inFlightTopUps.get(branch) === run) {
|
|
511
|
-
this.inFlightTopUps.delete(branch);
|
|
512
|
-
}
|
|
513
|
-
}
|
|
514
|
-
}
|
|
515
|
-
|
|
516
435
|
private async cloneProcessMapForBranch(workspaceDir: string, branch: string): Promise<void> {
|
|
517
436
|
const targetDir = path.join(workspaceDir, this.kbDirName);
|
|
518
437
|
|
|
@@ -561,11 +480,6 @@ export class WorkspaceService implements IWorkspaceService {
|
|
|
561
480
|
// it never touches the working tree, and a drifted config is what
|
|
562
481
|
// breaks the next pull.
|
|
563
482
|
await this.normalizeCloneTracking(targetDir, branch);
|
|
564
|
-
// An upgraded deployment REUSES this persistent clone, so a top-up
|
|
565
|
-
// bound to fresh clones alone never runs a new build's scaffolding
|
|
566
|
-
// or migrations here — the Groups→Plugins rename sat out an upgrade
|
|
567
|
-
// for exactly this reason.
|
|
568
|
-
await this.topUpScaffolding(targetDir, branch);
|
|
569
483
|
return;
|
|
570
484
|
}
|
|
571
485
|
// Half-built dir — wipe and re-clone.
|
|
@@ -606,15 +520,6 @@ export class WorkspaceService implements IWorkspaceService {
|
|
|
606
520
|
redactError(listenerErr),
|
|
607
521
|
);
|
|
608
522
|
}
|
|
609
|
-
// Fill in any base scaffolding this branch is missing, now that it's
|
|
610
|
-
// freshly checked out. Runs on whichever branch the user loaded (not
|
|
611
|
-
// just protected ones). Best-effort inside the helper — like the
|
|
612
|
-
// onWorkspaceCloned listener above — so even a future change that lets
|
|
613
|
-
// it throw can never roll back an otherwise-good clone. (The
|
|
614
|
-
// once-per-process guard is a formality here: a branch being freshly
|
|
615
|
-
// cloned was either never topped up or had its claim cleared with the
|
|
616
|
-
// clone it belonged to.)
|
|
617
|
-
await this.topUpScaffolding(targetDir, branch);
|
|
618
523
|
} catch (err) {
|
|
619
524
|
const redacted = redactError(err);
|
|
620
525
|
console.error(`[workspace] Failed to clone for branch "${branch}":`, redacted);
|
|
@@ -643,10 +548,6 @@ export class WorkspaceService implements IWorkspaceService {
|
|
|
643
548
|
await fs.rm(workspaceDir, { recursive: true, force: true });
|
|
644
549
|
const branch = branchForWorkspaceId(workspaceId);
|
|
645
550
|
this.branchDirs.delete(branch);
|
|
646
|
-
// The top-up claim died with the clone it was made against — a branch
|
|
647
|
-
// re-created later gets a fresh clone and must be offered it again (and
|
|
648
|
-
// without this, long-lived processes would accumulate dead branch names).
|
|
649
|
-
this.toppedUpBranches.delete(branch);
|
|
650
551
|
}
|
|
651
552
|
|
|
652
553
|
async listFiles(workspaceId: string, readFilter?: ReadTreeFilter): Promise<FileTreeEntry> {
|
|
@@ -1284,11 +1185,6 @@ export class WorkspaceService implements IWorkspaceService {
|
|
|
1284
1185
|
try {
|
|
1285
1186
|
await fs.rm(dir, { recursive: true, force: true });
|
|
1286
1187
|
this.branchDirs.delete(branchForWorkspaceId(entry.name));
|
|
1287
|
-
// The top-up claim dies with the clone (same rule as every other
|
|
1288
|
-
// eviction site): a branch re-created after the sweep gets a fresh
|
|
1289
|
-
// clone that must be OFFERED the scaffolding top-up, not judged by
|
|
1290
|
-
// the fate of a directory that no longer exists.
|
|
1291
|
-
this.toppedUpBranches.delete(branchForWorkspaceId(entry.name));
|
|
1292
1188
|
removed.push(entry.name);
|
|
1293
1189
|
} catch (err) {
|
|
1294
1190
|
console.warn(
|