@bevel-software/platform-core-backend 0.7.4 → 0.8.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 +202 -202
- package/THIRD-PARTY-NOTICES.md +428 -454
- package/dist/core/core-ports.d.ts +1 -1
- package/dist/core/create-core-server.d.ts.map +1 -1
- package/dist/core/create-core-server.js +51 -7
- package/dist/core/create-core-server.js.map +1 -1
- package/dist/core/create-core-services.d.ts +5 -3
- package/dist/core/create-core-services.d.ts.map +1 -1
- package/dist/core/create-core-services.js +38 -21
- package/dist/core/create-core-services.js.map +1 -1
- package/dist/modules/access/access-control.interface.d.ts +8 -7
- package/dist/modules/access/access-control.interface.d.ts.map +1 -1
- package/dist/modules/access/access-control.service.d.ts +1 -1
- package/dist/modules/access/access-control.service.d.ts.map +1 -1
- package/dist/modules/access/access-control.service.js +6 -6
- package/dist/modules/access/access-control.service.js.map +1 -1
- package/dist/modules/access/access-declarations.d.ts +5 -5
- package/dist/modules/access/access-declarations.js +3 -3
- package/dist/modules/access/access-mutation.service.d.ts +3 -3
- package/dist/modules/access/access-mutation.service.d.ts.map +1 -1
- package/dist/modules/access/access-mutation.service.js +3 -3
- package/dist/modules/access/access-mutation.service.js.map +1 -1
- package/dist/modules/access/access-splice.js +4 -4
- package/dist/modules/access/access-splice.js.map +1 -1
- package/dist/modules/access/access.routes.js +19 -19
- package/dist/modules/access/access.routes.js.map +1 -1
- package/dist/modules/access/creator-access.d.ts +2 -2
- package/dist/modules/access/creator-access.js +5 -5
- package/dist/modules/access/creator-access.js.map +1 -1
- package/dist/modules/access/roles-admin.service.d.ts +18 -4
- package/dist/modules/access/roles-admin.service.d.ts.map +1 -1
- package/dist/modules/access/roles-admin.service.js +14 -4
- package/dist/modules/access/roles-admin.service.js.map +1 -1
- package/dist/modules/code-mode/code-mode-names.d.ts +5 -13
- package/dist/modules/code-mode/code-mode-names.d.ts.map +1 -1
- package/dist/modules/code-mode/code-mode-names.js +5 -27
- package/dist/modules/code-mode/code-mode-names.js.map +1 -1
- package/dist/modules/code-mode/code-mode.tool.d.ts.map +1 -1
- package/dist/modules/code-mode/code-mode.tool.js +29 -7
- package/dist/modules/code-mode/code-mode.tool.js.map +1 -1
- package/dist/modules/mcp/mcp.service.d.ts +11 -52
- package/dist/modules/mcp/mcp.service.d.ts.map +1 -1
- package/dist/modules/mcp/mcp.service.js +33 -395
- package/dist/modules/mcp/mcp.service.js.map +1 -1
- package/dist/modules/plugins/index.d.ts +7 -0
- package/dist/modules/plugins/index.d.ts.map +1 -0
- package/dist/modules/plugins/index.js +6 -0
- package/dist/modules/plugins/index.js.map +1 -0
- package/dist/modules/plugins/join-proposals.d.ts +53 -0
- package/dist/modules/plugins/join-proposals.d.ts.map +1 -0
- package/dist/modules/plugins/join-proposals.js +67 -0
- package/dist/modules/plugins/join-proposals.js.map +1 -0
- package/dist/modules/plugins/join-requests.service.d.ts +81 -0
- package/dist/modules/plugins/join-requests.service.d.ts.map +1 -0
- package/dist/modules/plugins/join-requests.service.js +135 -0
- package/dist/modules/plugins/join-requests.service.js.map +1 -0
- package/dist/modules/plugins/plugin-provision.service.d.ts +134 -0
- package/dist/modules/plugins/plugin-provision.service.d.ts.map +1 -0
- package/dist/modules/plugins/plugin-provision.service.js +344 -0
- package/dist/modules/plugins/plugin-provision.service.js.map +1 -0
- package/dist/modules/plugins/plugins.contract.d.ts +106 -0
- package/dist/modules/plugins/plugins.contract.d.ts.map +1 -0
- package/dist/modules/plugins/plugins.contract.js +36 -0
- package/dist/modules/plugins/plugins.contract.js.map +1 -0
- package/dist/modules/plugins/plugins.routes.d.ts +42 -0
- package/dist/modules/plugins/plugins.routes.d.ts.map +1 -0
- package/dist/modules/plugins/plugins.routes.js +379 -0
- package/dist/modules/plugins/plugins.routes.js.map +1 -0
- package/dist/modules/plugins/plugins.service.d.ts +60 -0
- package/dist/modules/plugins/plugins.service.d.ts.map +1 -0
- package/dist/modules/plugins/plugins.service.js +172 -0
- package/dist/modules/plugins/plugins.service.js.map +1 -0
- package/dist/modules/skills/pending-skills.service.d.ts +2 -2
- package/dist/modules/skills/pending-skills.service.js +7 -7
- package/dist/modules/skills/pending-skills.service.js.map +1 -1
- package/dist/modules/skills/skills.contract.d.ts +4 -4
- 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.service.js +5 -5
- package/dist/modules/skills/skills.service.js.map +1 -1
- package/dist/modules/tool-manuals/mcp-json-discovery.d.ts +65 -0
- package/dist/modules/tool-manuals/mcp-json-discovery.d.ts.map +1 -0
- package/dist/modules/tool-manuals/mcp-json-discovery.js +276 -0
- package/dist/modules/tool-manuals/mcp-json-discovery.js.map +1 -0
- package/dist/modules/tool-manuals/mcp-server-edit.service.d.ts +92 -0
- package/dist/modules/tool-manuals/mcp-server-edit.service.d.ts.map +1 -0
- package/dist/modules/tool-manuals/mcp-server-edit.service.js +328 -0
- package/dist/modules/tool-manuals/mcp-server-edit.service.js.map +1 -0
- package/dist/modules/tool-manuals/tool-manuals.contract.d.ts +38 -12
- 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 +13 -2
- package/dist/modules/tool-manuals/tool-manuals.routes.d.ts.map +1 -1
- package/dist/modules/tool-manuals/tool-manuals.routes.js +233 -2
- package/dist/modules/tool-manuals/tool-manuals.routes.js.map +1 -1
- package/dist/modules/tool-manuals/tool-manuals.service.d.ts.map +1 -1
- package/dist/modules/tool-manuals/tool-manuals.service.js +74 -37
- package/dist/modules/tool-manuals/tool-manuals.service.js.map +1 -1
- package/dist/modules/tool-manuals/tool-manuals.tools.js +6 -3
- package/dist/modules/tool-manuals/tool-manuals.tools.js.map +1 -1
- package/dist/modules/workflow/git/git.service.js +2 -2
- package/dist/modules/workflow/git/git.service.js.map +1 -1
- package/dist/modules/workflow/pending-commits.service.d.ts +11 -0
- package/dist/modules/workflow/pending-commits.service.d.ts.map +1 -1
- package/dist/modules/workflow/pending-commits.service.js +37 -9
- package/dist/modules/workflow/pending-commits.service.js.map +1 -1
- package/dist/modules/workflow/pending-commits.worker.d.ts +17 -4
- package/dist/modules/workflow/pending-commits.worker.d.ts.map +1 -1
- package/dist/modules/workflow/pending-commits.worker.js +63 -9
- package/dist/modules/workflow/pending-commits.worker.js.map +1 -1
- package/dist/modules/workflow/workflow.service.d.ts +1 -0
- package/dist/modules/workflow/workflow.service.d.ts.map +1 -1
- package/dist/modules/workflow/workflow.service.js +6 -1
- package/dist/modules/workflow/workflow.service.js.map +1 -1
- package/dist/modules/workspace/kb-seed.service.d.ts +2 -2
- package/dist/modules/workspace/kb-seed.service.d.ts.map +1 -1
- package/dist/modules/workspace/kb-seed.service.js +43 -10
- package/dist/modules/workspace/kb-seed.service.js.map +1 -1
- package/dist/modules/workspace/plugins-migration.d.ts +50 -0
- package/dist/modules/workspace/plugins-migration.d.ts.map +1 -0
- package/dist/modules/workspace/plugins-migration.js +379 -0
- package/dist/modules/workspace/plugins-migration.js.map +1 -0
- package/dist/modules/workspace/workspace.routes.js +3 -3
- package/dist/modules/workspace/workspace.routes.js.map +1 -1
- package/dist/modules/workspace/workspace.service.d.ts +26 -0
- package/dist/modules/workspace/workspace.service.d.ts.map +1 -1
- package/dist/modules/workspace/workspace.service.js +83 -12
- package/dist/modules/workspace/workspace.service.js.map +1 -1
- package/dist/shared/kb-layout.test.js +3 -3
- package/dist/shared/kb-layout.test.js.map +1 -1
- package/dist/shared/utcp-namespace.d.ts +6 -27
- package/dist/shared/utcp-namespace.d.ts.map +1 -1
- package/dist/shared/utcp-namespace.js +6 -63
- package/dist/shared/utcp-namespace.js.map +1 -1
- package/dist/shared/variable-refs.d.ts +42 -0
- package/dist/shared/variable-refs.d.ts.map +1 -0
- package/dist/shared/variable-refs.js +60 -0
- package/dist/shared/variable-refs.js.map +1 -0
- package/kb-template/.bevelignore +1 -1
- package/kb-template/AGENTS.md +88 -35
- package/kb-template/KnowledgeBase/How to get started.md +10 -10
- package/kb-template/access.md +36 -36
- package/migrations/meta/0000_snapshot.json +1479 -1479
- package/package.json +5 -4
- package/src/assets.ts +25 -25
- package/src/core/core-ports.ts +106 -106
- package/src/core/create-core-server.ts +55 -9
- package/src/core/create-core-services.ts +48 -24
- package/src/index.ts +69 -69
- package/src/modules/access/__tests__/access-control.atref-batch.test.ts +98 -98
- package/src/modules/access/__tests__/access-declarations.test.ts +28 -28
- package/src/modules/access/__tests__/access-md-format.test.ts +18 -18
- package/src/modules/access/__tests__/access-mutation.service.test.ts +5 -5
- package/src/modules/access/__tests__/access-splice.test.ts +2 -2
- package/src/modules/access/__tests__/access.routes.overrides.test.ts +16 -16
- package/src/modules/access/__tests__/grant-sources.test.ts +12 -12
- package/src/modules/access/__tests__/roles-admin.service.test.ts +13 -1
- package/src/modules/access/access-control.interface.ts +8 -7
- package/src/modules/access/access-control.service.ts +7 -7
- package/src/modules/access/access-declarations.ts +5 -5
- package/src/modules/access/access-mutation.service.ts +3 -3
- package/src/modules/access/access-splice.ts +4 -4
- package/src/modules/access/access.routes.ts +20 -20
- package/src/modules/access/creator-access.ts +5 -5
- package/src/modules/access/roles-admin.service.ts +13 -2
- package/src/modules/admin/admin-access.routes.ts +29 -29
- package/src/modules/auth/__tests__/auth.routes.test.ts +91 -91
- package/src/modules/auth/__tests__/rate-limit.test.ts +36 -36
- package/src/modules/auth/rate-limit.ts +45 -45
- package/src/modules/code-mode/__tests__/code-mode.tool.test.ts +67 -0
- package/src/modules/code-mode/code-mode-names.ts +10 -36
- package/src/modules/code-mode/code-mode.tool.ts +27 -7
- package/src/modules/database/connection.ts +15 -15
- package/src/modules/database/schema.ts +11 -11
- package/src/modules/diff/__tests__/diff.routes.rejectPathsLocked.test.ts +150 -150
- package/src/modules/mcp/mcp.service.ts +57 -435
- package/src/modules/{groups → plugins}/__tests__/join-proposals.test.ts +1 -1
- package/src/modules/{groups → plugins}/__tests__/join-requests.service.test.ts +7 -7
- package/src/modules/{groups/__tests__/group-index.service.test.ts → plugins/__tests__/plugin-index.service.test.ts} +41 -41
- package/src/modules/plugins/__tests__/plugin-provision.service.test.ts +312 -0
- package/src/modules/{groups/__tests__/groups.routes.test.ts → plugins/__tests__/plugins.routes.test.ts} +100 -100
- package/src/modules/plugins/index.ts +17 -0
- package/src/modules/{groups → plugins}/join-proposals.ts +2 -2
- package/src/modules/{groups → plugins}/join-requests.service.ts +8 -8
- package/src/modules/{groups/group-provision.service.ts → plugins/plugin-provision.service.ts} +139 -69
- package/src/modules/{groups/groups.contract.ts → plugins/plugins.contract.ts} +26 -26
- package/src/modules/{groups/groups.routes.ts → plugins/plugins.routes.ts} +102 -102
- package/src/modules/{groups/groups.service.ts → plugins/plugins.service.ts} +43 -43
- package/src/modules/secrets-vault/__tests__/tool-owner-gate.route.test.ts +143 -143
- package/src/modules/skills/__tests__/pending-skills.service.test.ts +14 -14
- package/src/modules/skills/__tests__/skills.service.test.ts +13 -13
- package/src/modules/skills/pending-skills.service.ts +7 -7
- package/src/modules/skills/skills.contract.ts +4 -4
- package/src/modules/skills/skills.service.ts +5 -5
- package/src/modules/tool-auth/llm-usage-meter.ts +19 -19
- package/src/modules/tool-manuals/__tests__/mcp-json-discovery.test.ts +198 -0
- package/src/modules/tool-manuals/__tests__/mcp-server-edit.service.test.ts +346 -0
- package/src/modules/tool-manuals/__tests__/tool-manuals.archive.route.test.ts +101 -0
- package/src/modules/tool-manuals/__tests__/tool-manuals.detail.route.test.ts +3 -3
- 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 +27 -27
- package/src/modules/tool-manuals/__tests__/tool-manuals.tools.test.ts +3 -3
- package/src/modules/tool-manuals/mcp-json-discovery.ts +328 -0
- package/src/modules/tool-manuals/mcp-server-edit.service.ts +434 -0
- package/src/modules/tool-manuals/tool-manuals.contract.ts +35 -12
- package/src/modules/tool-manuals/tool-manuals.routes.ts +222 -1
- package/src/modules/tool-manuals/tool-manuals.service.ts +82 -42
- package/src/modules/tool-manuals/tool-manuals.tools.ts +6 -3
- package/src/modules/workflow/__tests__/pending-commits.worker.test.ts +118 -0
- package/src/modules/workflow/__tests__/workflow.service.facade.test.ts +1 -1
- package/src/modules/workflow/git/__tests__/branch-name.test.ts +3 -3
- package/src/modules/workflow/git/__tests__/git.service.accessGating.test.ts +3 -3
- package/src/modules/workflow/git/__tests__/git.service.commitFile.test.ts +13 -8
- package/src/modules/workflow/git/__tests__/git.service.deleteBranch.test.ts +1 -1
- package/src/modules/workflow/git/__tests__/pull-request.service.test.ts +1 -1
- package/src/modules/workflow/git/git.service.ts +2 -2
- package/src/modules/workflow/pending-commits.service.ts +48 -12
- package/src/modules/workflow/pending-commits.worker.ts +64 -8
- package/src/modules/workflow/review-workflow/__tests__/approval-states.test.ts +1 -1
- package/src/modules/workflow/review-workflow/__tests__/cancel-pr.test.ts +1 -1
- package/src/modules/workflow/workflow-hooks.ts +101 -101
- package/src/modules/workflow/workflow.service.ts +13 -2
- package/src/modules/workspace/__tests__/kb-seed.service.test.ts +81 -13
- package/src/modules/workspace/__tests__/plugins-migration.test.ts +427 -0
- package/src/modules/workspace/__tests__/session-ontology.gate.test.ts +237 -237
- package/src/modules/workspace/__tests__/workspace.routes.create-grant.test.ts +236 -236
- package/src/modules/workspace/__tests__/workspace.routes.delete.test.ts +179 -179
- package/src/modules/workspace/__tests__/workspace.routes.download.test.ts +320 -320
- package/src/modules/workspace/__tests__/workspace.routes.read-gate.test.ts +337 -337
- package/src/modules/workspace/__tests__/workspace.service.test.ts +116 -0
- package/src/modules/workspace/bevel-ignore.ts +66 -66
- package/src/modules/workspace/kb-seed.service.ts +38 -9
- package/src/modules/workspace/plugins-migration.ts +479 -0
- package/src/modules/workspace/session-sink.ts +25 -25
- package/src/modules/workspace/workspace.routes.ts +3 -3
- package/src/modules/workspace/workspace.service.ts +85 -14
- package/src/modules/workspace/workspace.tools.ts +922 -922
- package/src/shared/__tests__/join-request.test.ts +13 -13
- package/src/shared/__tests__/kb-layout.plugin.test.ts +45 -0
- package/src/shared/kb-layout.test.ts +3 -3
- package/src/shared/utcp-namespace.ts +10 -68
- package/src/shared/variable-refs.ts +64 -0
- package/src/modules/groups/__tests__/group-provision.service.test.ts +0 -247
- package/src/modules/groups/index.ts +0 -17
- package/src/shared/__tests__/kb-layout.group.test.ts +0 -45
- /package/kb-template/{Groups → Plugins}/.gitkeep +0 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bevel-software/platform-core-backend",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.8.0",
|
|
4
4
|
"description": "Open-source core backend of the Bevel platform: git-backed knowledge workspace, workflow (branches/change requests/locks/SSE), skills, tools, secrets vault, access control and the remote MCP surface.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -36,7 +36,7 @@
|
|
|
36
36
|
"@utcp/http": "^1.1.7",
|
|
37
37
|
"@utcp/mcp": "^1.1.3",
|
|
38
38
|
"@utcp/sdk": "^1.1.1",
|
|
39
|
-
"adm-zip": "^0.
|
|
39
|
+
"adm-zip": "^0.6.0",
|
|
40
40
|
"cors": "^2.8.5",
|
|
41
41
|
"dotenv": "^16.4.0",
|
|
42
42
|
"drizzle-orm": "^0.45.2",
|
|
@@ -46,7 +46,8 @@
|
|
|
46
46
|
"pg": "^8.20.0",
|
|
47
47
|
"yaml": "^2.9.0",
|
|
48
48
|
"zod": "^3.24.0",
|
|
49
|
-
"@bevel-software/platform-
|
|
49
|
+
"@bevel-software/platform-mcp-core": "0.8.0",
|
|
50
|
+
"@bevel-software/platform-shared": "0.8.0"
|
|
50
51
|
},
|
|
51
52
|
"devDependencies": {
|
|
52
53
|
"@types/adm-zip": "^0.5.8",
|
|
@@ -60,7 +61,7 @@
|
|
|
60
61
|
"drizzle-kit": "^0.31.10",
|
|
61
62
|
"tsx": "^4.19.0",
|
|
62
63
|
"typescript": "^5.8.0",
|
|
63
|
-
"vitest": "^2.
|
|
64
|
+
"vitest": "^3.2.6"
|
|
64
65
|
},
|
|
65
66
|
"license": "Apache-2.0",
|
|
66
67
|
"repository": {
|
package/src/assets.ts
CHANGED
|
@@ -1,25 +1,25 @@
|
|
|
1
|
-
import path from 'node:path';
|
|
2
|
-
import { fileURLToPath } from 'node:url';
|
|
3
|
-
|
|
4
|
-
/**
|
|
5
|
-
* Locations of the assets shipped INSIDE this package (`files` in
|
|
6
|
-
* package.json): the squashed core migration history (`migrations/`) and the
|
|
7
|
-
* KB seed template (`kb-template/`). Both live at the PACKAGE ROOT, and this
|
|
8
|
-
* module is a direct child of either `src/` (in-repo / tsx) or `dist/`
|
|
9
|
-
* (compiled) — so one `..` hop from the module URL reaches the package root
|
|
10
|
-
* in BOTH layouts. Resolved lazily so bundlers that rewrite `import.meta.url`
|
|
11
|
-
* still get a sensible answer at call time.
|
|
12
|
-
*/
|
|
13
|
-
function packageRoot(): string {
|
|
14
|
-
return fileURLToPath(new URL('..', import.meta.url));
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
/** Absolute path of the packaged core Drizzle migrations folder. */
|
|
18
|
-
export function coreMigrationsDir(): string {
|
|
19
|
-
return path.join(packageRoot(), 'migrations');
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
/** Absolute path of the packaged KB seed template (`kb-template/`). */
|
|
23
|
-
export function defaultKbTemplateDir(): string {
|
|
24
|
-
return path.join(packageRoot(), 'kb-template');
|
|
25
|
-
}
|
|
1
|
+
import path from 'node:path';
|
|
2
|
+
import { fileURLToPath } from 'node:url';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Locations of the assets shipped INSIDE this package (`files` in
|
|
6
|
+
* package.json): the squashed core migration history (`migrations/`) and the
|
|
7
|
+
* KB seed template (`kb-template/`). Both live at the PACKAGE ROOT, and this
|
|
8
|
+
* module is a direct child of either `src/` (in-repo / tsx) or `dist/`
|
|
9
|
+
* (compiled) — so one `..` hop from the module URL reaches the package root
|
|
10
|
+
* in BOTH layouts. Resolved lazily so bundlers that rewrite `import.meta.url`
|
|
11
|
+
* still get a sensible answer at call time.
|
|
12
|
+
*/
|
|
13
|
+
function packageRoot(): string {
|
|
14
|
+
return fileURLToPath(new URL('..', import.meta.url));
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/** Absolute path of the packaged core Drizzle migrations folder. */
|
|
18
|
+
export function coreMigrationsDir(): string {
|
|
19
|
+
return path.join(packageRoot(), 'migrations');
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/** Absolute path of the packaged KB seed template (`kb-template/`). */
|
|
23
|
+
export function defaultKbTemplateDir(): string {
|
|
24
|
+
return path.join(packageRoot(), 'kb-template');
|
|
25
|
+
}
|
package/src/core/core-ports.ts
CHANGED
|
@@ -1,106 +1,106 @@
|
|
|
1
|
-
import type { ISessionSink } from '../modules/workspace/session-sink.js';
|
|
2
|
-
import type {
|
|
3
|
-
ISystemNoticeSink,
|
|
4
|
-
RecoveryAgentRunner,
|
|
5
|
-
} from '../modules/workflow/pending-commits.worker.js';
|
|
6
|
-
import type { ILlmUsageMeter } from '../modules/tool-auth/llm-usage-meter.js';
|
|
7
|
-
import type { AuthProviderPlugin } from '../modules/auth/auth.routes.js';
|
|
8
|
-
import type { IErasureParticipant } from '../modules/auth/account-erasure.service.js';
|
|
9
|
-
|
|
10
|
-
/**
|
|
11
|
-
* Every seam the enterprise overlay can fill in the CORE composition
|
|
12
|
-
* (`createCoreServices`). All fields are optional; each has a safe core-only
|
|
13
|
-
* default, so `createCoreServices(config)` with no ports yields a fully
|
|
14
|
-
* working core deployment.
|
|
15
|
-
*
|
|
16
|
-
* Two consumption patterns exist, and they matter for wiring order:
|
|
17
|
-
*
|
|
18
|
-
* - CONSTRUCTION-TIME ports (`recoveryAgent`, `systemNotice`,
|
|
19
|
-
* `erasureParticipants`): dereferenced while core services are being
|
|
20
|
-
* constructed. Enterprise implementations of these need core services that
|
|
21
|
-
* don't exist yet at that point (the background-agent factory, the thread
|
|
22
|
-
* service, …), so the enterprise root passes FORWARDING DELEGATORS / a
|
|
23
|
-
* mutable array here and assigns the real targets right after
|
|
24
|
-
* `createCoreServices` returns. That is safe because core only *calls* these
|
|
25
|
-
* ports at request/commit/erasure time, long after boot — the same
|
|
26
|
-
* late-binding pattern the composition root already uses for e.g. the MCP
|
|
27
|
-
* OAuth revoke closure.
|
|
28
|
-
*
|
|
29
|
-
* - SERVER-TIME seams (`sessionSink`, `usageMeter`, `authProviders`): only
|
|
30
|
-
* read when `createCoreServer` mounts routes / registers tools. Core seeds
|
|
31
|
-
* them onto `CoreServices` from these ports (with the defaults below); the
|
|
32
|
-
* enterprise root overwrites the `CoreServices` fields (or pushes into the
|
|
33
|
-
* `authProviders` array) after construction, before the server is built.
|
|
34
|
-
*
|
|
35
|
-
* (Commit-time KB validation and the ontology write block are NOT ports:
|
|
36
|
-
* they are workflow lifecycle HOOKS the enterprise root registers on
|
|
37
|
-
* `workflowService.hooks` after construction — see
|
|
38
|
-
* `modules/workflow/workflow-hooks.ts`.)
|
|
39
|
-
*/
|
|
40
|
-
export interface CorePorts {
|
|
41
|
-
/**
|
|
42
|
-
* Backs the `start_session` tool. Core default: {@link UuidSessionSink}
|
|
43
|
-
* (a bare random id). Enterprise substitutes a sink that mints a real chat
|
|
44
|
-
* thread so the same id works end to end with `ask`.
|
|
45
|
-
*/
|
|
46
|
-
sessionSink?: ISessionSink;
|
|
47
|
-
/**
|
|
48
|
-
* Recovery-agent dispatcher for the pending-commits worker. The worker
|
|
49
|
-
* requires one, so the core default is {@link noopRecoveryAgent} — a run
|
|
50
|
-
* that just returns, meaning the row stays pending until the recovery
|
|
51
|
-
* budget is exhausted and the worker escalates via `systemNotice`.
|
|
52
|
-
*/
|
|
53
|
-
recoveryAgent?: RecoveryAgentRunner;
|
|
54
|
-
/**
|
|
55
|
-
* Where the pending-commits worker escalates terminal failures. Core
|
|
56
|
-
* default: {@link consoleSystemNoticeSink} (stderr, no dashboard).
|
|
57
|
-
* Enterprise passes its feedback service.
|
|
58
|
-
*/
|
|
59
|
-
systemNotice?: ISystemNoticeSink;
|
|
60
|
-
/**
|
|
61
|
-
* Per-connection-key LLM usage metering shown on the connection-key
|
|
62
|
-
* management routes. Core default: {@link unmeteredLlmUsage} (no proxy,
|
|
63
|
-
* nothing to meter). Enterprise passes the LLM proxy's usage service.
|
|
64
|
-
*/
|
|
65
|
-
usageMeter?: ILlmUsageMeter;
|
|
66
|
-
/**
|
|
67
|
-
* SSO login plugins the auth router mounts. Core default: `[]` (password
|
|
68
|
-
* login only). The array instance is kept on `CoreServices.authProviders`,
|
|
69
|
-
* so an enterprise root may pass an array it fills after construction.
|
|
70
|
-
*/
|
|
71
|
-
authProviders?: AuthProviderPlugin[];
|
|
72
|
-
/**
|
|
73
|
-
* Module-owned GDPR-erasure slices run by `AccountErasureService`. Core
|
|
74
|
-
* default: `[]` (core erases only the rows it owns). The array reference is
|
|
75
|
-
* held — not copied — so an enterprise root may pass an array it fills after
|
|
76
|
-
* construction (participants are only iterated at erasure time).
|
|
77
|
-
*/
|
|
78
|
-
erasureParticipants?: IErasureParticipant[];
|
|
79
|
-
/**
|
|
80
|
-
* Root folders THIS distribution reserves in the knowledge base, on top of
|
|
81
|
-
* core's `KnowledgeBase/` + `
|
|
82
|
-
*
|
|
83
|
-
* A name here does two things: the seeder guarantees the folder exists on
|
|
84
|
-
* every branch it tops up, and — because the names are already reserved in
|
|
85
|
-
* `kb-layout.ts` — the file tree keeps rendering it as its own root instead
|
|
86
|
-
* of folding it into Knowledge as stray content.
|
|
87
|
-
*
|
|
88
|
-
* The folder is created as an empty `<dir>/.gitkeep`, written rather than
|
|
89
|
-
* copied, so reserving a root does not oblige a distribution to fork the
|
|
90
|
-
* packaged template. Ship a `KB_TEMPLATE_DIR` of your own when those folders
|
|
91
|
-
* should arrive carrying READMEs.
|
|
92
|
-
*/
|
|
93
|
-
kbExtraRootDirs?: readonly string[];
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
/**
|
|
97
|
-
* Core default recovery agent: does nothing. The worker's retry ladder still
|
|
98
|
-
* works — a stuck row burns its recovery budget on these no-op runs and then
|
|
99
|
-
* escalates to the `systemNotice` sink, which is exactly the "no recovery
|
|
100
|
-
* agent available" behavior a core-only deployment wants.
|
|
101
|
-
*/
|
|
102
|
-
export const noopRecoveryAgent: RecoveryAgentRunner = {
|
|
103
|
-
async run(): Promise<void> {
|
|
104
|
-
// Intentionally empty — see doc comment.
|
|
105
|
-
},
|
|
106
|
-
};
|
|
1
|
+
import type { ISessionSink } from '../modules/workspace/session-sink.js';
|
|
2
|
+
import type {
|
|
3
|
+
ISystemNoticeSink,
|
|
4
|
+
RecoveryAgentRunner,
|
|
5
|
+
} from '../modules/workflow/pending-commits.worker.js';
|
|
6
|
+
import type { ILlmUsageMeter } from '../modules/tool-auth/llm-usage-meter.js';
|
|
7
|
+
import type { AuthProviderPlugin } from '../modules/auth/auth.routes.js';
|
|
8
|
+
import type { IErasureParticipant } from '../modules/auth/account-erasure.service.js';
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Every seam the enterprise overlay can fill in the CORE composition
|
|
12
|
+
* (`createCoreServices`). All fields are optional; each has a safe core-only
|
|
13
|
+
* default, so `createCoreServices(config)` with no ports yields a fully
|
|
14
|
+
* working core deployment.
|
|
15
|
+
*
|
|
16
|
+
* Two consumption patterns exist, and they matter for wiring order:
|
|
17
|
+
*
|
|
18
|
+
* - CONSTRUCTION-TIME ports (`recoveryAgent`, `systemNotice`,
|
|
19
|
+
* `erasureParticipants`): dereferenced while core services are being
|
|
20
|
+
* constructed. Enterprise implementations of these need core services that
|
|
21
|
+
* don't exist yet at that point (the background-agent factory, the thread
|
|
22
|
+
* service, …), so the enterprise root passes FORWARDING DELEGATORS / a
|
|
23
|
+
* mutable array here and assigns the real targets right after
|
|
24
|
+
* `createCoreServices` returns. That is safe because core only *calls* these
|
|
25
|
+
* ports at request/commit/erasure time, long after boot — the same
|
|
26
|
+
* late-binding pattern the composition root already uses for e.g. the MCP
|
|
27
|
+
* OAuth revoke closure.
|
|
28
|
+
*
|
|
29
|
+
* - SERVER-TIME seams (`sessionSink`, `usageMeter`, `authProviders`): only
|
|
30
|
+
* read when `createCoreServer` mounts routes / registers tools. Core seeds
|
|
31
|
+
* them onto `CoreServices` from these ports (with the defaults below); the
|
|
32
|
+
* enterprise root overwrites the `CoreServices` fields (or pushes into the
|
|
33
|
+
* `authProviders` array) after construction, before the server is built.
|
|
34
|
+
*
|
|
35
|
+
* (Commit-time KB validation and the ontology write block are NOT ports:
|
|
36
|
+
* they are workflow lifecycle HOOKS the enterprise root registers on
|
|
37
|
+
* `workflowService.hooks` after construction — see
|
|
38
|
+
* `modules/workflow/workflow-hooks.ts`.)
|
|
39
|
+
*/
|
|
40
|
+
export interface CorePorts {
|
|
41
|
+
/**
|
|
42
|
+
* Backs the `start_session` tool. Core default: {@link UuidSessionSink}
|
|
43
|
+
* (a bare random id). Enterprise substitutes a sink that mints a real chat
|
|
44
|
+
* thread so the same id works end to end with `ask`.
|
|
45
|
+
*/
|
|
46
|
+
sessionSink?: ISessionSink;
|
|
47
|
+
/**
|
|
48
|
+
* Recovery-agent dispatcher for the pending-commits worker. The worker
|
|
49
|
+
* requires one, so the core default is {@link noopRecoveryAgent} — a run
|
|
50
|
+
* that just returns, meaning the row stays pending until the recovery
|
|
51
|
+
* budget is exhausted and the worker escalates via `systemNotice`.
|
|
52
|
+
*/
|
|
53
|
+
recoveryAgent?: RecoveryAgentRunner;
|
|
54
|
+
/**
|
|
55
|
+
* Where the pending-commits worker escalates terminal failures. Core
|
|
56
|
+
* default: {@link consoleSystemNoticeSink} (stderr, no dashboard).
|
|
57
|
+
* Enterprise passes its feedback service.
|
|
58
|
+
*/
|
|
59
|
+
systemNotice?: ISystemNoticeSink;
|
|
60
|
+
/**
|
|
61
|
+
* Per-connection-key LLM usage metering shown on the connection-key
|
|
62
|
+
* management routes. Core default: {@link unmeteredLlmUsage} (no proxy,
|
|
63
|
+
* nothing to meter). Enterprise passes the LLM proxy's usage service.
|
|
64
|
+
*/
|
|
65
|
+
usageMeter?: ILlmUsageMeter;
|
|
66
|
+
/**
|
|
67
|
+
* SSO login plugins the auth router mounts. Core default: `[]` (password
|
|
68
|
+
* login only). The array instance is kept on `CoreServices.authProviders`,
|
|
69
|
+
* so an enterprise root may pass an array it fills after construction.
|
|
70
|
+
*/
|
|
71
|
+
authProviders?: AuthProviderPlugin[];
|
|
72
|
+
/**
|
|
73
|
+
* Module-owned GDPR-erasure slices run by `AccountErasureService`. Core
|
|
74
|
+
* default: `[]` (core erases only the rows it owns). The array reference is
|
|
75
|
+
* held — not copied — so an enterprise root may pass an array it fills after
|
|
76
|
+
* construction (participants are only iterated at erasure time).
|
|
77
|
+
*/
|
|
78
|
+
erasureParticipants?: IErasureParticipant[];
|
|
79
|
+
/**
|
|
80
|
+
* Root folders THIS distribution reserves in the knowledge base, on top of
|
|
81
|
+
* core's `KnowledgeBase/` + `Plugins/`. Core default: `[]`.
|
|
82
|
+
*
|
|
83
|
+
* A name here does two things: the seeder guarantees the folder exists on
|
|
84
|
+
* every branch it tops up, and — because the names are already reserved in
|
|
85
|
+
* `kb-layout.ts` — the file tree keeps rendering it as its own root instead
|
|
86
|
+
* of folding it into Knowledge as stray content.
|
|
87
|
+
*
|
|
88
|
+
* The folder is created as an empty `<dir>/.gitkeep`, written rather than
|
|
89
|
+
* copied, so reserving a root does not oblige a distribution to fork the
|
|
90
|
+
* packaged template. Ship a `KB_TEMPLATE_DIR` of your own when those folders
|
|
91
|
+
* should arrive carrying READMEs.
|
|
92
|
+
*/
|
|
93
|
+
kbExtraRootDirs?: readonly string[];
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* Core default recovery agent: does nothing. The worker's retry ladder still
|
|
98
|
+
* works — a stuck row burns its recovery budget on these no-op runs and then
|
|
99
|
+
* escalates to the `systemNotice` sink, which is exactly the "no recovery
|
|
100
|
+
* agent available" behavior a core-only deployment wants.
|
|
101
|
+
*/
|
|
102
|
+
export const noopRecoveryAgent: RecoveryAgentRunner = {
|
|
103
|
+
async run(): Promise<void> {
|
|
104
|
+
// Intentionally empty — see doc comment.
|
|
105
|
+
},
|
|
106
|
+
};
|
|
@@ -21,7 +21,7 @@ import { registerWorkflowTools } from '../modules/workflow/agent-tools/workflow.
|
|
|
21
21
|
import { registerWorkspaceTools } from '../modules/workspace/workspace.tools.js';
|
|
22
22
|
import { RECOVERY_BOT_EMAIL } from '../modules/workflow/recovery-bot.js';
|
|
23
23
|
import { registerSkillsTools, createSkillsRoutes } from '../modules/skills/index.js';
|
|
24
|
-
import {
|
|
24
|
+
import { createPluginsRoutes } from '../modules/plugins/index.js';
|
|
25
25
|
import type { SessionOntologyGate } from '../modules/workspace/session-ontology.gate.js';
|
|
26
26
|
import {
|
|
27
27
|
createSecretsVaultRoutes,
|
|
@@ -30,7 +30,7 @@ import {
|
|
|
30
30
|
import { createAdminAccessRoutes } from '../modules/admin/admin-access.routes.js';
|
|
31
31
|
import { createAccountRoutes } from '../modules/auth/account.routes.js';
|
|
32
32
|
import { createSetupRoutes } from '../modules/settings/setup.routes.js';
|
|
33
|
-
import { DEFAULT_BRANCH, PROTECTED_BRANCHES } from '@bevel-software/platform-shared';
|
|
33
|
+
import { DEFAULT_BRANCH, PROTECTED_BRANCHES, type AuthUser } from '@bevel-software/platform-shared';
|
|
34
34
|
import { GIT_SHA } from '../version.js';
|
|
35
35
|
import type { CoreServices } from './create-core-services.js';
|
|
36
36
|
|
|
@@ -150,6 +150,30 @@ export async function createCoreServer(
|
|
|
150
150
|
res.json({ status: 'ok', sha: GIT_SHA, timestamp: Date.now() });
|
|
151
151
|
});
|
|
152
152
|
|
|
153
|
+
/**
|
|
154
|
+
* This deployment's MCP endpoint, derived ONCE.
|
|
155
|
+
*
|
|
156
|
+
* Two consumers must agree on it: `/api/config` below, which is where the
|
|
157
|
+
* frontend learns what address to show people, and the OAuth
|
|
158
|
+
* `resourceServerUrl` further down, which is the resource identifier the
|
|
159
|
+
* protected-resource metadata publishes and therefore the one that decides
|
|
160
|
+
* whether a connection actually works.
|
|
161
|
+
*
|
|
162
|
+
* A constant rather than the same expression written twice. The frontend
|
|
163
|
+
* carried the two-places version of this bug for a long time — six inline
|
|
164
|
+
* sites each rebuilding the address, held together by a docstring asserting
|
|
165
|
+
* they could not diverge — and a comment is not a mechanism.
|
|
166
|
+
*
|
|
167
|
+
* Userinfo is STRIPPED: a `PUBLIC_BACKEND_URL` spelled with `user:pass@`
|
|
168
|
+
* (a basic-auth proxy in front of the deployment, say) would otherwise be
|
|
169
|
+
* republished verbatim by the unauthenticated `/api/config` below — a
|
|
170
|
+
* credential handed to any caller. The address is ours to publish; the
|
|
171
|
+
* credential never was.
|
|
172
|
+
*/
|
|
173
|
+
const mcpResourceUrl = new URL('/api/mcp', core.config.publicBackendUrl);
|
|
174
|
+
mcpResourceUrl.username = '';
|
|
175
|
+
mcpResourceUrl.password = '';
|
|
176
|
+
|
|
153
177
|
/**
|
|
154
178
|
* The handful of facts the browser needs BEFORE it can render anything, and
|
|
155
179
|
* therefore before it can authenticate: the branch model.
|
|
@@ -170,6 +194,21 @@ export async function createCoreServer(
|
|
|
170
194
|
defaultBranch: DEFAULT_BRANCH,
|
|
171
195
|
protectedBranches: [...PROTECTED_BRANCHES],
|
|
172
196
|
},
|
|
197
|
+
/**
|
|
198
|
+
* The same value the OAuth metadata publishes (see `mcpResourceUrl`).
|
|
199
|
+
*
|
|
200
|
+
* The frontend used to build this from `window.location.origin`, which
|
|
201
|
+
* is the browser's idea of our address rather than ours. The two agree
|
|
202
|
+
* on a simple deployment and disagree behind a proxy, on a second
|
|
203
|
+
* domain, or on an internal hostname — and the one that decides whether
|
|
204
|
+
* a connection works is this one.
|
|
205
|
+
*
|
|
206
|
+
* That was survivable while every surface was copy-paste: a human sees
|
|
207
|
+
* the host before pasting it. It stops being survivable the moment we
|
|
208
|
+
* hand the URL to a third party (a connector install link), where
|
|
209
|
+
* nobody reads it and the failure surfaces inside someone else's UI.
|
|
210
|
+
*/
|
|
211
|
+
mcpUrl: mcpResourceUrl.toString(),
|
|
173
212
|
});
|
|
174
213
|
});
|
|
175
214
|
|
|
@@ -225,7 +264,7 @@ export async function createCoreServer(
|
|
|
225
264
|
app.use(mcpAuthRouter({
|
|
226
265
|
provider: core.mcpOAuthProvider,
|
|
227
266
|
issuerUrl: new URL(core.config.publicBackendUrl),
|
|
228
|
-
resourceServerUrl:
|
|
267
|
+
resourceServerUrl: mcpResourceUrl,
|
|
229
268
|
scopesSupported: ['mcp'],
|
|
230
269
|
resourceName: 'Bevel MCP',
|
|
231
270
|
}));
|
|
@@ -300,6 +339,7 @@ export async function createCoreServer(
|
|
|
300
339
|
core.toolManualService,
|
|
301
340
|
core.manualAuthMiddleware,
|
|
302
341
|
async (userId) => (await core.authService.getUserById(userId))?.email,
|
|
342
|
+
{ workspaceService: core.workspaceService, accessControl: core.accessControl, kbDirName: core.kbDirName },
|
|
303
343
|
));
|
|
304
344
|
app.use('/api', toolsRouter);
|
|
305
345
|
|
|
@@ -355,17 +395,17 @@ export async function createCoreServer(
|
|
|
355
395
|
core.authMiddleware,
|
|
356
396
|
createSkillsRoutes(core.skillService, core.pendingSkillsService),
|
|
357
397
|
);
|
|
358
|
-
//
|
|
359
|
-
// like every other read surface:
|
|
398
|
+
// Plugin enumeration + join requests. Browser-only (JWT), and fail-closed
|
|
399
|
+
// like every other read surface: plugins the caller cannot access (member,
|
|
360
400
|
// manager, or discoverable via the access.md file's own read grant) are
|
|
361
401
|
// absent from the list. A join request is a plain change request.
|
|
362
|
-
app.use('/api', core.authMiddleware,
|
|
363
|
-
core.
|
|
402
|
+
app.use('/api', core.authMiddleware, createPluginsRoutes(
|
|
403
|
+
core.pluginIndexService,
|
|
364
404
|
core.accessControl,
|
|
365
405
|
core.workflowService,
|
|
366
406
|
core.workspaceService,
|
|
367
407
|
core.joinRequestsService,
|
|
368
|
-
core.
|
|
408
|
+
core.pluginProvisionService,
|
|
369
409
|
core.kbDirName,
|
|
370
410
|
async (req) => (req.userId ? ((await core.authService.getUserById(req.userId)) ?? null) : null),
|
|
371
411
|
));
|
|
@@ -383,7 +423,13 @@ export async function createCoreServer(
|
|
|
383
423
|
// workspace — it has to work on a deployment that has no knowledge base yet,
|
|
384
424
|
// which is the whole reason it exists.
|
|
385
425
|
app.use('/api', core.authMiddleware, createSetupRoutes(core.settings, core.adminAccess));
|
|
386
|
-
app.use('/api', core.authMiddleware, createToolManualsBrowserRoutes(core.toolManualService
|
|
426
|
+
app.use('/api', core.authMiddleware, createToolManualsBrowserRoutes(core.toolManualService, {
|
|
427
|
+
service: core.mcpServerEditService,
|
|
428
|
+
getUser: async (userId) => {
|
|
429
|
+
const u = await core.authService.getUserById(userId);
|
|
430
|
+
return u ? ({ id: u.id, email: u.email, name: u.name } as AuthUser) : undefined;
|
|
431
|
+
},
|
|
432
|
+
}));
|
|
387
433
|
app.use('/api', core.authMiddleware, createSecretsVaultRoutes(secretsVaultRoutesDeps));
|
|
388
434
|
// The authed tail of the MCP OAuth flow: /connect calls these to describe
|
|
389
435
|
// the pending authorization and, on Finish, to mint the one-time code. The
|
|
@@ -5,7 +5,7 @@ import {
|
|
|
5
5
|
configureBranchModel,
|
|
6
6
|
validateBranchModel,
|
|
7
7
|
PROTECTED_BRANCHES,
|
|
8
|
-
|
|
8
|
+
PLUGINS_DIR,
|
|
9
9
|
} from '@bevel-software/platform-shared';
|
|
10
10
|
import { CoreConfig } from '../core-config.js';
|
|
11
11
|
import { getDb, type Database } from '../modules/database/connection.js';
|
|
@@ -33,7 +33,8 @@ import { AccessControlService } from '../modules/access/access-control.service.j
|
|
|
33
33
|
import { CreatorAccessService } from '../modules/access/creator-access.js';
|
|
34
34
|
import { PendingSkillsService, SkillService } from '../modules/skills/index.js';
|
|
35
35
|
import { ToolManualService } from '../modules/tool-manuals/index.js';
|
|
36
|
-
import {
|
|
36
|
+
import { McpServerEditService } from '../modules/tool-manuals/mcp-server-edit.service.js';
|
|
37
|
+
import { PluginIndexService, PluginProvisionService, JoinRequestsService } from '../modules/plugins/index.js';
|
|
37
38
|
import {
|
|
38
39
|
DbSecretsVaultService,
|
|
39
40
|
McpOAuthDiscoveryService,
|
|
@@ -102,8 +103,9 @@ export interface CoreServices {
|
|
|
102
103
|
skillService: SkillService;
|
|
103
104
|
pendingSkillsService: PendingSkillsService;
|
|
104
105
|
toolManualService: ToolManualService;
|
|
105
|
-
|
|
106
|
-
|
|
106
|
+
mcpServerEditService: McpServerEditService;
|
|
107
|
+
pluginIndexService: PluginIndexService;
|
|
108
|
+
pluginProvisionService: PluginProvisionService;
|
|
107
109
|
joinRequestsService: JoinRequestsService;
|
|
108
110
|
authService: AuthService;
|
|
109
111
|
authMiddleware: ReturnType<typeof createAuthMiddleware>;
|
|
@@ -260,15 +262,15 @@ export async function createCoreServices(
|
|
|
260
262
|
const routineWritePolicy = new RoutineWritePolicyService();
|
|
261
263
|
// Skills: discovered from the default-branch workspace only (global catalog).
|
|
262
264
|
const skillService = new SkillService(workspaceService, accessControl, kbDirName);
|
|
263
|
-
// Tool manuals: user-authored `*.tool` files under `
|
|
265
|
+
// Tool manuals: user-authored `*.tool` files under `Plugins/` in the default
|
|
264
266
|
// branch — access-controlled like Skills, served to external agents via
|
|
265
267
|
// `GET /api/agent/all-tools` and registered on the MCP proxy's UTCP client.
|
|
266
268
|
const toolManualService = new ToolManualService(workspaceService, accessControl, kbDirName);
|
|
267
|
-
//
|
|
269
|
+
// Plugins: the folders under `Plugins/` that carry a
|
|
268
270
|
// team's skills AND the tools they need. Enumerated for EVERY authenticated
|
|
269
|
-
// caller — a
|
|
271
|
+
// caller — a plugin they cannot read still exists for them, as a locked one —
|
|
270
272
|
// with the counts read off the two catalogs above rather than a second scan.
|
|
271
|
-
const
|
|
273
|
+
const pluginIndexService = new PluginIndexService(
|
|
272
274
|
workspaceService,
|
|
273
275
|
accessControl,
|
|
274
276
|
skillService,
|
|
@@ -384,16 +386,28 @@ export async function createCoreServices(
|
|
|
384
386
|
workflowHooks,
|
|
385
387
|
);
|
|
386
388
|
|
|
387
|
-
// Join requests: derived entirely from two copies of a
|
|
389
|
+
// Join requests: derived entirely from two copies of a plugin's `access.md`
|
|
388
390
|
// (the request's branch vs the default branch), so it holds no state — it
|
|
389
391
|
// only needs to read files at refs and to close a request whose proposals
|
|
390
392
|
// have all landed.
|
|
391
393
|
const joinRequestsService = new JoinRequestsService(workspaceService, workflowService);
|
|
392
|
-
//
|
|
393
|
-
//
|
|
394
|
+
// Server-scoped MCP editing — the tool page's edit form. One server's truth
|
|
395
|
+
// spans a plugin's mcp.json AND plugin.json extensions block, and this is
|
|
396
|
+
// the ONE writer that rewrites both entries and commits them together (see
|
|
397
|
+
// McpServerEditService).
|
|
398
|
+
const mcpServerEditService = new McpServerEditService(
|
|
399
|
+
workspaceService,
|
|
400
|
+
workflowService,
|
|
401
|
+
accessControl,
|
|
402
|
+
toolManualService,
|
|
403
|
+
kbDirName,
|
|
404
|
+
);
|
|
405
|
+
|
|
406
|
+
// Plugin provisioning — the one privileged door that brings `Plugins/<name>/`
|
|
407
|
+
// folders into existence (named plugins and personal folders alike). Commits
|
|
394
408
|
// INLINE through the same pipeline the pending-commits worker uses, so the
|
|
395
409
|
// folder's rules are at HEAD before the endpoint answers.
|
|
396
|
-
const
|
|
410
|
+
const pluginProvisionService = new PluginProvisionService(
|
|
397
411
|
workspaceService,
|
|
398
412
|
workflowService,
|
|
399
413
|
accessControl,
|
|
@@ -422,16 +436,16 @@ export async function createCoreServices(
|
|
|
422
436
|
// caches are independent, so the split preserves behavior.)
|
|
423
437
|
fileChangeNotifier.onFilesChanged(({ branch, paths }) => {
|
|
424
438
|
if (branch !== DEFAULT_BRANCH) return;
|
|
425
|
-
// Skills, tools and the
|
|
439
|
+
// Skills, tools and the plugin index all live under `Plugins/`, so one
|
|
426
440
|
// touch check drives all three caches. An access grant lands as a
|
|
427
|
-
// default-branch change to `
|
|
428
|
-
// what makes a newly-granted
|
|
441
|
+
// default-branch change to `Plugins/<plugin>/access.md`, so this is also
|
|
442
|
+
// what makes a newly-granted plugin unlock within one round-trip instead
|
|
429
443
|
// of one TTL.
|
|
430
|
-
const touched = paths.some((p) => p.startsWith(`${kbDirName}/${
|
|
444
|
+
const touched = paths.some((p) => p.startsWith(`${kbDirName}/${PLUGINS_DIR}/`));
|
|
431
445
|
if (touched) {
|
|
432
446
|
toolManualService.invalidate();
|
|
433
447
|
skillService.invalidate();
|
|
434
|
-
|
|
448
|
+
pluginIndexService.invalidate();
|
|
435
449
|
}
|
|
436
450
|
});
|
|
437
451
|
|
|
@@ -448,7 +462,7 @@ export async function createCoreServices(
|
|
|
448
462
|
if (!('branch' in event) || event.branch !== DEFAULT_BRANCH) return;
|
|
449
463
|
toolManualService.invalidate();
|
|
450
464
|
skillService.invalidate();
|
|
451
|
-
|
|
465
|
+
pluginIndexService.invalidate();
|
|
452
466
|
});
|
|
453
467
|
|
|
454
468
|
// Admin = `Admin` role in roles.yaml, resolved through the access model on the
|
|
@@ -567,7 +581,12 @@ export async function createCoreServices(
|
|
|
567
581
|
});
|
|
568
582
|
// RFC 9728 pointer carried on every MCP 401 challenge so OAuth-capable
|
|
569
583
|
// clients discover the AS. Single source of truth for the resource id.
|
|
584
|
+
// Userinfo is stripped for the same reason the server's own copy strips it
|
|
585
|
+
// (see create-core-server.ts): the pointer rides an unauthenticated 401
|
|
586
|
+
// challenge, and a `user:pass@` from PUBLIC_BACKEND_URL must not ride along.
|
|
570
587
|
const mcpResourceUrl = new URL('/api/mcp', config.publicBackendUrl);
|
|
588
|
+
mcpResourceUrl.username = '';
|
|
589
|
+
mcpResourceUrl.password = '';
|
|
571
590
|
const mcpResourceMetadataUrl = getOAuthProtectedResourceMetadataUrl(mcpResourceUrl);
|
|
572
591
|
const mcpAuthMiddleware = createMcpAuthMiddleware(
|
|
573
592
|
authService,
|
|
@@ -622,10 +641,14 @@ export async function createCoreServices(
|
|
|
622
641
|
);
|
|
623
642
|
const pendingCommitsWorker = new PendingCommitsWorker({
|
|
624
643
|
service: pendingCommitsService,
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
644
|
+
// The service IS the driver — passed directly rather than wrapped in a
|
|
645
|
+
// forwarding lambda. A lambda that names its parameters silently drops any
|
|
646
|
+
// the interface later adds (TypeScript accepts a shorter parameter list),
|
|
647
|
+
// and that is not hypothetical: the wrapper here took four arguments and
|
|
648
|
+
// swallowed the `opts` carrying `skipValidation`, so the burst-validation
|
|
649
|
+
// skip was a no-op in production while every unit test — which stubs this
|
|
650
|
+
// port — passed. No wrapper, no gap to fall through.
|
|
651
|
+
workflow: workflowService,
|
|
629
652
|
// Both escalation sinks come through CorePorts: the recovery agent and the
|
|
630
653
|
// notice sink are enterprise-owned (background-agent factory / feedback
|
|
631
654
|
// dashboard); core defaults skip recovery and log to stderr.
|
|
@@ -671,6 +694,7 @@ export async function createCoreServices(
|
|
|
671
694
|
return {
|
|
672
695
|
config,
|
|
673
696
|
db,
|
|
697
|
+
mcpServerEditService,
|
|
674
698
|
workspaceService,
|
|
675
699
|
kbSeedService,
|
|
676
700
|
settings,
|
|
@@ -683,8 +707,8 @@ export async function createCoreServices(
|
|
|
683
707
|
skillService,
|
|
684
708
|
pendingSkillsService,
|
|
685
709
|
toolManualService,
|
|
686
|
-
|
|
687
|
-
|
|
710
|
+
pluginIndexService,
|
|
711
|
+
pluginProvisionService,
|
|
688
712
|
joinRequestsService,
|
|
689
713
|
authService,
|
|
690
714
|
authMiddleware,
|