@bevel-software/platform-core-backend 0.4.1 → 0.5.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/THIRD-PARTY-NOTICES.md +6118 -0
- package/dist/core/core-ports.d.ts +15 -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 +40 -6
- package/dist/core/create-core-server.js.map +1 -1
- package/dist/core/create-core-services.d.ts +17 -1
- package/dist/core/create-core-services.d.ts.map +1 -1
- package/dist/core/create-core-services.js +153 -29
- package/dist/core/create-core-services.js.map +1 -1
- package/dist/core-config.d.ts +70 -21
- package/dist/core-config.d.ts.map +1 -1
- package/dist/core-config.js +134 -58
- package/dist/core-config.js.map +1 -1
- package/dist/modules/access/access-control.interface.d.ts +6 -0
- package/dist/modules/access/access-control.interface.d.ts.map +1 -1
- package/dist/modules/access/access-control.service.d.ts +74 -5
- package/dist/modules/access/access-control.service.d.ts.map +1 -1
- package/dist/modules/access/access-control.service.js +116 -15
- package/dist/modules/access/access-control.service.js.map +1 -1
- package/dist/modules/access/access-declarations.d.ts +93 -0
- package/dist/modules/access/access-declarations.d.ts.map +1 -0
- package/dist/modules/access/access-declarations.js +168 -0
- package/dist/modules/access/access-declarations.js.map +1 -0
- package/dist/modules/access/access-mutation.service.js +4 -4
- package/dist/modules/access/access-mutation.service.js.map +1 -1
- package/dist/modules/access/access-splice.d.ts +16 -1
- package/dist/modules/access/access-splice.d.ts.map +1 -1
- package/dist/modules/access/access-splice.js +40 -21
- package/dist/modules/access/access-splice.js.map +1 -1
- package/dist/modules/access/access.routes.d.ts.map +1 -1
- package/dist/modules/access/access.routes.js +51 -0
- package/dist/modules/access/access.routes.js.map +1 -1
- package/dist/modules/access/creator-access.d.ts +8 -0
- package/dist/modules/access/creator-access.d.ts.map +1 -1
- package/dist/modules/access/creator-access.js +21 -2
- package/dist/modules/access/creator-access.js.map +1 -1
- package/dist/modules/admin/admin-access.service.d.ts +1 -1
- package/dist/modules/admin/admin-access.service.d.ts.map +1 -1
- package/dist/modules/admin/admin-access.service.js +3 -2
- package/dist/modules/admin/admin-access.service.js.map +1 -1
- package/dist/modules/auth/auth.routes.d.ts.map +1 -1
- package/dist/modules/auth/auth.routes.js +50 -1
- package/dist/modules/auth/auth.routes.js.map +1 -1
- package/dist/modules/auth/auth.service.d.ts +39 -10
- package/dist/modules/auth/auth.service.d.ts.map +1 -1
- package/dist/modules/auth/auth.service.js +38 -16
- package/dist/modules/auth/auth.service.js.map +1 -1
- package/dist/modules/database/core-schema.d.ts +124 -0
- package/dist/modules/database/core-schema.d.ts.map +1 -1
- package/dist/modules/database/core-schema.js +45 -0
- package/dist/modules/database/core-schema.js.map +1 -1
- package/dist/modules/groups/group-provision.service.d.ts +130 -0
- package/dist/modules/groups/group-provision.service.d.ts.map +1 -0
- package/dist/modules/groups/group-provision.service.js +288 -0
- package/dist/modules/groups/group-provision.service.js.map +1 -0
- package/dist/modules/groups/groups.contract.d.ts +106 -0
- package/dist/modules/groups/groups.contract.d.ts.map +1 -0
- package/dist/modules/groups/groups.contract.js +36 -0
- package/dist/modules/groups/groups.contract.js.map +1 -0
- package/dist/modules/groups/groups.routes.d.ts +42 -0
- package/dist/modules/groups/groups.routes.d.ts.map +1 -0
- package/dist/modules/groups/groups.routes.js +379 -0
- package/dist/modules/groups/groups.routes.js.map +1 -0
- package/dist/modules/groups/groups.service.d.ts +60 -0
- package/dist/modules/groups/groups.service.d.ts.map +1 -0
- package/dist/modules/groups/groups.service.js +172 -0
- package/dist/modules/groups/groups.service.js.map +1 -0
- package/dist/modules/groups/index.d.ts +7 -0
- package/dist/modules/groups/index.d.ts.map +1 -0
- package/dist/modules/groups/index.js +6 -0
- package/dist/modules/groups/index.js.map +1 -0
- package/dist/modules/groups/join-proposals.d.ts +53 -0
- package/dist/modules/groups/join-proposals.d.ts.map +1 -0
- package/dist/modules/groups/join-proposals.js +67 -0
- package/dist/modules/groups/join-proposals.js.map +1 -0
- package/dist/modules/groups/join-requests.service.d.ts +81 -0
- package/dist/modules/groups/join-requests.service.d.ts.map +1 -0
- package/dist/modules/groups/join-requests.service.js +135 -0
- package/dist/modules/groups/join-requests.service.js.map +1 -0
- package/dist/modules/secrets-vault/secrets-vault.routes.d.ts +20 -0
- package/dist/modules/secrets-vault/secrets-vault.routes.d.ts.map +1 -1
- package/dist/modules/secrets-vault/secrets-vault.routes.js +59 -11
- package/dist/modules/secrets-vault/secrets-vault.routes.js.map +1 -1
- package/dist/modules/settings/deployment-settings.service.d.ts +129 -0
- package/dist/modules/settings/deployment-settings.service.d.ts.map +1 -0
- package/dist/modules/settings/deployment-settings.service.js +368 -0
- package/dist/modules/settings/deployment-settings.service.js.map +1 -0
- package/dist/modules/settings/setup.routes.d.ts +49 -0
- package/dist/modules/settings/setup.routes.d.ts.map +1 -0
- package/dist/modules/settings/setup.routes.js +292 -0
- package/dist/modules/settings/setup.routes.js.map +1 -0
- package/dist/modules/skills/index.d.ts +2 -1
- package/dist/modules/skills/index.d.ts.map +1 -1
- package/dist/modules/skills/index.js +1 -0
- package/dist/modules/skills/index.js.map +1 -1
- package/dist/modules/skills/pending-skills.service.d.ts +40 -0
- package/dist/modules/skills/pending-skills.service.d.ts.map +1 -0
- package/dist/modules/skills/pending-skills.service.js +147 -0
- package/dist/modules/skills/pending-skills.service.js.map +1 -0
- package/dist/modules/skills/skills.contract.d.ts +32 -3
- package/dist/modules/skills/skills.contract.d.ts.map +1 -1
- package/dist/modules/skills/skills.contract.js +1 -1
- package/dist/modules/skills/skills.routes.d.ts +3 -2
- package/dist/modules/skills/skills.routes.d.ts.map +1 -1
- package/dist/modules/skills/skills.routes.js +18 -1
- package/dist/modules/skills/skills.routes.js.map +1 -1
- package/dist/modules/skills/skills.service.d.ts +22 -0
- package/dist/modules/skills/skills.service.d.ts.map +1 -1
- package/dist/modules/skills/skills.service.js +24 -12
- package/dist/modules/skills/skills.service.js.map +1 -1
- package/dist/modules/tool-manuals/index.d.ts +1 -1
- package/dist/modules/tool-manuals/index.d.ts.map +1 -1
- package/dist/modules/tool-manuals/index.js.map +1 -1
- package/dist/modules/tool-manuals/tool-manuals.contract.d.ts +47 -2
- package/dist/modules/tool-manuals/tool-manuals.contract.d.ts.map +1 -1
- package/dist/modules/tool-manuals/tool-manuals.contract.js +1 -1
- package/dist/modules/tool-manuals/tool-manuals.routes.d.ts +4 -0
- package/dist/modules/tool-manuals/tool-manuals.routes.d.ts.map +1 -1
- package/dist/modules/tool-manuals/tool-manuals.routes.js +23 -0
- package/dist/modules/tool-manuals/tool-manuals.routes.js.map +1 -1
- package/dist/modules/tool-manuals/tool-manuals.service.d.ts +3 -1
- package/dist/modules/tool-manuals/tool-manuals.service.d.ts.map +1 -1
- package/dist/modules/tool-manuals/tool-manuals.service.js +84 -17
- package/dist/modules/tool-manuals/tool-manuals.service.js.map +1 -1
- package/dist/modules/tool-manuals/tool-manuals.tools.d.ts.map +1 -1
- package/dist/modules/tool-manuals/tool-manuals.tools.js +6 -2
- package/dist/modules/tool-manuals/tool-manuals.tools.js.map +1 -1
- package/dist/modules/workflow/agent-tools/workflow.tools.d.ts.map +1 -1
- package/dist/modules/workflow/agent-tools/workflow.tools.js +4 -2
- package/dist/modules/workflow/agent-tools/workflow.tools.js.map +1 -1
- package/dist/modules/workflow/event-bus.d.ts +11 -0
- package/dist/modules/workflow/event-bus.d.ts.map +1 -1
- package/dist/modules/workflow/event-bus.js +22 -0
- package/dist/modules/workflow/event-bus.js.map +1 -1
- package/dist/modules/workflow/file-lock.service.d.ts +9 -0
- package/dist/modules/workflow/file-lock.service.d.ts.map +1 -1
- package/dist/modules/workflow/file-lock.service.js +16 -0
- package/dist/modules/workflow/file-lock.service.js.map +1 -1
- package/dist/modules/workflow/git/branch-name.d.ts +1 -1
- package/dist/modules/workflow/git/branch-name.d.ts.map +1 -1
- package/dist/modules/workflow/git/branch-name.js +1 -1
- package/dist/modules/workflow/git/branch-name.js.map +1 -1
- package/dist/modules/workflow/git/git.service.d.ts +31 -2
- package/dist/modules/workflow/git/git.service.d.ts.map +1 -1
- package/dist/modules/workflow/git/git.service.js +144 -52
- package/dist/modules/workflow/git/git.service.js.map +1 -1
- package/dist/modules/workflow/git/pull-request.service.d.ts +12 -6
- package/dist/modules/workflow/git/pull-request.service.d.ts.map +1 -1
- package/dist/modules/workflow/git/pull-request.service.js +19 -9
- package/dist/modules/workflow/git/pull-request.service.js.map +1 -1
- package/dist/modules/workflow/review-workflow/review-workflow.service.d.ts.map +1 -1
- package/dist/modules/workflow/review-workflow/review-workflow.service.js +12 -3
- package/dist/modules/workflow/review-workflow/review-workflow.service.js.map +1 -1
- package/dist/modules/workflow/workflow.routes.d.ts.map +1 -1
- package/dist/modules/workflow/workflow.routes.js +95 -14
- package/dist/modules/workflow/workflow.routes.js.map +1 -1
- package/dist/modules/workflow/workflow.service.d.ts +92 -3
- package/dist/modules/workflow/workflow.service.d.ts.map +1 -1
- package/dist/modules/workflow/workflow.service.js +381 -108
- package/dist/modules/workflow/workflow.service.js.map +1 -1
- package/dist/modules/workspace/bevel-ignore.d.ts +5 -0
- package/dist/modules/workspace/bevel-ignore.d.ts.map +1 -1
- package/dist/modules/workspace/bevel-ignore.js +5 -1
- package/dist/modules/workspace/bevel-ignore.js.map +1 -1
- package/dist/modules/workspace/kb-seed.interface.d.ts +1 -1
- package/dist/modules/workspace/kb-seed.service.d.ts +60 -5
- package/dist/modules/workspace/kb-seed.service.d.ts.map +1 -1
- package/dist/modules/workspace/kb-seed.service.js +228 -51
- package/dist/modules/workspace/kb-seed.service.js.map +1 -1
- package/dist/modules/workspace/workspace.routes.d.ts +2 -1
- package/dist/modules/workspace/workspace.routes.d.ts.map +1 -1
- package/dist/modules/workspace/workspace.routes.js +51 -18
- package/dist/modules/workspace/workspace.routes.js.map +1 -1
- package/dist/modules/workspace/workspace.service.d.ts +16 -4
- package/dist/modules/workspace/workspace.service.d.ts.map +1 -1
- package/dist/modules/workspace/workspace.service.js +36 -9
- package/dist/modules/workspace/workspace.service.js.map +1 -1
- package/dist/modules/workspace/workspace.tools.d.ts.map +1 -1
- package/dist/modules/workspace/workspace.tools.js +8 -3
- package/dist/modules/workspace/workspace.tools.js.map +1 -1
- package/dist/shared/kb-layout.test.js +2 -2
- package/dist/test-setup.d.ts +2 -0
- package/dist/test-setup.d.ts.map +1 -0
- package/dist/test-setup.js +18 -0
- package/dist/test-setup.js.map +1 -0
- package/kb-template/.bevelignore +6 -2
- package/kb-template/AGENTS.md +272 -0
- package/kb-template/KnowledgeBase/How to get started.md +65 -0
- package/kb-template/access.md +36 -36
- package/migrations/0002_user_onboarding_done.sql +1 -0
- package/migrations/0003_deployment_settings.sql +9 -0
- package/migrations/meta/0001_snapshot.json +1486 -0
- package/migrations/meta/0002_snapshot.json +1493 -0
- package/migrations/meta/0003_snapshot.json +1552 -0
- package/migrations/meta/_journal.json +15 -1
- package/package.json +5 -4
- package/src/__tests__/branch-model.test.ts +79 -0
- package/src/__tests__/core-config.admin.test.ts +114 -0
- package/src/__tests__/database-url.test.ts +70 -0
- package/src/core/core-ports.ts +15 -0
- package/src/core/create-core-server.ts +55 -6
- package/src/core/create-core-services.ts +201 -36
- package/src/core-config.ts +139 -59
- package/src/modules/access/__tests__/access-declarations.test.ts +195 -0
- package/src/modules/access/__tests__/access-md-format.test.ts +191 -0
- package/src/modules/access/__tests__/access-splice.test.ts +21 -0
- package/src/modules/access/__tests__/access.routes.overrides.test.ts +214 -0
- package/src/modules/access/access-control.interface.ts +11 -0
- package/src/modules/access/access-control.service.ts +113 -15
- package/src/modules/access/access-declarations.ts +251 -0
- package/src/modules/access/access-mutation.service.ts +4 -4
- package/src/modules/access/access-splice.ts +64 -21
- package/src/modules/access/access.routes.ts +61 -0
- package/src/modules/access/creator-access.ts +22 -2
- package/src/modules/admin/admin-access.service.ts +4 -3
- package/src/modules/auth/__tests__/auth.service.test.ts +57 -0
- package/src/modules/auth/__tests__/onboarding-done.route.test.ts +147 -0
- package/src/modules/auth/auth.routes.ts +50 -1
- package/src/modules/auth/auth.service.ts +55 -17
- package/src/modules/database/core-schema.ts +46 -0
- package/src/modules/groups/__tests__/group-index.service.test.ts +225 -0
- package/src/modules/groups/__tests__/group-provision.service.test.ts +247 -0
- package/src/modules/groups/__tests__/groups.routes.test.ts +493 -0
- package/src/modules/groups/__tests__/join-proposals.test.ts +101 -0
- package/src/modules/groups/__tests__/join-requests.service.test.ts +175 -0
- package/src/modules/groups/group-provision.service.ts +328 -0
- package/src/modules/groups/groups.contract.ts +107 -0
- package/src/modules/groups/groups.routes.ts +433 -0
- package/src/modules/groups/groups.service.ts +193 -0
- package/src/modules/groups/index.ts +17 -0
- package/src/modules/groups/join-proposals.ts +114 -0
- package/src/modules/groups/join-requests.service.ts +185 -0
- package/src/modules/secrets-vault/__tests__/oauth-return-to.route.test.ts +283 -0
- package/src/modules/secrets-vault/secrets-vault.routes.ts +68 -12
- package/src/modules/settings/__tests__/deployment-settings.service.test.ts +256 -0
- package/src/modules/settings/__tests__/setup.routes.test.ts +201 -0
- package/src/modules/settings/deployment-settings.service.ts +419 -0
- package/src/modules/settings/setup.routes.ts +317 -0
- package/src/modules/skills/__tests__/pending-skills.service.test.ts +240 -0
- package/src/modules/skills/__tests__/skills.service.test.ts +13 -13
- package/src/modules/skills/index.ts +3 -0
- package/src/modules/skills/pending-skills.service.ts +168 -0
- package/src/modules/skills/skills.contract.ts +34 -3
- package/src/modules/skills/skills.routes.ts +23 -2
- package/src/modules/skills/skills.service.ts +24 -16
- package/src/modules/tool-manuals/__tests__/tool-manuals.detail.route.test.ts +262 -0
- package/src/modules/tool-manuals/__tests__/tool-manuals.mcp-oauth.test.ts +2 -2
- package/src/modules/tool-manuals/__tests__/tool-manuals.service.test.ts +61 -23
- package/src/modules/tool-manuals/__tests__/tool-manuals.tools.test.ts +156 -156
- package/src/modules/tool-manuals/index.ts +2 -0
- package/src/modules/tool-manuals/tool-manuals.contract.ts +50 -2
- package/src/modules/tool-manuals/tool-manuals.routes.ts +21 -0
- package/src/modules/tool-manuals/tool-manuals.service.ts +86 -17
- package/src/modules/tool-manuals/tool-manuals.tools.ts +206 -202
- package/src/modules/workflow/__tests__/event-bus.test.ts +35 -0
- package/src/modules/workflow/__tests__/workflow.service.facade.test.ts +251 -5
- package/src/modules/workflow/agent-tools/workflow.tools.ts +4 -2
- package/src/modules/workflow/event-bus.ts +25 -0
- package/src/modules/workflow/file-lock.service.ts +17 -0
- package/src/modules/workflow/git/__tests__/git.service.accessGating.test.ts +9 -49
- package/src/modules/workflow/git/__tests__/git.service.changedFilesForPr.test.ts +101 -0
- package/src/modules/workflow/git/__tests__/git.service.commitFile.test.ts +219 -211
- package/src/modules/workflow/git/__tests__/git.service.fileContentsAtCommit.test.ts +132 -0
- package/src/modules/workflow/git/__tests__/git.service.logForFile.test.ts +4 -2
- package/src/modules/workflow/git/__tests__/git.service.postMergePull.test.ts +275 -272
- package/src/modules/workflow/git/__tests__/git.service.pull.test.ts +5 -0
- package/src/modules/workflow/git/__tests__/pull-request.service.viewer-can-cancel.test.ts +44 -0
- package/src/modules/workflow/git/branch-name.ts +5 -1
- package/src/modules/workflow/git/git.service.ts +159 -62
- package/src/modules/workflow/git/pull-request.service.ts +22 -11
- package/src/modules/workflow/review-workflow/__tests__/cancel-pr.test.ts +4 -1
- package/src/modules/workflow/review-workflow/review-workflow.service.ts +12 -3
- package/src/modules/workflow/workflow.routes.ts +91 -13
- package/src/modules/workflow/workflow.service.ts +353 -13
- package/src/modules/workspace/__tests__/kb-seed.service.test.ts +255 -24
- package/src/modules/workspace/__tests__/workspace.routes.create-grant.test.ts +236 -233
- package/src/modules/workspace/__tests__/workspace.routes.delete.test.ts +179 -176
- package/src/modules/workspace/__tests__/workspace.routes.download.test.ts +320 -303
- package/src/modules/workspace/__tests__/workspace.routes.read-gate.test.ts +337 -276
- package/src/modules/workspace/__tests__/workspace.tools.test.ts +14 -6
- package/src/modules/workspace/bevel-ignore.ts +66 -62
- package/src/modules/workspace/kb-seed.interface.ts +1 -1
- package/src/modules/workspace/kb-seed.service.ts +247 -53
- package/src/modules/workspace/workspace.routes.ts +54 -18
- package/src/modules/workspace/workspace.service.ts +45 -7
- package/src/modules/workspace/workspace.tools.ts +922 -917
- package/src/shared/__tests__/frontmatter-id.test.ts +53 -0
- package/src/shared/__tests__/join-request.test.ts +96 -0
- package/src/shared/__tests__/kb-layout.group.test.ts +45 -0
- package/src/shared/kb-layout.test.ts +2 -2
- package/src/test-setup.ts +18 -0
- package/kb-template/Agents/README.md +0 -38
- package/kb-template/CLAUDE.md +0 -419
- package/kb-template/Data/.gitkeep +0 -0
- package/kb-template/Data/README.md +0 -39
- package/kb-template/KnowledgeBase/README.md +0 -37
- package/kb-template/Pipelines/.gitkeep +0 -0
- package/kb-template/Pipelines/README.md +0 -38
- package/kb-template/Skills/.gitkeep +0 -0
- package/kb-template/Skills/README.md +0 -32
- package/kb-template/Tools/.gitkeep +0 -0
- package/kb-template/Tools/README.md +0 -42
- /package/kb-template/{Agents → Groups}/.gitkeep +0 -0
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { describe, it, expect, beforeEach, afterEach } from 'vitest';
|
|
1
|
+
import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest';
|
|
2
2
|
import { execFile } from 'node:child_process';
|
|
3
3
|
import { promisify } from 'node:util';
|
|
4
4
|
import fs from 'node:fs/promises';
|
|
@@ -28,8 +28,20 @@ async function git(cwd: string, args: string[]): Promise<string> {
|
|
|
28
28
|
return stdout.toString();
|
|
29
29
|
}
|
|
30
30
|
|
|
31
|
-
function makeSeeder(
|
|
32
|
-
|
|
31
|
+
function makeSeeder(
|
|
32
|
+
upstream: string,
|
|
33
|
+
admins: readonly string[] = ADMINS,
|
|
34
|
+
extraDirs: readonly string[] = [],
|
|
35
|
+
): KbSeedService {
|
|
36
|
+
return new KbSeedService(
|
|
37
|
+
upstream,
|
|
38
|
+
TEMPLATE_DIR,
|
|
39
|
+
PROTECTED,
|
|
40
|
+
DEFAULT_BRANCH,
|
|
41
|
+
admins,
|
|
42
|
+
'x-access-token',
|
|
43
|
+
extraDirs,
|
|
44
|
+
);
|
|
33
45
|
}
|
|
34
46
|
|
|
35
47
|
/** Clone a branch of the upstream into a fresh checkout for inspection. */
|
|
@@ -102,12 +114,18 @@ describe('KbSeedService', () => {
|
|
|
102
114
|
for (const branch of PROTECTED) {
|
|
103
115
|
const dir = await checkout(root, upstream, branch);
|
|
104
116
|
expect(await exists(path.join(dir, 'access.md'))).toBe(true);
|
|
105
|
-
expect(await exists(path.join(dir, '
|
|
117
|
+
expect(await exists(path.join(dir, 'AGENTS.md'))).toBe(true);
|
|
106
118
|
expect(await exists(path.join(dir, '.bevelignore'))).toBe(true);
|
|
107
119
|
expect(await exists(path.join(dir, '.gitignore'))).toBe(true);
|
|
108
|
-
//
|
|
120
|
+
// Core's two roots are seeded (kept present via their .gitkeep).
|
|
109
121
|
expect(await exists(path.join(dir, 'KnowledgeBase/.gitkeep'))).toBe(true);
|
|
110
|
-
expect(await exists(path.join(dir, '
|
|
122
|
+
expect(await exists(path.join(dir, 'Groups/.gitkeep'))).toBe(true);
|
|
123
|
+
// …and only those two. `Data/`, `Agents/` and `Pipelines/` scaffold an
|
|
124
|
+
// agentic execution layer this platform does not have, so seeding them
|
|
125
|
+
// would hand every operator three empty folders nothing can fill.
|
|
126
|
+
for (const enterpriseOnly of ['Data', 'Agents', 'Pipelines']) {
|
|
127
|
+
expect(await exists(path.join(dir, enterpriseOnly))).toBe(false);
|
|
128
|
+
}
|
|
111
129
|
|
|
112
130
|
const roles = await fs.readFile(path.join(dir, 'roles.yaml'), 'utf8');
|
|
113
131
|
for (const email of ADMINS) expect(roles).toContain(email);
|
|
@@ -116,10 +134,14 @@ describe('KbSeedService', () => {
|
|
|
116
134
|
}
|
|
117
135
|
});
|
|
118
136
|
|
|
119
|
-
|
|
137
|
+
// Unreachable through the app — `ADMIN_EMAIL` is required at boot, so the
|
|
138
|
+
// list always has exactly one entry. Kept as a guard on the seeder's own
|
|
139
|
+
// contract: a KB seeded with no Admin cannot resolve access at all, and
|
|
140
|
+
// silently writing an Admin-less roles.yaml would be worse than refusing.
|
|
141
|
+
it('refuses to seed an empty remote with no initial Admin', async () => {
|
|
120
142
|
const upstream = await emptyUpstream();
|
|
121
143
|
await expect(makeSeeder(upstream, []).ensureRemoteSeeded()).rejects.toThrow(
|
|
122
|
-
/
|
|
144
|
+
/no initial Admin/,
|
|
123
145
|
);
|
|
124
146
|
});
|
|
125
147
|
});
|
|
@@ -130,11 +152,11 @@ describe('KbSeedService', () => {
|
|
|
130
152
|
const upstream = await seededUpstream([DEFAULT_BRANCH], {
|
|
131
153
|
'roles.yaml': 'roles:\n Admin:\n - keep@example.com\n',
|
|
132
154
|
'access.md': 'existing',
|
|
133
|
-
'
|
|
155
|
+
'AGENTS.md': 'existing',
|
|
134
156
|
'.bevelignore': 'x',
|
|
135
157
|
'.gitignore': 'x',
|
|
136
158
|
'KnowledgeBase/Real/Knowledge/.gitkeep': '',
|
|
137
|
-
'
|
|
159
|
+
'Groups/.gitkeep': '',
|
|
138
160
|
});
|
|
139
161
|
|
|
140
162
|
await makeSeeder(upstream).ensureRemoteSeeded();
|
|
@@ -148,9 +170,9 @@ describe('KbSeedService', () => {
|
|
|
148
170
|
// roles.yaml + access.md already exist with custom content — must survive.
|
|
149
171
|
'roles.yaml': 'roles:\n Admin:\n - keep@example.com\n',
|
|
150
172
|
'access.md': 'CUSTOM ACCESS RULES',
|
|
151
|
-
//
|
|
173
|
+
// AGENTS.md / .bevelignore / .gitignore are absent → should be added.
|
|
152
174
|
'KnowledgeBase/Real/Knowledge/.gitkeep': '',
|
|
153
|
-
'
|
|
175
|
+
'Groups/.gitkeep': '',
|
|
154
176
|
});
|
|
155
177
|
|
|
156
178
|
// Simulate the app loading the branch: a fresh clone, then top-up on it.
|
|
@@ -163,7 +185,7 @@ describe('KbSeedService', () => {
|
|
|
163
185
|
expect(await fs.readFile(path.join(dir, 'access.md'), 'utf8')).toBe('CUSTOM ACCESS RULES');
|
|
164
186
|
expect(await fs.readFile(path.join(dir, 'roles.yaml'), 'utf8')).toContain('keep@example.com');
|
|
165
187
|
// Missing scaffolding added.
|
|
166
|
-
expect(await exists(path.join(dir, '
|
|
188
|
+
expect(await exists(path.join(dir, 'AGENTS.md'))).toBe(true);
|
|
167
189
|
expect(await exists(path.join(dir, '.bevelignore'))).toBe(true);
|
|
168
190
|
// Sample content is NOT restored — the real KnowledgeBase already had content,
|
|
169
191
|
// so no placeholder .gitkeep is dropped into it, and no ExampleOntology appears.
|
|
@@ -171,11 +193,68 @@ describe('KbSeedService', () => {
|
|
|
171
193
|
expect(await exists(path.join(dir, 'KnowledgeBase/ExampleOntology'))).toBe(false);
|
|
172
194
|
});
|
|
173
195
|
|
|
196
|
+
it('replaces an edited AGENTS.md with the current template — the file is managed', async () => {
|
|
197
|
+
const upstream = await seededUpstream(PROTECTED, {
|
|
198
|
+
'roles.yaml': 'roles:\n Admin:\n - keep@example.com\n',
|
|
199
|
+
'AGENTS.md': '# my own conventions\n',
|
|
200
|
+
'.bevelignore': 'AGENTS.md\n',
|
|
201
|
+
'.gitignore': '',
|
|
202
|
+
'access.md': 'CUSTOM ACCESS RULES',
|
|
203
|
+
'KnowledgeBase/Real/Knowledge/.gitkeep': '',
|
|
204
|
+
'Groups/.gitkeep': '',
|
|
205
|
+
});
|
|
206
|
+
|
|
207
|
+
const repoDir = await checkout(root, upstream, DEFAULT_BRANCH);
|
|
208
|
+
await makeSeeder(upstream).topUpWorkspace(repoDir, DEFAULT_BRANCH);
|
|
209
|
+
|
|
210
|
+
const dir = await checkout(root, upstream, DEFAULT_BRANCH);
|
|
211
|
+
const agents = await fs.readFile(path.join(dir, 'AGENTS.md'), 'utf8');
|
|
212
|
+
// The template's copy, not the edit — and the template says WHY, so the
|
|
213
|
+
// overwrite is a stated contract rather than a surprise.
|
|
214
|
+
expect(agents).not.toContain('my own conventions');
|
|
215
|
+
expect(agents).toContain('managed by the platform');
|
|
216
|
+
// Everything the platform does NOT manage is preserved verbatim.
|
|
217
|
+
expect(await fs.readFile(path.join(dir, 'access.md'), 'utf8')).toBe('CUSTOM ACCESS RULES');
|
|
218
|
+
const log = await git(dir, ['log', '-1', '--pretty=%s']);
|
|
219
|
+
expect(log.trim()).toBe('Update AGENTS.md to the current platform template');
|
|
220
|
+
});
|
|
221
|
+
|
|
222
|
+
it('a current AGENTS.md makes no refresh commit, even with CRLF endings', async () => {
|
|
223
|
+
const template = await fs.readFile(
|
|
224
|
+
path.join(__dirname, '../../../../kb-template/AGENTS.md'),
|
|
225
|
+
'utf8',
|
|
226
|
+
);
|
|
227
|
+
const upstream = await seededUpstream(PROTECTED, {
|
|
228
|
+
'roles.yaml': 'roles:\n Admin:\n - keep@example.com\n',
|
|
229
|
+
// Same content, Windows endings — must read as "same", or the managed
|
|
230
|
+
// refresh would commit churn on every boot forever.
|
|
231
|
+
//
|
|
232
|
+
// `\r?\n`, not `\n`: on a Windows checkout (`core.autocrlf=true`) the
|
|
233
|
+
// template already HAS CRLF, so converting every `\n` would produce
|
|
234
|
+
// `\r\r\n` — a file that differs from the template for real, failing
|
|
235
|
+
// this test for a reason that has nothing to do with what it asserts.
|
|
236
|
+
// Matching the optional `\r` normalizes first, so the fixture is
|
|
237
|
+
// exactly-CRLF on every platform.
|
|
238
|
+
'AGENTS.md': template.replace(/\r?\n/g, '\r\n'),
|
|
239
|
+
'.bevelignore': 'AGENTS.md\n',
|
|
240
|
+
'.gitignore': '',
|
|
241
|
+
'access.md': 'CUSTOM ACCESS RULES',
|
|
242
|
+
'KnowledgeBase/Real/Knowledge/.gitkeep': '',
|
|
243
|
+
'Groups/.gitkeep': '',
|
|
244
|
+
});
|
|
245
|
+
|
|
246
|
+
const first = await checkout(root, upstream, DEFAULT_BRANCH);
|
|
247
|
+
await makeSeeder(upstream).topUpWorkspace(first, DEFAULT_BRANCH);
|
|
248
|
+
const after = await headCommitCount(root, upstream, DEFAULT_BRANCH);
|
|
249
|
+
// Only the pre-seed commit: nothing was missing, nothing was stale.
|
|
250
|
+
expect(after).toBe(1);
|
|
251
|
+
});
|
|
252
|
+
|
|
174
253
|
it('topUpWorkspace is idempotent — a second load makes no new commit', async () => {
|
|
175
254
|
const upstream = await seededUpstream(PROTECTED, {
|
|
176
255
|
'roles.yaml': 'roles:\n Admin:\n - keep@example.com\n',
|
|
177
256
|
'KnowledgeBase/Real/Knowledge/.gitkeep': '',
|
|
178
|
-
'
|
|
257
|
+
'Groups/.gitkeep': '',
|
|
179
258
|
});
|
|
180
259
|
|
|
181
260
|
const first = await checkout(root, upstream, DEFAULT_BRANCH);
|
|
@@ -191,23 +270,175 @@ describe('KbSeedService', () => {
|
|
|
191
270
|
expect(after2).toBe(after1);
|
|
192
271
|
});
|
|
193
272
|
|
|
194
|
-
|
|
273
|
+
});
|
|
274
|
+
|
|
275
|
+
/**
|
|
276
|
+
* A distribution that owns folders core has no feature for — the agentic
|
|
277
|
+
* execution layer's `Data/`, `Agents/`, `Pipelines/` — claims them through
|
|
278
|
+
* `extraDirs` (wired from `CorePorts.kbExtraRootDirs`).
|
|
279
|
+
*
|
|
280
|
+
* The point is that claiming a root does NOT require forking the packaged
|
|
281
|
+
* template: `TEMPLATE_DIR` here is core's, which carries no entry for any of
|
|
282
|
+
* these, and the folders still arrive. Their `.gitkeep` is written rather
|
|
283
|
+
* than copied for exactly that reason.
|
|
284
|
+
*/
|
|
285
|
+
/**
|
|
286
|
+
* A knowledge base seeded before AGENTS.md was named that: top-up adds the
|
|
287
|
+
* file, and the `.bevelignore` already there lists only the old name — so
|
|
288
|
+
* without this the conventions doc starts showing in the file tree and the
|
|
289
|
+
* agent view on every existing deployment. We created the mismatch by adding
|
|
290
|
+
* the file, so top-up closes it.
|
|
291
|
+
*/
|
|
292
|
+
describe('the pre-rename ignore file', () => {
|
|
293
|
+
const legacy = (ignore: string): Record<string, string> => ({
|
|
294
|
+
'KnowledgeBase/.gitkeep': '',
|
|
295
|
+
'Groups/.gitkeep': '',
|
|
296
|
+
'access.md': '---\nwrite:\n - Admin\n---\n',
|
|
297
|
+
'roles.yaml': 'roles:\n Admin:\n - a@example.com\n',
|
|
298
|
+
'.gitignore': '',
|
|
299
|
+
'.bevelignore': ignore,
|
|
300
|
+
});
|
|
301
|
+
|
|
302
|
+
it('learns about AGENTS.md when top-up adds one', async () => {
|
|
303
|
+
const upstream = await seededUpstream([DEFAULT_BRANCH], {
|
|
304
|
+
...legacy('# mine\n.gitignore\nCLAUDE.md\nMy-Own-Rule/\n'),
|
|
305
|
+
'CLAUDE.md': '# conventions',
|
|
306
|
+
});
|
|
307
|
+
const repoDir = await checkout(root, upstream, DEFAULT_BRANCH);
|
|
308
|
+
await makeSeeder(upstream).topUpWorkspace(repoDir, DEFAULT_BRANCH);
|
|
309
|
+
|
|
310
|
+
const dir = await checkout(root, upstream, DEFAULT_BRANCH);
|
|
311
|
+
expect(await exists(path.join(dir, 'AGENTS.md'))).toBe(true);
|
|
312
|
+
const ignore = await fs.readFile(path.join(dir, '.bevelignore'), 'utf8');
|
|
313
|
+
expect(ignore.split('\n').map((l) => l.trim())).toContain('AGENTS.md');
|
|
314
|
+
// The operator's own rules survive — this appends, it does not rewrite.
|
|
315
|
+
expect(ignore).toContain('My-Own-Rule/');
|
|
316
|
+
expect(ignore).toContain('CLAUDE.md');
|
|
317
|
+
});
|
|
318
|
+
|
|
319
|
+
it('is left alone when it already knows the pattern', async () => {
|
|
320
|
+
const upstream = await seededUpstream([DEFAULT_BRANCH], legacy('AGENTS.md\n'));
|
|
321
|
+
const repoDir = await checkout(root, upstream, DEFAULT_BRANCH);
|
|
322
|
+
await makeSeeder(upstream).topUpWorkspace(repoDir, DEFAULT_BRANCH);
|
|
323
|
+
|
|
324
|
+
const dir = await checkout(root, upstream, DEFAULT_BRANCH);
|
|
325
|
+
const ignore = await fs.readFile(path.join(dir, '.bevelignore'), 'utf8');
|
|
326
|
+
expect(ignore.split('\n').filter((l) => l.trim() === 'AGENTS.md')).toHaveLength(1);
|
|
327
|
+
});
|
|
328
|
+
});
|
|
329
|
+
|
|
330
|
+
describe('distribution-reserved roots', () => {
|
|
331
|
+
it('creates extra roots that the template knows nothing about', async () => {
|
|
332
|
+
const upstream = await emptyUpstream();
|
|
333
|
+
await makeSeeder(upstream, ADMINS, ['Data', 'Agents', 'Pipelines']).ensureRemoteSeeded();
|
|
334
|
+
|
|
335
|
+
const dir = await checkout(root, upstream, DEFAULT_BRANCH);
|
|
336
|
+
// Core's two, still there.
|
|
337
|
+
expect(await exists(path.join(dir, 'KnowledgeBase/.gitkeep'))).toBe(true);
|
|
338
|
+
expect(await exists(path.join(dir, 'Groups/.gitkeep'))).toBe(true);
|
|
339
|
+
// …and the three this distribution asked for.
|
|
340
|
+
for (const claimed of ['Data', 'Agents', 'Pipelines']) {
|
|
341
|
+
expect(await exists(path.join(dir, `${claimed}/.gitkeep`))).toBe(true);
|
|
342
|
+
}
|
|
343
|
+
});
|
|
344
|
+
|
|
345
|
+
/**
|
|
346
|
+
* The name is joined onto the repo root and onto `<dir>/.gitkeep`, so a
|
|
347
|
+
* separator or a `..` would write outside the repo being seeded. Refused
|
|
348
|
+
* at CONSTRUCTION, so a bad value surfaces at boot rather than part-way
|
|
349
|
+
* through seeding somebody's knowledge base.
|
|
350
|
+
*/
|
|
351
|
+
it.each(['../escape', 'nested/dir', '/absolute', '..', '.', ''])(
|
|
352
|
+
'refuses %j as a reserved root',
|
|
353
|
+
(bad) => {
|
|
354
|
+
expect(() => makeSeeder('unused', ADMINS, [bad])).toThrow(/single path segment/);
|
|
355
|
+
},
|
|
356
|
+
);
|
|
357
|
+
|
|
358
|
+
/**
|
|
359
|
+
* Being reserved is what makes a name worth claiming — the file tree
|
|
360
|
+
* renders it as its own root instead of folding it into Knowledge — so the
|
|
361
|
+
* names in `kb-layout.ts` must stay ACCEPTED here. A guard that rejected
|
|
362
|
+
* them would reject the only real use of this argument.
|
|
363
|
+
*/
|
|
364
|
+
/**
|
|
365
|
+
* A root named after a required FILE is a typo whose outcome is silence:
|
|
366
|
+
* the file is laid down first in both seed paths, so `ensureRequiredDirs`
|
|
367
|
+
* finds the path taken and skips it, and the directory never appears with
|
|
368
|
+
* nothing said about why. Refused at construction instead.
|
|
369
|
+
*/
|
|
370
|
+
it.each(['access.md', 'AGENTS.md', '.bevelignore', '.gitignore'])(
|
|
371
|
+
'refuses %j, which is a required file rather than a root',
|
|
372
|
+
(collide) => {
|
|
373
|
+
expect(() => makeSeeder('unused', ADMINS, [collide])).toThrow(/collides with a required file/);
|
|
374
|
+
},
|
|
375
|
+
);
|
|
376
|
+
|
|
377
|
+
it('accepts the reserved names a distribution actually claims', () => {
|
|
378
|
+
expect(() => makeSeeder('unused', ADMINS, ['Data', 'Agents', 'Pipelines'])).not.toThrow();
|
|
379
|
+
});
|
|
380
|
+
|
|
381
|
+
/**
|
|
382
|
+
* A FILE named `Groups` used to satisfy the presence check — `fs.access`
|
|
383
|
+
* answers "is there something here?" — so the seeder skipped it, said
|
|
384
|
+
* nothing, and left a knowledge base permanently missing a root it claims
|
|
385
|
+
* to guarantee. Now it says so.
|
|
386
|
+
*
|
|
387
|
+
* Surfaces as a warning rather than a crash on this path: `topUpWorkspace`
|
|
388
|
+
* is documented best-effort and must never block a user from loading a
|
|
389
|
+
* branch. The point is that the condition is REPORTED at all.
|
|
390
|
+
*/
|
|
391
|
+
it('refuses a required root that exists as a file, instead of skipping it', async () => {
|
|
392
|
+
const upstream = await seededUpstream([DEFAULT_BRANCH], {
|
|
393
|
+
'AGENTS.md': '# x',
|
|
394
|
+
'access.md': 'read:\n - everyone\n',
|
|
395
|
+
'.bevelignore': '',
|
|
396
|
+
'.gitignore': '',
|
|
397
|
+
'KnowledgeBase/.gitkeep': '',
|
|
398
|
+
// Not a folder.
|
|
399
|
+
Groups: 'this is a file, not the groups root',
|
|
400
|
+
});
|
|
401
|
+
const repoDir = await checkout(root, upstream, DEFAULT_BRANCH);
|
|
402
|
+
const warn = vi.spyOn(console, 'warn').mockImplementation(() => {});
|
|
403
|
+
try {
|
|
404
|
+
await makeSeeder(upstream).topUpWorkspace(repoDir, DEFAULT_BRANCH);
|
|
405
|
+
expect(warn.mock.calls.flat().join(' ')).toMatch(/Groups.*not a directory/);
|
|
406
|
+
} finally {
|
|
407
|
+
warn.mockRestore();
|
|
408
|
+
}
|
|
409
|
+
// …and it did not quietly replace the file either.
|
|
410
|
+
expect((await fs.lstat(path.join(repoDir, 'Groups'))).isFile()).toBe(true);
|
|
411
|
+
});
|
|
412
|
+
|
|
413
|
+
/**
|
|
414
|
+
* A non-protected branch is somebody's change-in-waiting — a suggestions
|
|
415
|
+
* branch behind an open change request, a personal draft — and a
|
|
416
|
+
* scaffolding commit landing on it shows up as noise in their diff
|
|
417
|
+
* against the default branch (a stray scaffolding file riding along in a
|
|
418
|
+
* skill proposal was the observed symptom). Whatever the protected
|
|
419
|
+
* branches lack, they get when THEY load; drafts fork from them.
|
|
420
|
+
*/
|
|
421
|
+
it('topUpWorkspace leaves non-protected branches alone', async () => {
|
|
195
422
|
const upstream = await seededUpstream(PROTECTED, {
|
|
196
423
|
'roles.yaml': 'roles:\n Admin:\n - keep@example.com\n',
|
|
197
424
|
'KnowledgeBase/Real/Knowledge/.gitkeep': '',
|
|
198
|
-
'
|
|
425
|
+
'Groups/.gitkeep': '',
|
|
199
426
|
});
|
|
200
|
-
// Branch a
|
|
427
|
+
// Branch a suggestion off the default and load it.
|
|
201
428
|
const seed = await checkout(root, upstream, DEFAULT_BRANCH);
|
|
202
|
-
await git(seed, ['checkout', '-b', 'alice/
|
|
203
|
-
await git(seed, ['push', 'origin', 'alice/
|
|
429
|
+
await git(seed, ['checkout', '-b', 'suggestions/alice/knowledge']);
|
|
430
|
+
await git(seed, ['push', 'origin', 'suggestions/alice/knowledge']);
|
|
204
431
|
|
|
205
|
-
const
|
|
206
|
-
await
|
|
432
|
+
const before = await headCommitCount(root, upstream, 'suggestions/alice/knowledge');
|
|
433
|
+
const repoDir = await checkout(root, upstream, 'suggestions/alice/knowledge');
|
|
434
|
+
await makeSeeder(upstream).topUpWorkspace(repoDir, 'suggestions/alice/knowledge');
|
|
207
435
|
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
436
|
+
// No scaffolding commit: the branch's diff against the default branch
|
|
437
|
+
// stays exactly what its author put there.
|
|
438
|
+
const after = await headCommitCount(root, upstream, 'suggestions/alice/knowledge');
|
|
439
|
+
expect(after).toBe(before);
|
|
440
|
+
const dir = await checkout(root, upstream, 'suggestions/alice/knowledge');
|
|
441
|
+
expect(await exists(path.join(dir, 'AGENTS.md'))).toBe(false);
|
|
211
442
|
});
|
|
212
443
|
});
|
|
213
444
|
});
|