@bevel-software/platform-shared 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 +16 -41
- package/dist/git/types.d.ts +2 -2
- package/dist/workspace/join-request.d.ts +17 -17
- package/dist/workspace/join-request.d.ts.map +1 -1
- package/dist/workspace/join-request.js +33 -27
- package/dist/workspace/join-request.js.map +1 -1
- package/dist/workspace/kb-layout.d.ts +102 -31
- package/dist/workspace/kb-layout.d.ts.map +1 -1
- package/dist/workspace/kb-layout.js +123 -37
- package/dist/workspace/kb-layout.js.map +1 -1
- package/package.json +1 -1
- package/src/git/types.ts +2 -2
- package/src/workspace/join-request.ts +33 -27
- package/src/workspace/kb-layout.ts +136 -37
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* The join-request naming convention — how "asking to join a
|
|
2
|
+
* The join-request naming convention — how "asking to join a plugin" rides on
|
|
3
3
|
* plain change requests with zero new backend state.
|
|
4
4
|
*
|
|
5
5
|
* A join request IS a change request: a draft branch carrying one commit that
|
|
6
|
-
* adds the requester to the
|
|
6
|
+
* adds the requester to the plugin's `access.md` body `read:` list, opened
|
|
7
7
|
* against the default branch. What makes it recognisable — to the `Requested`
|
|
8
8
|
* chip, to the manager-side proposals surface, to idempotency — is only this
|
|
9
9
|
* branch-name convention. Both sides (backend, frontend) read it from here so
|
|
10
10
|
* they can never drift.
|
|
11
11
|
*
|
|
12
|
-
* <email-localpart>/join-<
|
|
12
|
+
* <email-localpart>/join-<plugin-kebab>-<pluginTag>-<requesterTag>
|
|
13
13
|
*
|
|
14
14
|
* follows the workspace's existing `<email-localpart>/<kebab-slug>` draft
|
|
15
15
|
* convention, so join branches sort with the requester's other drafts and
|
|
@@ -18,15 +18,15 @@
|
|
|
18
18
|
* WHY TWO TAGS: the localpart and the kebab slug are both LOSSY, and each
|
|
19
19
|
* loss has its own failure:
|
|
20
20
|
*
|
|
21
|
-
* - `
|
|
22
|
-
* knows the
|
|
23
|
-
* without this tag, listing one
|
|
21
|
+
* - `pluginTag` — over the EXACT plugin name, recomputable by anyone who
|
|
22
|
+
* knows the plugin. `Finance!` and `finance` share the slug `finance`;
|
|
23
|
+
* without this tag, listing one plugin's requests would match the other's
|
|
24
24
|
* branches, read the wrong `access.md` (unchanged on that branch), see an
|
|
25
25
|
* empty diff and SETTLE the request — closing a change request and
|
|
26
|
-
* deleting a branch that belong to a different
|
|
27
|
-
* is "the diff is empty", so
|
|
26
|
+
* deleting a branch that belong to a different plugin. The settle decision
|
|
27
|
+
* is "the diff is empty", so plugin identity must be exact BEFORE the diff
|
|
28
28
|
* is consulted, and `isJoinBranchFor` recomputes this tag to make it so.
|
|
29
|
-
* - `requesterTag` — over the full email (+
|
|
29
|
+
* - `requesterTag` — over the full email (+ plugin), NOT recomputable by a
|
|
30
30
|
* reader (a manager listing requests does not know each requester's
|
|
31
31
|
* email; `isJoinBranchFor` matches its shape only). It exists so
|
|
32
32
|
* `ali@bevel.software` and `ali@other.com` never share a branch — else
|
|
@@ -37,9 +37,9 @@
|
|
|
37
37
|
* ordinary access mutation path, and settling only ever closes a request
|
|
38
38
|
* whose file adds nothing over the default branch.
|
|
39
39
|
*/
|
|
40
|
-
/**
|
|
41
|
-
export function
|
|
42
|
-
return
|
|
40
|
+
/** Plugin name → the kebab slug used in the join branch (lossy by design). */
|
|
41
|
+
export function kebabPluginName(plugin) {
|
|
42
|
+
return plugin
|
|
43
43
|
.trim()
|
|
44
44
|
.toLowerCase()
|
|
45
45
|
.replace(/\s+/g, '-')
|
|
@@ -66,35 +66,41 @@ function shortTag(input) {
|
|
|
66
66
|
}
|
|
67
67
|
return hash.toString(36).padStart(TAG_LENGTH, '0').slice(-TAG_LENGTH);
|
|
68
68
|
}
|
|
69
|
-
/** The exact-
|
|
70
|
-
function
|
|
71
|
-
|
|
69
|
+
/** The exact-plugin tag — recomputable from the plugin name alone. */
|
|
70
|
+
function pluginTag(plugin) {
|
|
71
|
+
// `g:` predates the group→plugin rename, and it STAYS: the prefix is baked
|
|
72
|
+
// into every join branch already on a remote, and `isJoinBranchFor`
|
|
73
|
+
// recomputes this tag to recognise them. Changing it to `p:` would change
|
|
74
|
+
// every recomputed tag and orphan every in-flight join request. The prefix
|
|
75
|
+
// only disambiguates this tag's input from `u:<email>` — any stable byte
|
|
76
|
+
// does that, so there is nothing to gain by renaming it.
|
|
77
|
+
return shortTag(`g:${plugin}`);
|
|
72
78
|
}
|
|
73
|
-
/** The deterministic join branch for (requester,
|
|
74
|
-
export function joinBranchFor(email,
|
|
79
|
+
/** The deterministic join branch for (requester, plugin). */
|
|
80
|
+
export function joinBranchFor(email, plugin) {
|
|
75
81
|
const normalizedEmail = email.trim().toLowerCase();
|
|
76
82
|
const localpart = normalizedEmail.split('@')[0] || normalizedEmail;
|
|
77
|
-
const slug =
|
|
78
|
-
const requester = shortTag(`u:${normalizedEmail}\n${
|
|
79
|
-
// A
|
|
83
|
+
const slug = kebabPluginName(plugin);
|
|
84
|
+
const requester = shortTag(`u:${normalizedEmail}\n${plugin}`);
|
|
85
|
+
// A plugin whose name has no alphanumerics at all (`!!!`) kebabs to '' — the
|
|
80
86
|
// tags alone still yield a valid, matchable branch.
|
|
81
87
|
const middle = slug ? `${slug}-` : '';
|
|
82
|
-
return `${localpart}/join-${middle}${
|
|
88
|
+
return `${localpart}/join-${middle}${pluginTag(plugin)}-${requester}`;
|
|
83
89
|
}
|
|
84
90
|
/**
|
|
85
|
-
* Does `branch` look like SOMEBODY's join branch for EXACTLY `
|
|
91
|
+
* Does `branch` look like SOMEBODY's join branch for EXACTLY `plugin`?
|
|
86
92
|
*
|
|
87
|
-
* The
|
|
88
|
-
* what keeps slug-colliding
|
|
93
|
+
* The plugin half (slug + `pluginTag`) is recomputed and must match — this is
|
|
94
|
+
* what keeps slug-colliding plugins (`Finance!` vs `finance`) from seeing,
|
|
89
95
|
* and worse settling, each other's requests. The requester half cannot be
|
|
90
96
|
* recomputed (the reader has no email) and matches by shape; the requester's
|
|
91
97
|
* identity comes from the change request's own attribution.
|
|
92
98
|
*/
|
|
93
|
-
export function isJoinBranchFor(branch,
|
|
94
|
-
const slug =
|
|
99
|
+
export function isJoinBranchFor(branch, plugin) {
|
|
100
|
+
const slug = kebabPluginName(plugin);
|
|
95
101
|
const middle = slug ? `${escapeRegExp(slug)}-` : '';
|
|
96
102
|
const requester = `[0-9a-z]{${TAG_LENGTH}}`;
|
|
97
|
-
return new RegExp(`^[^/]+/join-${middle}${
|
|
103
|
+
return new RegExp(`^[^/]+/join-${middle}${pluginTag(plugin)}-${requester}$`).test(branch);
|
|
98
104
|
}
|
|
99
105
|
function escapeRegExp(s) {
|
|
100
106
|
return s.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"join-request.js","sourceRoot":"","sources":["../../src/workspace/join-request.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsCG;AAEH,
|
|
1
|
+
{"version":3,"file":"join-request.js","sourceRoot":"","sources":["../../src/workspace/join-request.ts"],"names":[],"mappings":"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"}
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
*
|
|
7
7
|
* <kbDirName>/
|
|
8
8
|
* ├── KnowledgeBase/ ← all team ontologies live here (the knowledge graph)
|
|
9
|
-
* ├──
|
|
9
|
+
* ├── Plugins/ ← one folder per plugin; each holds BOTH skills and tools
|
|
10
10
|
* ├── Data/ ← agent-produced records; parsed like KnowledgeBase/
|
|
11
11
|
* ├── Agents/ ← .agent files — agent role configurations (not the graph)
|
|
12
12
|
* ├── Pipelines/ ← .pipeline files — execution-layer processes (not the graph)
|
|
@@ -22,7 +22,7 @@
|
|
|
22
22
|
*
|
|
23
23
|
* These names are the single source of truth for both sides of the app:
|
|
24
24
|
* - Backend: the graph parser discovers ontologies under the
|
|
25
|
-
* {@link ONTOLOGY_ROOTS} (`KnowledgeBase/` and `Data/`); `
|
|
25
|
+
* {@link ONTOLOGY_ROOTS} (`KnowledgeBase/` and `Data/`); `Plugins/`,
|
|
26
26
|
* `Agents/`, `Pipelines/` (and anything else at the root) are ignored by
|
|
27
27
|
* parsing, validation, and the diagram.
|
|
28
28
|
* - Frontend: the file tree renders these root folders as distinct
|
|
@@ -33,35 +33,106 @@
|
|
|
33
33
|
/** Folder under the repo root that contains all team ontologies. */
|
|
34
34
|
export declare const KNOWLEDGE_BASE_DIR = "KnowledgeBase";
|
|
35
35
|
/**
|
|
36
|
-
* Folder under the repo root that holds the
|
|
36
|
+
* Folder under the repo root that holds the plugins.
|
|
37
37
|
*
|
|
38
|
-
*
|
|
39
|
-
*
|
|
40
|
-
*
|
|
38
|
+
* Plugins/<Plugin>/plugin.json the Agent Plugins manifest
|
|
39
|
+
* Plugins/<Plugin>/skills/<skill>/SKILL.md a skill
|
|
40
|
+
* Plugins/<Plugin>/mcp.json MCP servers
|
|
41
|
+
* Plugins/<Plugin>/software.bevel.hexis/tools/ http + inline `.tool` manuals
|
|
42
|
+
* Plugins/<Plugin>/access.md who can read/write the plugin
|
|
41
43
|
*
|
|
42
|
-
*
|
|
43
|
-
*
|
|
44
|
-
*
|
|
45
|
-
* the
|
|
44
|
+
* Each folder is one plugin, laid out per the Agent Plugins specification
|
|
45
|
+
* (https://agent-plugins.org, v1.0.0) so another conformant client can load it:
|
|
46
|
+
* it finds the manifest, the skills and the MCP servers, and ignores everything
|
|
47
|
+
* under the reverse-DNS extension directory.
|
|
46
48
|
*
|
|
47
|
-
*
|
|
48
|
-
*
|
|
49
|
-
*
|
|
49
|
+
* Two parts of a plugin are ours and deliberately outside the portable core:
|
|
50
|
+
*
|
|
51
|
+
* - `access.md`, which must sit at the PLUGIN ROOT. Access resolution walks
|
|
52
|
+
* repo root → file directory accumulating rules, so the same file one level
|
|
53
|
+
* down would govern only that subtree — silently narrowing what it protects.
|
|
54
|
+
* - `software.bevel.hexis/tools/*.tool`, the UTCP manuals whose `http` and
|
|
55
|
+
* `inline` types the spec has no slot for. `mcp`-type manuals are emitted as
|
|
56
|
+
* real `mcp.json` entries instead, so the portable half stays portable.
|
|
57
|
+
*
|
|
58
|
+
* Skills and tools live TOGETHER in one plugin because they share a single
|
|
59
|
+
* access boundary: a tool a plugin cannot read is a skill that plugin cannot
|
|
60
|
+
* run, so splitting them across two roots meant maintaining the same permission
|
|
61
|
+
* twice and letting them drift.
|
|
62
|
+
*
|
|
63
|
+
* A plugin is not a registry of unique names — it is a folder. The same
|
|
64
|
+
* integration may exist in several plugins as separate files (`Everyone/…/
|
|
65
|
+
* notion.tool` and `Finance/…/notion.tool`), each with its own credentials and
|
|
50
66
|
* its own access rule. That duplication is the design, not an accident.
|
|
67
|
+
*
|
|
68
|
+
* The DIRECTORY name is unconstrained by the spec (§4.1 — a plugin is located
|
|
69
|
+
* by path, and the name carries no meaning to a client), so folders keep their
|
|
70
|
+
* display casing. The lowercase slug the spec does constrain lives in the
|
|
71
|
+
* manifest's `name` field.
|
|
72
|
+
*/
|
|
73
|
+
export declare const PLUGINS_DIR = "Plugins";
|
|
74
|
+
/**
|
|
75
|
+
* The pre-rename name of {@link PLUGINS_DIR}. Referenced ONLY by the migration
|
|
76
|
+
* that renames it — every other consumer should be reading the new name, and a
|
|
77
|
+
* second live spelling is exactly how two layouts start being supported by
|
|
78
|
+
* accident.
|
|
79
|
+
*/
|
|
80
|
+
export declare const LEGACY_GROUPS_DIR = "Groups";
|
|
81
|
+
/** The manifest that makes a directory a plugin (Agent Plugins §4.1). */
|
|
82
|
+
export declare const PLUGIN_MANIFEST_FILE = "plugin.json";
|
|
83
|
+
/** The MCP server configuration a conformant client reads (Agent Plugins §8). */
|
|
84
|
+
export declare const PLUGIN_MCP_FILE = "mcp.json";
|
|
85
|
+
/** Where a plugin's skills live, one folder each (Agent Plugins §7.1). */
|
|
86
|
+
export declare const PLUGIN_SKILLS_DIR = "skills";
|
|
87
|
+
/**
|
|
88
|
+
* Our reverse-DNS extension namespace. The spec reserves these directories for
|
|
89
|
+
* exactly this — client-specific behaviour that a portable core should not
|
|
90
|
+
* carry — so anything a conformant third-party client has no way to interpret
|
|
91
|
+
* goes here rather than loose in the plugin root.
|
|
92
|
+
*/
|
|
93
|
+
export declare const HEXIS_EXTENSION_NS = "software.bevel.hexis";
|
|
94
|
+
/** UTCP manuals whose `http`/`inline` types the spec cannot express. */
|
|
95
|
+
export declare const HEXIS_TOOLS_DIR = "software.bevel.hexis/tools";
|
|
96
|
+
/**
|
|
97
|
+
* The manifest `name` for a plugin folder: lowercased, anything outside
|
|
98
|
+
* `[a-z0-9.-]` folded to `-`, runs collapsed, ends trimmed to alphanumerics.
|
|
99
|
+
*
|
|
100
|
+
* The schema's pattern is `^(?!.*(?:--|\.\.))[a-z0-9](?:[a-z0-9.-]*[a-z0-9])?$`
|
|
101
|
+
* — so a folder like `personal-<user-id>` whose sanitized id happens to contain
|
|
102
|
+
* a doubled separator would produce an INVALID manifest, which is fatal to a
|
|
103
|
+
* conformant client. Collapsing runs is what makes that unrepresentable rather
|
|
104
|
+
* than merely unlikely.
|
|
105
|
+
*/
|
|
106
|
+
export declare function pluginManifestName(folderName: string): string;
|
|
107
|
+
/** The schema a v1.0.0 manifest declares, and the version both files must agree on. */
|
|
108
|
+
export declare const AGENT_PLUGINS_SCHEMA_VERSION = "1.0.0";
|
|
109
|
+
export declare const PLUGIN_MANIFEST_SCHEMA = "https://agent-plugins.org/schemas/1.0.0/plugin.schema.json";
|
|
110
|
+
export declare const PLUGIN_MCP_SCHEMA = "https://agent-plugins.org/schemas/1.0.0/mcp.schema.json";
|
|
111
|
+
/**
|
|
112
|
+
* A minimal, valid `plugin.json` for a plugin folder.
|
|
113
|
+
*
|
|
114
|
+
* Deliberately only the two required fields. `version`, `license` and the rest
|
|
115
|
+
* are optional metadata about a DISTRIBUTED package, and inventing values for a
|
|
116
|
+
* folder someone just made in the app would be asserting things nobody said —
|
|
117
|
+
* a plugin here is a place a team keeps skills, not something published.
|
|
118
|
+
*
|
|
119
|
+
* The display name is the folder, which is why nothing here carries one: the
|
|
120
|
+
* manifest's `name` is constrained to a lowercase slug, and the field set is
|
|
121
|
+
* closed, so there is no conformant home for "Sales" other than an extension.
|
|
51
122
|
*/
|
|
52
|
-
export declare
|
|
123
|
+
export declare function renderPluginManifest(folderName: string): string;
|
|
53
124
|
/**
|
|
54
|
-
* The reserved name prefix marking a personal folder under `
|
|
55
|
-
* `
|
|
125
|
+
* The reserved name prefix marking a personal folder under `Plugins/` —
|
|
126
|
+
* `Plugins/personal-<user-id>/` is where a person's own skills live: created
|
|
56
127
|
* implicitly on their first personal skill, private by default (its seeded
|
|
57
128
|
* `access.md` names only its owner), and never listed as a group.
|
|
58
129
|
*
|
|
59
130
|
* The marker is STRUCTURAL on purpose: every surface that enumerates groups
|
|
60
131
|
* (catalog scan, sidebar, counts) filters on the name alone, with no access
|
|
61
|
-
* lookup needed, and the
|
|
62
|
-
* prefix — so a regular
|
|
132
|
+
* lookup needed, and the plugin-creation endpoint refuses names carrying the
|
|
133
|
+
* prefix — so a regular plugin can never squat on someone's personal folder.
|
|
63
134
|
*/
|
|
64
|
-
export declare const
|
|
135
|
+
export declare const PERSONAL_PLUGIN_PREFIX = "personal-";
|
|
65
136
|
/**
|
|
66
137
|
* The one personal folder name for a user — keyed to the STABLE user id, not
|
|
67
138
|
* the email: emails change, and a folder keyed to one would be orphaned the
|
|
@@ -70,23 +141,23 @@ export declare const PERSONAL_GROUP_PREFIX = "personal-";
|
|
|
70
141
|
* sanitizer — the id lands in the folder name exactly as it lands in the
|
|
71
142
|
* user's suggestion-branch names, so the two spellings can never disagree.
|
|
72
143
|
*/
|
|
73
|
-
export declare function
|
|
74
|
-
/** Whether a `
|
|
75
|
-
export declare function
|
|
144
|
+
export declare function personalPluginFolderName(userId: string): string;
|
|
145
|
+
/** Whether a `Plugins/` child is somebody's personal folder. */
|
|
146
|
+
export declare function isPersonalPluginFolder(folderName: string): boolean;
|
|
76
147
|
/**
|
|
77
|
-
* The
|
|
78
|
-
* sits outside any
|
|
148
|
+
* The plugin a repo-root-relative path belongs to, or `null` for content that
|
|
149
|
+
* sits outside any plugin.
|
|
79
150
|
*
|
|
80
|
-
*
|
|
81
|
-
*
|
|
82
|
-
*
|
|
83
|
-
* KnowledgeBase/Product/…
|
|
151
|
+
* Plugins/GTM/skills/heyreach-campaign/SKILL.md → 'GTM'
|
|
152
|
+
* Plugins/GTM/mcp.json → 'GTM'
|
|
153
|
+
* Plugins/loose-skill/SKILL.md → 'loose-skill' (the folder IS the plugin)
|
|
154
|
+
* KnowledgeBase/Product/… → null (not a plugin root)
|
|
84
155
|
*
|
|
85
|
-
* Returns null rather than throwing because a
|
|
86
|
-
* have. Callers bucket by it; nothing requires it.
|
|
156
|
+
* Returns null rather than throwing because a plugin is a property SOME paths
|
|
157
|
+
* have. Callers bucket by it; nothing requires it. A plugin-less skill is a
|
|
87
158
|
* real, supported state — the prototype calls those "yours alone".
|
|
88
159
|
*/
|
|
89
|
-
export declare function
|
|
160
|
+
export declare function pluginOfPath(repoRelativePath: string): string | null;
|
|
90
161
|
/**
|
|
91
162
|
* Folder under the repo root for agent-produced records (pipeline instances,
|
|
92
163
|
* work items, intermediate outputs). Parsed exactly like `KnowledgeBase/`:
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"kb-layout.d.ts","sourceRoot":"","sources":["../../src/workspace/kb-layout.ts"],"names":[],"mappings":"AAEA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AAEH,oEAAoE;AACpE,eAAO,MAAM,kBAAkB,kBAAkB,CAAC;AAElD
|
|
1
|
+
{"version":3,"file":"kb-layout.d.ts","sourceRoot":"","sources":["../../src/workspace/kb-layout.ts"],"names":[],"mappings":"AAEA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AAEH,oEAAoE;AACpE,eAAO,MAAM,kBAAkB,kBAAkB,CAAC;AAElD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqCG;AACH,eAAO,MAAM,WAAW,YAAY,CAAC;AAErC;;;;;GAKG;AACH,eAAO,MAAM,iBAAiB,WAAW,CAAC;AAE1C,yEAAyE;AACzE,eAAO,MAAM,oBAAoB,gBAAgB,CAAC;AAElD,iFAAiF;AACjF,eAAO,MAAM,eAAe,aAAa,CAAC;AAE1C,0EAA0E;AAC1E,eAAO,MAAM,iBAAiB,WAAW,CAAC;AAE1C;;;;;GAKG;AACH,eAAO,MAAM,kBAAkB,yBAAyB,CAAC;AAEzD,wEAAwE;AACxE,eAAO,MAAM,eAAe,+BAAgC,CAAC;AAE7D;;;;;;;;;GASG;AACH,wBAAgB,kBAAkB,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,CAa7D;AAED,uFAAuF;AACvF,eAAO,MAAM,4BAA4B,UAAU,CAAC;AACpD,eAAO,MAAM,sBAAsB,+DAAyF,CAAC;AAC7H,eAAO,MAAM,iBAAiB,4DAAsF,CAAC;AAErH;;;;;;;;;;;GAWG;AACH,wBAAgB,oBAAoB,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,CAM/D;AAED;;;;;;;;;;GAUG;AACH,eAAO,MAAM,sBAAsB,cAAc,CAAC;AAElD;;;;;;;GAOG;AACH,wBAAgB,wBAAwB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAE/D;AAED,gEAAgE;AAChE,wBAAgB,sBAAsB,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAElE;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,YAAY,CAAC,gBAAgB,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAOpE;AAED;;;;GAIG;AACH,eAAO,MAAM,QAAQ,SAAS,CAAC;AAE/B,0GAA0G;AAC1G,eAAO,MAAM,UAAU,WAAW,CAAC;AAEnC,6GAA6G;AAC7G,eAAO,MAAM,aAAa,cAAc,CAAC;AAEzC;;;GAGG;AACH,eAAO,MAAM,cAAc,EAAE,SAAS,MAAM,EAAmC,CAAC;AAEhF,gFAAgF;AAChF,eAAO,MAAM,aAAa,cAAc,CAAC;AAEzC,qFAAqF;AACrF,eAAO,MAAM,YAAY,cAAc,CAAC;AAExC,+EAA+E;AAC/E,eAAO,MAAM,gBAAgB,aAAyC,CAAC;AAEvE;;;;;GAKG;AACH,MAAM,MAAM,QAAQ,GAAG,MAAM,GAAG,IAAI,CAAC"}
|
|
@@ -7,7 +7,7 @@ import { branchSegment } from '../git/branchAuthor.js';
|
|
|
7
7
|
*
|
|
8
8
|
* <kbDirName>/
|
|
9
9
|
* ├── KnowledgeBase/ ← all team ontologies live here (the knowledge graph)
|
|
10
|
-
* ├──
|
|
10
|
+
* ├── Plugins/ ← one folder per plugin; each holds BOTH skills and tools
|
|
11
11
|
* ├── Data/ ← agent-produced records; parsed like KnowledgeBase/
|
|
12
12
|
* ├── Agents/ ← .agent files — agent role configurations (not the graph)
|
|
13
13
|
* ├── Pipelines/ ← .pipeline files — execution-layer processes (not the graph)
|
|
@@ -23,7 +23,7 @@ import { branchSegment } from '../git/branchAuthor.js';
|
|
|
23
23
|
*
|
|
24
24
|
* These names are the single source of truth for both sides of the app:
|
|
25
25
|
* - Backend: the graph parser discovers ontologies under the
|
|
26
|
-
* {@link ONTOLOGY_ROOTS} (`KnowledgeBase/` and `Data/`); `
|
|
26
|
+
* {@link ONTOLOGY_ROOTS} (`KnowledgeBase/` and `Data/`); `Plugins/`,
|
|
27
27
|
* `Agents/`, `Pipelines/` (and anything else at the root) are ignored by
|
|
28
28
|
* parsing, validation, and the diagram.
|
|
29
29
|
* - Frontend: the file tree renders these root folders as distinct
|
|
@@ -34,35 +34,121 @@ import { branchSegment } from '../git/branchAuthor.js';
|
|
|
34
34
|
/** Folder under the repo root that contains all team ontologies. */
|
|
35
35
|
export const KNOWLEDGE_BASE_DIR = 'KnowledgeBase';
|
|
36
36
|
/**
|
|
37
|
-
* Folder under the repo root that holds the
|
|
37
|
+
* Folder under the repo root that holds the plugins.
|
|
38
38
|
*
|
|
39
|
-
*
|
|
40
|
-
*
|
|
41
|
-
*
|
|
39
|
+
* Plugins/<Plugin>/plugin.json the Agent Plugins manifest
|
|
40
|
+
* Plugins/<Plugin>/skills/<skill>/SKILL.md a skill
|
|
41
|
+
* Plugins/<Plugin>/mcp.json MCP servers
|
|
42
|
+
* Plugins/<Plugin>/software.bevel.hexis/tools/ http + inline `.tool` manuals
|
|
43
|
+
* Plugins/<Plugin>/access.md who can read/write the plugin
|
|
42
44
|
*
|
|
43
|
-
*
|
|
44
|
-
*
|
|
45
|
-
*
|
|
46
|
-
* the
|
|
45
|
+
* Each folder is one plugin, laid out per the Agent Plugins specification
|
|
46
|
+
* (https://agent-plugins.org, v1.0.0) so another conformant client can load it:
|
|
47
|
+
* it finds the manifest, the skills and the MCP servers, and ignores everything
|
|
48
|
+
* under the reverse-DNS extension directory.
|
|
47
49
|
*
|
|
48
|
-
*
|
|
49
|
-
*
|
|
50
|
-
*
|
|
50
|
+
* Two parts of a plugin are ours and deliberately outside the portable core:
|
|
51
|
+
*
|
|
52
|
+
* - `access.md`, which must sit at the PLUGIN ROOT. Access resolution walks
|
|
53
|
+
* repo root → file directory accumulating rules, so the same file one level
|
|
54
|
+
* down would govern only that subtree — silently narrowing what it protects.
|
|
55
|
+
* - `software.bevel.hexis/tools/*.tool`, the UTCP manuals whose `http` and
|
|
56
|
+
* `inline` types the spec has no slot for. `mcp`-type manuals are emitted as
|
|
57
|
+
* real `mcp.json` entries instead, so the portable half stays portable.
|
|
58
|
+
*
|
|
59
|
+
* Skills and tools live TOGETHER in one plugin because they share a single
|
|
60
|
+
* access boundary: a tool a plugin cannot read is a skill that plugin cannot
|
|
61
|
+
* run, so splitting them across two roots meant maintaining the same permission
|
|
62
|
+
* twice and letting them drift.
|
|
63
|
+
*
|
|
64
|
+
* A plugin is not a registry of unique names — it is a folder. The same
|
|
65
|
+
* integration may exist in several plugins as separate files (`Everyone/…/
|
|
66
|
+
* notion.tool` and `Finance/…/notion.tool`), each with its own credentials and
|
|
51
67
|
* its own access rule. That duplication is the design, not an accident.
|
|
68
|
+
*
|
|
69
|
+
* The DIRECTORY name is unconstrained by the spec (§4.1 — a plugin is located
|
|
70
|
+
* by path, and the name carries no meaning to a client), so folders keep their
|
|
71
|
+
* display casing. The lowercase slug the spec does constrain lives in the
|
|
72
|
+
* manifest's `name` field.
|
|
52
73
|
*/
|
|
53
|
-
export const
|
|
74
|
+
export const PLUGINS_DIR = 'Plugins';
|
|
75
|
+
/**
|
|
76
|
+
* The pre-rename name of {@link PLUGINS_DIR}. Referenced ONLY by the migration
|
|
77
|
+
* that renames it — every other consumer should be reading the new name, and a
|
|
78
|
+
* second live spelling is exactly how two layouts start being supported by
|
|
79
|
+
* accident.
|
|
80
|
+
*/
|
|
81
|
+
export const LEGACY_GROUPS_DIR = 'Groups';
|
|
82
|
+
/** The manifest that makes a directory a plugin (Agent Plugins §4.1). */
|
|
83
|
+
export const PLUGIN_MANIFEST_FILE = 'plugin.json';
|
|
84
|
+
/** The MCP server configuration a conformant client reads (Agent Plugins §8). */
|
|
85
|
+
export const PLUGIN_MCP_FILE = 'mcp.json';
|
|
86
|
+
/** Where a plugin's skills live, one folder each (Agent Plugins §7.1). */
|
|
87
|
+
export const PLUGIN_SKILLS_DIR = 'skills';
|
|
88
|
+
/**
|
|
89
|
+
* Our reverse-DNS extension namespace. The spec reserves these directories for
|
|
90
|
+
* exactly this — client-specific behaviour that a portable core should not
|
|
91
|
+
* carry — so anything a conformant third-party client has no way to interpret
|
|
92
|
+
* goes here rather than loose in the plugin root.
|
|
93
|
+
*/
|
|
94
|
+
export const HEXIS_EXTENSION_NS = 'software.bevel.hexis';
|
|
95
|
+
/** UTCP manuals whose `http`/`inline` types the spec cannot express. */
|
|
96
|
+
export const HEXIS_TOOLS_DIR = `${HEXIS_EXTENSION_NS}/tools`;
|
|
97
|
+
/**
|
|
98
|
+
* The manifest `name` for a plugin folder: lowercased, anything outside
|
|
99
|
+
* `[a-z0-9.-]` folded to `-`, runs collapsed, ends trimmed to alphanumerics.
|
|
100
|
+
*
|
|
101
|
+
* The schema's pattern is `^(?!.*(?:--|\.\.))[a-z0-9](?:[a-z0-9.-]*[a-z0-9])?$`
|
|
102
|
+
* — so a folder like `personal-<user-id>` whose sanitized id happens to contain
|
|
103
|
+
* a doubled separator would produce an INVALID manifest, which is fatal to a
|
|
104
|
+
* conformant client. Collapsing runs is what makes that unrepresentable rather
|
|
105
|
+
* than merely unlikely.
|
|
106
|
+
*/
|
|
107
|
+
export function pluginManifestName(folderName) {
|
|
108
|
+
const slug = folderName
|
|
109
|
+
.toLowerCase()
|
|
110
|
+
.replace(/[^a-z0-9.-]+/g, '-')
|
|
111
|
+
.replace(/-{2,}/g, '-')
|
|
112
|
+
.replace(/\.{2,}/g, '.')
|
|
113
|
+
.replace(/^[^a-z0-9]+/, '')
|
|
114
|
+
.replace(/[^a-z0-9]+$/, '')
|
|
115
|
+
.slice(0, 64)
|
|
116
|
+
.replace(/[^a-z0-9]+$/, '');
|
|
117
|
+
// Every character can be stripped (a folder named `---`), and `name` is
|
|
118
|
+
// required — fall back rather than emit a manifest that fails validation.
|
|
119
|
+
return slug || 'plugin';
|
|
120
|
+
}
|
|
121
|
+
/** The schema a v1.0.0 manifest declares, and the version both files must agree on. */
|
|
122
|
+
export const AGENT_PLUGINS_SCHEMA_VERSION = '1.0.0';
|
|
123
|
+
export const PLUGIN_MANIFEST_SCHEMA = `https://agent-plugins.org/schemas/${AGENT_PLUGINS_SCHEMA_VERSION}/plugin.schema.json`;
|
|
124
|
+
export const PLUGIN_MCP_SCHEMA = `https://agent-plugins.org/schemas/${AGENT_PLUGINS_SCHEMA_VERSION}/mcp.schema.json`;
|
|
125
|
+
/**
|
|
126
|
+
* A minimal, valid `plugin.json` for a plugin folder.
|
|
127
|
+
*
|
|
128
|
+
* Deliberately only the two required fields. `version`, `license` and the rest
|
|
129
|
+
* are optional metadata about a DISTRIBUTED package, and inventing values for a
|
|
130
|
+
* folder someone just made in the app would be asserting things nobody said —
|
|
131
|
+
* a plugin here is a place a team keeps skills, not something published.
|
|
132
|
+
*
|
|
133
|
+
* The display name is the folder, which is why nothing here carries one: the
|
|
134
|
+
* manifest's `name` is constrained to a lowercase slug, and the field set is
|
|
135
|
+
* closed, so there is no conformant home for "Sales" other than an extension.
|
|
136
|
+
*/
|
|
137
|
+
export function renderPluginManifest(folderName) {
|
|
138
|
+
return `${JSON.stringify({ $schema: PLUGIN_MANIFEST_SCHEMA, name: pluginManifestName(folderName) }, null, 2)}\n`;
|
|
139
|
+
}
|
|
54
140
|
/**
|
|
55
|
-
* The reserved name prefix marking a personal folder under `
|
|
56
|
-
* `
|
|
141
|
+
* The reserved name prefix marking a personal folder under `Plugins/` —
|
|
142
|
+
* `Plugins/personal-<user-id>/` is where a person's own skills live: created
|
|
57
143
|
* implicitly on their first personal skill, private by default (its seeded
|
|
58
144
|
* `access.md` names only its owner), and never listed as a group.
|
|
59
145
|
*
|
|
60
146
|
* The marker is STRUCTURAL on purpose: every surface that enumerates groups
|
|
61
147
|
* (catalog scan, sidebar, counts) filters on the name alone, with no access
|
|
62
|
-
* lookup needed, and the
|
|
63
|
-
* prefix — so a regular
|
|
148
|
+
* lookup needed, and the plugin-creation endpoint refuses names carrying the
|
|
149
|
+
* prefix — so a regular plugin can never squat on someone's personal folder.
|
|
64
150
|
*/
|
|
65
|
-
export const
|
|
151
|
+
export const PERSONAL_PLUGIN_PREFIX = 'personal-';
|
|
66
152
|
/**
|
|
67
153
|
* The one personal folder name for a user — keyed to the STABLE user id, not
|
|
68
154
|
* the email: emails change, and a folder keyed to one would be orphaned the
|
|
@@ -71,33 +157,33 @@ export const PERSONAL_GROUP_PREFIX = 'personal-';
|
|
|
71
157
|
* sanitizer — the id lands in the folder name exactly as it lands in the
|
|
72
158
|
* user's suggestion-branch names, so the two spellings can never disagree.
|
|
73
159
|
*/
|
|
74
|
-
export function
|
|
75
|
-
return `${
|
|
160
|
+
export function personalPluginFolderName(userId) {
|
|
161
|
+
return `${PERSONAL_PLUGIN_PREFIX}${branchSegment(userId)}`;
|
|
76
162
|
}
|
|
77
|
-
/** Whether a `
|
|
78
|
-
export function
|
|
79
|
-
return folderName.startsWith(
|
|
163
|
+
/** Whether a `Plugins/` child is somebody's personal folder. */
|
|
164
|
+
export function isPersonalPluginFolder(folderName) {
|
|
165
|
+
return folderName.startsWith(PERSONAL_PLUGIN_PREFIX);
|
|
80
166
|
}
|
|
81
167
|
/**
|
|
82
|
-
* The
|
|
83
|
-
* sits outside any
|
|
168
|
+
* The plugin a repo-root-relative path belongs to, or `null` for content that
|
|
169
|
+
* sits outside any plugin.
|
|
84
170
|
*
|
|
85
|
-
*
|
|
86
|
-
*
|
|
87
|
-
*
|
|
88
|
-
* KnowledgeBase/Product/…
|
|
171
|
+
* Plugins/GTM/skills/heyreach-campaign/SKILL.md → 'GTM'
|
|
172
|
+
* Plugins/GTM/mcp.json → 'GTM'
|
|
173
|
+
* Plugins/loose-skill/SKILL.md → 'loose-skill' (the folder IS the plugin)
|
|
174
|
+
* KnowledgeBase/Product/… → null (not a plugin root)
|
|
89
175
|
*
|
|
90
|
-
* Returns null rather than throwing because a
|
|
91
|
-
* have. Callers bucket by it; nothing requires it.
|
|
176
|
+
* Returns null rather than throwing because a plugin is a property SOME paths
|
|
177
|
+
* have. Callers bucket by it; nothing requires it. A plugin-less skill is a
|
|
92
178
|
* real, supported state — the prototype calls those "yours alone".
|
|
93
179
|
*/
|
|
94
|
-
export function
|
|
180
|
+
export function pluginOfPath(repoRelativePath) {
|
|
95
181
|
const segments = repoRelativePath.split('/').filter(Boolean);
|
|
96
|
-
if (segments[0] !==
|
|
182
|
+
if (segments[0] !== PLUGINS_DIR)
|
|
97
183
|
return null;
|
|
98
|
-
// Needs a segment for the
|
|
99
|
-
// `
|
|
100
|
-
// and a loose `
|
|
184
|
+
// Needs a segment for the plugin AND at least one below it, otherwise
|
|
185
|
+
// `Plugins/GTM` (the folder itself) would report itself as being in a plugin,
|
|
186
|
+
// and a loose `Plugins/slack.tool` would report a plugin named "slack.tool".
|
|
101
187
|
return segments.length >= 3 ? (segments[1] ?? null) : null;
|
|
102
188
|
}
|
|
103
189
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"kb-layout.js","sourceRoot":"","sources":["../../src/workspace/kb-layout.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AAEvD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AAEH,oEAAoE;AACpE,MAAM,CAAC,MAAM,kBAAkB,GAAG,eAAe,CAAC;AAElD
|
|
1
|
+
{"version":3,"file":"kb-layout.js","sourceRoot":"","sources":["../../src/workspace/kb-layout.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bevel-software/platform-shared",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.8.0",
|
|
4
4
|
"description": "Shared types and pure domain utilities of the Bevel core platform (auth, workspace, git/workflow contracts, branch registry).",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
package/src/git/types.ts
CHANGED
|
@@ -120,8 +120,8 @@ export interface IGitService {
|
|
|
120
120
|
/**
|
|
121
121
|
* Skip the per-user protected-branch access gate for THIS push. Only
|
|
122
122
|
* for system-authorized flows whose endpoint is itself the
|
|
123
|
-
* authorization (
|
|
124
|
-
* unused name under `
|
|
123
|
+
* authorization (plugin provisioning: any signed-in user may claim an
|
|
124
|
+
* unused name under `Plugins/`, and the seeded access.md governs
|
|
125
125
|
* everything after). Never thread a raw user request into this.
|
|
126
126
|
*/
|
|
127
127
|
systemAuthorized?: boolean;
|