@bevel-software/platform-core-backend 0.7.5 → 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 +30 -18
- 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/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 +40 -20
- 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__/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/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/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
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The ONE variable-reference grammar, shared by every boundary that has to
|
|
3
|
+
* decide "would the substitutor expand this?" — `.tool` parsing, `mcp.json`
|
|
4
|
+
* discovery, the server editor's header split, and the Groups→Plugins
|
|
5
|
+
* migration. The decision has credential stakes on both sides (a reference
|
|
6
|
+
* mis-read as prose is a `${VAR}` written into portable, world-readable
|
|
7
|
+
* `mcp.json`; prose mis-read as a reference is a header that stops working),
|
|
8
|
+
* so the classifiers must not each keep their own approximation of it.
|
|
9
|
+
*/
|
|
10
|
+
/**
|
|
11
|
+
* The SDK substitutor's reference grammar, exactly: `${VAR}` or `$VAR`, names
|
|
12
|
+
* `[a-zA-Z0-9_]+`. Note a LEADING DIGIT is legal — `$5TOKEN` (and `$5` in
|
|
13
|
+
* prose) is a reference as far as substitution is concerned, and classifying
|
|
14
|
+
* it as anything else here would diverge from what actually expands.
|
|
15
|
+
*/
|
|
16
|
+
export const VARIABLE_REFERENCE_RE = /\$\{([a-zA-Z0-9_]+)\}|\$([a-zA-Z0-9_]+)/g;
|
|
17
|
+
// `.test()` on a global regex is stateful (lastIndex persists across calls) —
|
|
18
|
+
// the predicate gets its own non-global compilation of the same source.
|
|
19
|
+
const VARIABLE_REFERENCE_ONCE = new RegExp(VARIABLE_REFERENCE_RE.source);
|
|
20
|
+
/** True when any substring of `text` is a substitutor reference. */
|
|
21
|
+
export function containsVariableReference(text) {
|
|
22
|
+
return VARIABLE_REFERENCE_ONCE.test(text);
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Variable names the platform seeds for its own (Bevel-hosted) manuals:
|
|
26
|
+
* `<ns>_API_URL` points a manual at the backend and `<ns>_CONNECTION_KEY`
|
|
27
|
+
* carries the platform bearer. User-declared variables may not take these
|
|
28
|
+
* names, and user content may not reference them (bare or namespaced).
|
|
29
|
+
*/
|
|
30
|
+
export const RESERVED_VARIABLE_NAMES = ['API_URL', 'CONNECTION_KEY'];
|
|
31
|
+
/**
|
|
32
|
+
* A NAME is reserved by SUFFIX, not by exact match: the substitutor looks a
|
|
33
|
+
* variable up under the manual's UTCP namespace first, so `${<ns>_CONNECTION_KEY}`
|
|
34
|
+
* resolves the very same seeded value the bare `${CONNECTION_KEY}` does.
|
|
35
|
+
* Suffix matching also refuses harmless-looking near-misses (`MY_API_URL`) —
|
|
36
|
+
* deliberately fail-closed.
|
|
37
|
+
*/
|
|
38
|
+
export function isReservedVariableName(varName) {
|
|
39
|
+
return RESERVED_VARIABLE_NAMES.some((reserved) => varName.endsWith(reserved));
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* The first reserved REFERENCE anywhere in `doc` (scanned as JSON text), or
|
|
43
|
+
* null. Built on the shared grammar above, so what counts as a reference here
|
|
44
|
+
* is exactly what counts everywhere else — `${ API_URL }` with spaces is not
|
|
45
|
+
* expandable, so it is a literal to every boundary, not reserved to one and
|
|
46
|
+
* portable to another.
|
|
47
|
+
*/
|
|
48
|
+
export function findReservedVariableRef(doc) {
|
|
49
|
+
const text = JSON.stringify(doc) ?? '';
|
|
50
|
+
// A fresh instance per scan: `matchAll` COPIES the source regex's
|
|
51
|
+
// `lastIndex` (spec), and the exported one is mutable module state — any
|
|
52
|
+
// future `.exec`/`.test` on it would make this scan start mid-string.
|
|
53
|
+
for (const match of text.matchAll(new RegExp(VARIABLE_REFERENCE_RE.source, VARIABLE_REFERENCE_RE.flags))) {
|
|
54
|
+
const varName = match[1] ?? match[2] ?? '';
|
|
55
|
+
if (isReservedVariableName(varName))
|
|
56
|
+
return match[0];
|
|
57
|
+
}
|
|
58
|
+
return null;
|
|
59
|
+
}
|
|
60
|
+
//# sourceMappingURL=variable-refs.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"variable-refs.js","sourceRoot":"","sources":["../../src/shared/variable-refs.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH;;;;;GAKG;AACH,MAAM,CAAC,MAAM,qBAAqB,GAAG,0CAA0C,CAAC;AAEhF,8EAA8E;AAC9E,wEAAwE;AACxE,MAAM,uBAAuB,GAAG,IAAI,MAAM,CAAC,qBAAqB,CAAC,MAAM,CAAC,CAAC;AAEzE,oEAAoE;AACpE,MAAM,UAAU,yBAAyB,CAAC,IAAY;IACpD,OAAO,uBAAuB,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAC5C,CAAC;AAED;;;;;GAKG;AACH,MAAM,CAAC,MAAM,uBAAuB,GAAsB,CAAC,SAAS,EAAE,gBAAgB,CAAC,CAAC;AAExF;;;;;;GAMG;AACH,MAAM,UAAU,sBAAsB,CAAC,OAAe;IACpD,OAAO,uBAAuB,CAAC,IAAI,CAAC,CAAC,QAAQ,EAAE,EAAE,CAAC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC,CAAC;AAChF,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,uBAAuB,CAAC,GAAY;IAClD,MAAM,IAAI,GAAG,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC;IACvC,kEAAkE;IAClE,yEAAyE;IACzE,sEAAsE;IACtE,KAAK,MAAM,KAAK,IAAI,IAAI,CAAC,QAAQ,CAAC,IAAI,MAAM,CAAC,qBAAqB,CAAC,MAAM,EAAE,qBAAqB,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC;QACzG,MAAM,OAAO,GAAG,KAAK,CAAC,CAAC,CAAC,IAAI,KAAK,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;QAC3C,IAAI,sBAAsB,CAAC,OAAO,CAAC;YAAE,OAAO,KAAK,CAAC,CAAC,CAAC,CAAC;IACvD,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC"}
|
package/kb-template/.bevelignore
CHANGED
package/kb-template/AGENTS.md
CHANGED
|
@@ -21,36 +21,77 @@ change them.
|
|
|
21
21
|
```text
|
|
22
22
|
knowledge-base/
|
|
23
23
|
├── KnowledgeBase/ ← the knowledge itself; organise it however suits you
|
|
24
|
-
├──
|
|
24
|
+
├── Plugins/ ← one folder per plugin: its skills AND its tools
|
|
25
25
|
├── roles.yaml ← identity → role mapping (Admin-only edits)
|
|
26
26
|
└── access.md ← repo-root access-control rules
|
|
27
27
|
```
|
|
28
28
|
|
|
29
|
-
Only those two folders are structural, and only `
|
|
29
|
+
Only those two folders are structural, and only `Plugins/` has a layout the
|
|
30
30
|
platform reads:
|
|
31
31
|
|
|
32
32
|
```text
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
33
|
+
Plugins/<Plugin>/plugin.json the manifest (Agent Plugins)
|
|
34
|
+
Plugins/<Plugin>/skills/<skill>/SKILL.md a skill
|
|
35
|
+
Plugins/<Plugin>/mcp.json MCP servers (authoritative)
|
|
36
|
+
Plugins/<Plugin>/software.bevel.hexis/tools/ `.tool` manuals
|
|
37
|
+
Plugins/<Plugin>/access.md who can read/write the plugin
|
|
38
|
+
Plugins/personal-<user-id>/… one per person: private
|
|
37
39
|
```
|
|
38
40
|
|
|
39
|
-
Skills and tools live TOGETHER in a
|
|
40
|
-
boundary: a tool a
|
|
41
|
-
|
|
42
|
-
**
|
|
41
|
+
Skills and tools live TOGETHER in a plugin because they share one access
|
|
42
|
+
boundary: a tool a plugin cannot read is a skill that plugin cannot run.
|
|
43
|
+
|
|
44
|
+
**Symlinks are not supported anywhere under `Plugins/`.** Access control
|
|
45
|
+
resolves rules by path, and a symlink is a second path to the same content —
|
|
46
|
+
the two can disagree about who may read what. The platform never creates
|
|
47
|
+
them and ignores any it finds (they can only arrive via a direct git push).
|
|
48
|
+
|
|
49
|
+
**A plugin follows the [Agent Plugins](https://agent-plugins.org) specification**
|
|
50
|
+
(v1.0.0), so another conformant client can load one: it reads `plugin.json`, the
|
|
51
|
+
skills under `skills/`, and the servers in `mcp.json`, and ignores everything
|
|
52
|
+
else. Two things here are ours and sit outside that portable core. `access.md`
|
|
53
|
+
stays at the plugin root because access resolution walks root → file, so the
|
|
54
|
+
same rules one level down would govern only that subtree. And `http`/`inline` `.tool`
|
|
55
|
+
manuals live under the reverse-DNS `software.bevel.hexis/` namespace, because
|
|
56
|
+
the specification describes MCP servers only and has no way to express them.
|
|
57
|
+
|
|
58
|
+
**MCP servers belong in `mcp.json` — do not write `.tool` files for them.**
|
|
59
|
+
Each `mcpServers` key is the server's identity: it is the namespace its vault
|
|
60
|
+
secrets bind to (`<name>_<VAR>`), so renaming a key unbinds every configured
|
|
61
|
+
secret and sign-in. The portable entry carries only where the server is
|
|
62
|
+
(`type`, `url`, literal headers). Anything this platform needs beyond that —
|
|
63
|
+
auth headers carrying `${VAR}` vault references, `variables` declarations,
|
|
64
|
+
a `description`, or `local: true` for a server only reachable from a user's
|
|
65
|
+
machine — goes in `plugin.json` under
|
|
66
|
+
`extensions["software.bevel.hexis"].mcpServers[<name>]`, which other clients
|
|
67
|
+
ignore by design. A `type: "stdio"` entry (a command run on the user's own
|
|
68
|
+
machine) is always local: the hosted endpoint never spawns it; the local
|
|
69
|
+
`hexis-mcp` server fetches the plugin's files to a local directory and runs it
|
|
70
|
+
per the Agent Plugins runtime contract (`PLUGIN_ROOT`/`PLUGIN_DATA`, `./`
|
|
71
|
+
commands contained to the plugin).
|
|
72
|
+
|
|
73
|
+
**Secrets are never written into a plugin's portable files.** The specification
|
|
74
|
+
defines no portable credential mechanism on purpose: authorization and
|
|
75
|
+
credential storage are the client's business, header and `env` values are
|
|
76
|
+
"visible package data", and a client must not expand anything except
|
|
77
|
+
`${PLUGIN_ROOT}` and `${PLUGIN_DATA}`. So the Secrets Vault IS this platform's
|
|
78
|
+
answer to that — and `mcp.json` carries only where a server is, never a
|
|
79
|
+
`${VAR}` reference to how to authenticate with it. Those live in `plugin.json`
|
|
80
|
+
under `extensions["software.bevel.hexis"].mcpServers[<name>]`, which is ours
|
|
81
|
+
to interpret and which other clients ignore by design.
|
|
82
|
+
|
|
83
|
+
**Plugin folders are made through the app, not by writing files.** A plugin
|
|
43
84
|
exists exactly when its folder carries an `access.md` — a bare directory
|
|
44
|
-
under `
|
|
45
|
-
direct child of `
|
|
85
|
+
under `Plugins/` is not a plugin and is never listed. A new
|
|
86
|
+
direct child of `Plugins/` needs an `access.md` naming who runs it, and the
|
|
46
87
|
write gate refuses a plain write into an unused name there — so do not try to
|
|
47
|
-
create a
|
|
48
|
-
denied. Send the user to the app's **New
|
|
49
|
-
`POST /api/
|
|
88
|
+
create a plugin by writing a skill into `Plugins/<new-name>/…`; it will be
|
|
89
|
+
denied. Send the user to the app's **New plugin** button (or its
|
|
90
|
+
`POST /api/plugins` endpoint), then write into the folder it made. Names
|
|
50
91
|
starting with `personal-` are reserved: one such folder exists per person,
|
|
51
92
|
created automatically with their first personal skill, readable only by its
|
|
52
|
-
owner and never listed as a
|
|
53
|
-
there, and move into a
|
|
93
|
+
owner and never listed as a plugin — a signed-in user's own skills belong
|
|
94
|
+
there, and move into a plugin by moving the skill's folder.
|
|
54
95
|
|
|
55
96
|
Everything under `KnowledgeBase/` is yours to arrange. Subfolders, naming,
|
|
56
97
|
whether a topic is one file or twenty — all of it is a judgement call about
|
|
@@ -99,7 +140,7 @@ File-level write access decides how a change lands on the default branch:
|
|
|
99
140
|
review flow — and prefer a change request when in doubt, when the change is
|
|
100
141
|
large, or when it touches content the user does not own.
|
|
101
142
|
|
|
102
|
-
## Skills (`
|
|
143
|
+
## Skills (`Plugins/<Plugin>/skills/<skill>/SKILL.md`)
|
|
103
144
|
|
|
104
145
|
A skill is a folder holding a `SKILL.md` and whatever files it needs. The
|
|
105
146
|
frontmatter names it and declares which tools it may use:
|
|
@@ -113,21 +154,25 @@ allowed-tools: [slack_post_message]
|
|
|
113
154
|
```
|
|
114
155
|
|
|
115
156
|
The body is the instructions, in plain markdown. `allowed-tools` entries are
|
|
116
|
-
tool names from the `.tool` manuals in the same
|
|
117
|
-
tools its
|
|
157
|
+
tool names from the `.tool` manuals in the same plugin — a skill can only reach
|
|
158
|
+
tools its plugin can read.
|
|
118
159
|
|
|
119
|
-
## Tool Manuals (`
|
|
160
|
+
## Tool Manuals (`Plugins/<Plugin>/software.bevel.hexis/tools/*.tool`)
|
|
120
161
|
|
|
121
|
-
Each
|
|
122
|
-
integration may exist in several
|
|
123
|
-
and `Finance
|
|
124
|
-
a
|
|
162
|
+
Each plugin folder holds `*.tool` files — reusable **tool manuals** that let agents call external APIs. They are **not part of the knowledge graph** (never modelled as nodes) and are access-controlled like any other file via `access.md`. Any user who can *read* a `.tool` can use its tools; anyone who can *write* it sets its shared (admin) secrets (see below). Put each manual in the plugin's `software.bevel.hexis/tools/` directory, beside
|
|
163
|
+
the skills that use it. The same integration may exist in several plugins as
|
|
164
|
+
separate files (`Everyone/…/serper.tool` and `Finance/…/serper.tool`), each
|
|
165
|
+
with its own credentials and access rule — a plugin is a folder, not a registry
|
|
166
|
+
of unique names. Remember: `.tool` files are for `http` and `inline` manuals
|
|
167
|
+
only; MCP servers belong in `mcp.json`.
|
|
125
168
|
|
|
126
169
|
A `.tool` file is JSON or YAML. Its `type` decides how tools are discovered:
|
|
127
170
|
|
|
128
171
|
- **`inline`** — the tools are embedded in the file (no network round-trip to list them).
|
|
129
172
|
- **`http`** — `url` points to an endpoint that returns a UTCP manual.
|
|
130
|
-
|
|
173
|
+
|
|
174
|
+
(`type: mcp` is the LEGACY spelling of an MCP server as a `.tool`. The boot
|
|
175
|
+
migration converts such files into `mcp.json` entries; do not write new ones.)
|
|
131
176
|
|
|
132
177
|
**The tool is the frontmatter.** A `.tool` is one `---` YAML block holding *everything* — its `id`, its access verbs (`read:`/`write:`/`owner:`/`download:`), and its config (`type`/`url`/`variables`/…) — all in the same object. Anything after the closing `---` is free-form notes the parser ignores (like a `SKILL.md` body):
|
|
133
178
|
|
|
@@ -138,8 +183,8 @@ write:
|
|
|
138
183
|
- Product Team
|
|
139
184
|
owner:
|
|
140
185
|
- Jane Doe <jane@x.com>
|
|
141
|
-
type:
|
|
142
|
-
url: https://
|
|
186
|
+
type: http
|
|
187
|
+
url: https://api.example.com/utcp
|
|
143
188
|
---
|
|
144
189
|
```
|
|
145
190
|
|
|
@@ -149,7 +194,15 @@ url: https://mcp.example.com
|
|
|
149
194
|
|
|
150
195
|
**Frontmatter `id` = address.** This is generic, not tool-specific: ANY `.md` or `.tool` file whose frontmatter declares an `id` (or a lowercase snake_case/kebab `name`) is addressable at `/workspace/<branch>/<id>` in the app, exactly like a knowledge node — tools, skills (`SKILL.md`), and plain notes alike. Graph nodes win an id collision; files without frontmatter stay path-addressed.
|
|
151
196
|
|
|
152
|
-
**Remote vs local (`remote`).** A tool is available to remote agents by default. Add `remote: false` for a tool that only works on the user's own machine (e.g. an
|
|
197
|
+
**Remote vs local (`remote`).** A tool is available to remote agents by default. Add `remote: false` for a tool that only works on the user's own machine (e.g. an `http` manual whose `url` is on `localhost`): the hosted remote MCP endpoint cannot reach it, so it skips the tool and advertises it through the `list_local_tools` tool instead. (An MCP server that is local-only declares `local: true` in the plugin.json extensions block instead — see above.)
|
|
198
|
+
|
|
199
|
+
To actually USE those tools, run the workspace as a local MCP server:
|
|
200
|
+
|
|
201
|
+
```
|
|
202
|
+
npx @bevel-software/hexis-mcp --url <workspace-url> --key <connection-key>
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
It serves everything the hosted endpoint serves **plus** the local-only tools, because it runs on the machine where they exist. Remote tools still execute on the server, so their shared keys and OAuth sign-ins keep working untouched; a local-only tool's own `${VAR}`s come from the environment of whatever launched the command (your MCP client's config), since the Secrets Vault never leaves the server. Reading the `.tool` and wiring the server into your client by hand still works and is the fallback when the command is unavailable.
|
|
153
206
|
|
|
154
207
|
### Referencing secrets — `${VAR}` and the `variables` block
|
|
155
208
|
|
|
@@ -207,21 +260,21 @@ An `inline` manual with one tool:
|
|
|
207
260
|
When asked to add/integrate a product as a tool (e.g. "add Notion", "wire up Linear"), **never invent an endpoint or write a placeholder URL** — a `.tool` pointing at a made-up host is useless:
|
|
208
261
|
|
|
209
262
|
1. **Find the real endpoint from the vendor's own docs.** Prefer the vendor's official **remote MCP server** if one exists; otherwise fall back to their **REST API** base. No endpoint is named here on purpose — a URL copied into this file would be asserted long after it stopped being true, which is the failure this step exists to prevent. Use web search/extract to confirm the exact URL, transport, and auth scheme — don't answer from memory. If you have no web access or genuinely can't find it, **ask the user** for the endpoint URL and auth instead of guessing.
|
|
210
|
-
2. **Pick the
|
|
211
|
-
3. **An OAuth-protected MCP server usually needs NOTHING beyond `
|
|
263
|
+
2. **Pick the home from what you found.** An MCP server → an entry in the plugin's `mcp.json` (`type: "streamable-http"` with the official `url` — use the `https://…` URL, **never** `ws://`/`wss://`). A plain REST/HTTP endpoint → a `.tool` with `type: http`. Use `type: inline` only when hand-authoring the individual HTTP calls.
|
|
264
|
+
3. **An OAuth-protected MCP server usually needs NOTHING beyond its `mcp.json` entry.** Write just those two and let the app probe the server: it discovers the sign-in provider (MCP authorization spec), registers itself, and surfaces a per-user sign-in on the Connect page. That is the `oauth-auto` case, and for it you must NOT declare `variables` or `headers`.
|
|
212
265
|
|
|
213
266
|
Some providers do not support automatic registration (`oauth-manual` — see the walkthrough below). Those DO need a sign-in variable to hold the client id, and an admin pastes the client secret on the tool's page. You do not have to guess which kind you are facing: write the two lines, then run `list_tool_setup` and read `setup.kind`.
|
|
214
267
|
4. **For key-based auth, wire it as `variables`, never a hard-coded secret.** Reference credentials as `${VAR}` in `headers` (e.g. `Authorization: Bearer ${NOTION_TOKEN}`) and declare each in the `variables` block with a scope (`admin` = one shared value; `user` = per-user). Users fill the values in the Secrets Vault.
|
|
215
|
-
5. **
|
|
268
|
+
5. **Say so when a tool is reachable ONLY from the user's own machine.** For an MCP server (e.g. one on `localhost`), declare `local: true` on its entry in the plugin.json extensions block — `remote: false` is a `.tool` frontmatter field and means nothing in `mcp.json`. For an `http`/`inline` `.tool`, set `remote: false`. Otherwise leave the tool remote-capable.
|
|
216
269
|
|
|
217
270
|
### Checking what an admin still needs to configure
|
|
218
271
|
|
|
219
|
-
Call the **`list_tool_setup`** tool to see, for every accessible `.tool
|
|
272
|
+
Call the **`list_tool_setup`** tool to see, for every accessible tool — `.tool` manuals and `mcp.json` servers alike — what is configured and what is still missing. Use it whenever a tool isn't working, after adding a tool, or when asked "what do I need to set up?" — then EXPLAIN the remaining steps to the user rather than guessing. Per tool it reports:
|
|
220
273
|
|
|
221
|
-
- **`setup.kind`** (for
|
|
274
|
+
- **`setup.kind`** (for MCP servers): `open` = no credentials needed; `oauth-auto` = the platform registered itself with the server automatically and users just authorize on the **Connect page**; `oauth-manual` = the provider does not support automatic registration, so a tool writer must configure it by hand (below).
|
|
222
275
|
- **Per variable**: `adminConfigured` (the shared value — or, for a sign-in, the owner-side provider setup — is done), `userConfigured` / `authorized` (the CURRENT user's own value / sign-in), and `canWrite` (whether the current user may set the tool's shared config).
|
|
223
276
|
|
|
224
|
-
The listing is scoped by the same access controls as everything else: a
|
|
277
|
+
The listing is scoped by the same access controls as everything else: a tool the caller can't READ doesn't appear at all, and `canWrite` means write access **on the file that declares it** — the `.tool` file itself (via its frontmatter `write:`/`owner:` verbs or the `access.md` chain), or the plugin's `mcp.json` for an MCP server (via the plugin's `access.md` chain — `mcp.json` carries no verb list of its own) — NOT any platform role. The people who manage that file are exactly the people who configure its shared secrets. To delegate a `.tool` to someone, add them to that file's `write:`/`owner:` list; to delegate an MCP server, grant them `write` on the plugin in its `access.md` (both are edits you can make via change request). That alone lets them configure it.
|
|
225
278
|
|
|
226
279
|
**Agents never handle secret VALUES.** Never ask for an API key, token, or client secret in the conversation, and there is no tool to set one. Point the right person at the right surface instead:
|
|
227
280
|
|
|
@@ -17,7 +17,7 @@ Use the app switcher in the top-left corner to move between the two views:
|
|
|
17
17
|
|
|
18
18
|
- **Knowledge** is the reading and writing surface: a file tree on the left,
|
|
19
19
|
the document on the right.
|
|
20
|
-
- **Skills & Tools** is the library:
|
|
20
|
+
- **Skills & Tools** is the library: plugins holding skills and tools, who runs
|
|
21
21
|
them, and what still needs setting up.
|
|
22
22
|
|
|
23
23
|
## Write your first document
|
|
@@ -29,22 +29,22 @@ someone else, you get **Propose changes** instead. A proposal becomes a
|
|
|
29
29
|
nothing moves until they approve it. That is the whole safety model, and it
|
|
30
30
|
applies to agents exactly as it applies to people.
|
|
31
31
|
|
|
32
|
-
## Set up your
|
|
32
|
+
## Set up your plugin
|
|
33
33
|
|
|
34
|
-
In Skills & Tools, use **New
|
|
35
|
-
a
|
|
34
|
+
In Skills & Tools, use **New plugin** to make a place for your team. Creating
|
|
35
|
+
a plugin makes you the one who runs it: you approve its change requests,
|
|
36
36
|
answer join requests, and manage who can see what (the **Share** button on
|
|
37
|
-
the
|
|
38
|
-
space and can move into a
|
|
37
|
+
the plugin page). Skills you create outside any plugin land in your own private
|
|
38
|
+
space and can move into a plugin later.
|
|
39
39
|
|
|
40
40
|
## Give your agents skills and tools
|
|
41
41
|
|
|
42
|
-
- On a
|
|
42
|
+
- On a plugin page, **+** adds a skill: name it and an empty skill file opens,
|
|
43
43
|
ready for instructions. Write it the way you would brief a careful new
|
|
44
44
|
colleague: what to load, what to do, what to record.
|
|
45
|
-
- Tools
|
|
46
|
-
|
|
47
|
-
files.
|
|
45
|
+
- Tools live in the plugin too: most are small manual files, and MCP servers
|
|
46
|
+
go in the plugin's `mcp.json`. Sign-ins and keys are entered on the
|
|
47
|
+
**Connect** page or the tool's own page, never written into files.
|
|
48
48
|
|
|
49
49
|
## Connect your AI agent
|
|
50
50
|
|
package/kb-template/access.md
CHANGED
|
@@ -1,36 +1,36 @@
|
|
|
1
|
-
---
|
|
2
|
-
write:
|
|
3
|
-
- Admin
|
|
4
|
-
download:
|
|
5
|
-
- Admin
|
|
6
|
-
owner: []
|
|
7
|
-
---
|
|
8
|
-
|
|
9
|
-
# Repository access
|
|
10
|
-
|
|
11
|
-
This file is the root of the access-control tree for this knowledge base. It grants
|
|
12
|
-
write access only to the `Admin` role by default. Subfolders can broaden or narrow
|
|
13
|
-
access by adding their own `access.md`.
|
|
14
|
-
|
|
15
|
-
See [roles.yaml](roles.yaml) for the identity → role mapping. Access resolution and validation
|
|
16
|
-
run in the Bevel platform.
|
|
17
|
-
|
|
18
|
-
## Adding a folder-level rule
|
|
19
|
-
|
|
20
|
-
Drop an `access.md` into any folder, at any depth. Frontmatter
|
|
21
|
-
only — the body is ignored. Example:
|
|
22
|
-
|
|
23
|
-
```yaml
|
|
24
|
-
---
|
|
25
|
-
write:
|
|
26
|
-
- Admin
|
|
27
|
-
- Editor
|
|
28
|
-
- Jane Doe <jane.doe@example.com>
|
|
29
|
-
- deny Mallory Bad <mallory@example.com>
|
|
30
|
-
---
|
|
31
|
-
```
|
|
32
|
-
|
|
33
|
-
Each entry is either a grant (bare principal) or a denial (`deny <principal>` —
|
|
34
|
-
**lowercase `deny` only**; capitalised forms like `Deny` are treated as part of a
|
|
35
|
-
name). A principal is either a role name (matched case-insensitively against
|
|
36
|
-
`roles.yaml`) or a user reference in `Name <email>` form.
|
|
1
|
+
---
|
|
2
|
+
write:
|
|
3
|
+
- Admin
|
|
4
|
+
download:
|
|
5
|
+
- Admin
|
|
6
|
+
owner: []
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# Repository access
|
|
10
|
+
|
|
11
|
+
This file is the root of the access-control tree for this knowledge base. It grants
|
|
12
|
+
write access only to the `Admin` role by default. Subfolders can broaden or narrow
|
|
13
|
+
access by adding their own `access.md`.
|
|
14
|
+
|
|
15
|
+
See [roles.yaml](roles.yaml) for the identity → role mapping. Access resolution and validation
|
|
16
|
+
run in the Bevel platform.
|
|
17
|
+
|
|
18
|
+
## Adding a folder-level rule
|
|
19
|
+
|
|
20
|
+
Drop an `access.md` into any folder, at any depth. Frontmatter
|
|
21
|
+
only — the body is ignored. Example:
|
|
22
|
+
|
|
23
|
+
```yaml
|
|
24
|
+
---
|
|
25
|
+
write:
|
|
26
|
+
- Admin
|
|
27
|
+
- Editor
|
|
28
|
+
- Jane Doe <jane.doe@example.com>
|
|
29
|
+
- deny Mallory Bad <mallory@example.com>
|
|
30
|
+
---
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
Each entry is either a grant (bare principal) or a denial (`deny <principal>` —
|
|
34
|
+
**lowercase `deny` only**; capitalised forms like `Deny` are treated as part of a
|
|
35
|
+
name). A principal is either a role name (matched case-insensitively against
|
|
36
|
+
`roles.yaml`) or a user reference in `Name <email>` form.
|