@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.
@@ -1,15 +1,15 @@
1
1
  /**
2
- * The join-request naming convention — how "asking to join a group" rides on
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 group's `access.md` body `read:` list, opened
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-<group-kebab>-<groupTag>-<requesterTag>
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
- * - `groupTag` — over the EXACT group name, recomputable by anyone who
22
- * knows the group. `Finance!` and `finance` share the slug `finance`;
23
- * without this tag, listing one group's requests would match the other's
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 group. The settle decision
27
- * is "the diff is empty", so group identity must be exact BEFORE the diff
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 (+ group), NOT recomputable by a
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
- /** Group name → the kebab slug used in the join branch (lossy by design). */
41
- export function kebabGroupName(group) {
42
- return group
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-group tag — recomputable from the group name alone. */
70
- function groupTag(group) {
71
- return shortTag(`g:${group}`);
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, group). */
74
- export function joinBranchFor(email, group) {
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 = kebabGroupName(group);
78
- const requester = shortTag(`u:${normalizedEmail}\n${group}`);
79
- // A group whose name has no alphanumerics at all (`!!!`) kebabs to '' — the
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}${groupTag(group)}-${requester}`;
88
+ return `${localpart}/join-${middle}${pluginTag(plugin)}-${requester}`;
83
89
  }
84
90
  /**
85
- * Does `branch` look like SOMEBODY's join branch for EXACTLY `group`?
91
+ * Does `branch` look like SOMEBODY's join branch for EXACTLY `plugin`?
86
92
  *
87
- * The group half (slug + `groupTag`) is recomputed and must match — this is
88
- * what keeps slug-colliding groups (`Finance!` vs `finance`) from seeing,
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, group) {
94
- const slug = kebabGroupName(group);
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}${groupTag(group)}-${requester}$`).test(branch);
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,6EAA6E;AAC7E,MAAM,UAAU,cAAc,CAAC,KAAa;IAC1C,OAAO,KAAK;SACT,IAAI,EAAE;SACN,WAAW,EAAE;SACb,OAAO,CAAC,MAAM,EAAE,GAAG,CAAC;SACpB,OAAO,CAAC,aAAa,EAAE,EAAE,CAAC;SAC1B,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC;SACnB,OAAO,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC;AAC3B,CAAC;AAED,6DAA6D;AAC7D,MAAM,UAAU,GAAG,CAAC,CAAC;AAErB;;;;;;;GAOG;AACH,SAAS,QAAQ,CAAC,KAAa;IAC7B,IAAI,IAAI,GAAG,UAAU,CAAC;IACtB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACtC,IAAI,IAAI,KAAK,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC;QAC5B,qEAAqE;QACrE,IAAI,GAAG,CAAC,IAAI,GAAG,CAAC,CAAC,IAAI,IAAI,CAAC,CAAC,GAAG,CAAC,IAAI,IAAI,CAAC,CAAC,GAAG,CAAC,IAAI,IAAI,CAAC,CAAC,GAAG,CAAC,IAAI,IAAI,CAAC,CAAC,GAAG,CAAC,IAAI,IAAI,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC;IAC/F,CAAC;IACD,OAAO,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,UAAU,EAAE,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,UAAU,CAAC,CAAC;AACxE,CAAC;AAED,oEAAoE;AACpE,SAAS,QAAQ,CAAC,KAAa;IAC7B,OAAO,QAAQ,CAAC,KAAK,KAAK,EAAE,CAAC,CAAC;AAChC,CAAC;AAED,4DAA4D;AAC5D,MAAM,UAAU,aAAa,CAAC,KAAa,EAAE,KAAa;IACxD,MAAM,eAAe,GAAG,KAAK,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;IACnD,MAAM,SAAS,GAAG,eAAe,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,eAAe,CAAC;IACnE,MAAM,IAAI,GAAG,cAAc,CAAC,KAAK,CAAC,CAAC;IACnC,MAAM,SAAS,GAAG,QAAQ,CAAC,KAAK,eAAe,KAAK,KAAK,EAAE,CAAC,CAAC;IAC7D,4EAA4E;IAC5E,oDAAoD;IACpD,MAAM,MAAM,GAAG,IAAI,CAAC,CAAC,CAAC,GAAG,IAAI,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC;IACtC,OAAO,GAAG,SAAS,SAAS,MAAM,GAAG,QAAQ,CAAC,KAAK,CAAC,IAAI,SAAS,EAAE,CAAC;AACtE,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,UAAU,eAAe,CAAC,MAAc,EAAE,KAAa;IAC3D,MAAM,IAAI,GAAG,cAAc,CAAC,KAAK,CAAC,CAAC;IACnC,MAAM,MAAM,GAAG,IAAI,CAAC,CAAC,CAAC,GAAG,YAAY,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC;IACpD,MAAM,SAAS,GAAG,YAAY,UAAU,GAAG,CAAC;IAC5C,OAAO,IAAI,MAAM,CAAC,eAAe,MAAM,GAAG,QAAQ,CAAC,KAAK,CAAC,IAAI,SAAS,GAAG,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;AAC1F,CAAC;AAED,SAAS,YAAY,CAAC,CAAS;IAC7B,OAAO,CAAC,CAAC,OAAO,CAAC,qBAAqB,EAAE,MAAM,CAAC,CAAC;AAClD,CAAC"}
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
- * ├── Groups/ ← one folder per group; each holds BOTH skills and tools
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/`); `Groups/`,
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 groups.
36
+ * Folder under the repo root that holds the plugins.
37
37
  *
38
- * Groups/<Group>/<skill>/SKILL.md a skill
39
- * Groups/<Group>/<name>.tool a tool manual
40
- * Groups/<Group>/access.md who can read/write the whole group
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
- * One folder is one group. Skills and tools live TOGETHER inside it because
43
- * they share a single access boundary: a tool a group cannot read is a skill
44
- * that group cannot run, so splitting them across two roots meant maintaining
45
- * the same permission twice and letting them drift.
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
- * A group is not a registry of unique names — it is a folder. The same
48
- * integration may exist in several groups as separate files (`Everyone/
49
- * notion.tool` and `Finance/notion.tool`), each with its own credentials and
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 const GROUPS_DIR = "Groups";
123
+ export declare function renderPluginManifest(folderName: string): string;
53
124
  /**
54
- * The reserved name prefix marking a personal folder under `Groups/` —
55
- * `Groups/personal-<user-id>/` is where a person's own skills live: created
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 group-creation endpoint refuses names carrying the
62
- * prefix — so a regular group can never squat on someone's personal folder.
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 PERSONAL_GROUP_PREFIX = "personal-";
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 personalGroupFolderName(userId: string): string;
74
- /** Whether a `Groups/` child is somebody's personal folder. */
75
- export declare function isPersonalGroupFolder(folderName: string): boolean;
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 group a repo-root-relative path belongs to, or `null` for content that
78
- * sits outside any group.
148
+ * The plugin a repo-root-relative path belongs to, or `null` for content that
149
+ * sits outside any plugin.
79
150
  *
80
- * Groups/GTM/heyreach-campaign/SKILL.md → 'GTM'
81
- * Groups/GTM/heyreach.tool → 'GTM'
82
- * Groups/loose-skill/SKILL.md → null (no group folder)
83
- * KnowledgeBase/Product/… → null (not a group root)
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 group is a property SOME paths
86
- * have. Callers bucket by it; nothing requires it. An ungrouped skill is a
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 groupOfPath(repoRelativePath: string): string | null;
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;;;;;;;;;;;;;;;;GAgBG;AACH,eAAO,MAAM,UAAU,WAAW,CAAC;AAEnC;;;;;;;;;;GAUG;AACH,eAAO,MAAM,qBAAqB,cAAc,CAAC;AAEjD;;;;;;;GAOG;AACH,wBAAgB,uBAAuB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAE9D;AAED,+DAA+D;AAC/D,wBAAgB,qBAAqB,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAEjE;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,WAAW,CAAC,gBAAgB,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAOnE;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"}
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
- * ├── Groups/ ← one folder per group; each holds BOTH skills and tools
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/`); `Groups/`,
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 groups.
37
+ * Folder under the repo root that holds the plugins.
38
38
  *
39
- * Groups/<Group>/<skill>/SKILL.md a skill
40
- * Groups/<Group>/<name>.tool a tool manual
41
- * Groups/<Group>/access.md who can read/write the whole group
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
- * One folder is one group. Skills and tools live TOGETHER inside it because
44
- * they share a single access boundary: a tool a group cannot read is a skill
45
- * that group cannot run, so splitting them across two roots meant maintaining
46
- * the same permission twice and letting them drift.
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
- * A group is not a registry of unique names — it is a folder. The same
49
- * integration may exist in several groups as separate files (`Everyone/
50
- * notion.tool` and `Finance/notion.tool`), each with its own credentials and
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 GROUPS_DIR = 'Groups';
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 `Groups/` —
56
- * `Groups/personal-<user-id>/` is where a person's own skills live: created
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 group-creation endpoint refuses names carrying the
63
- * prefix — so a regular group can never squat on someone's personal folder.
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 PERSONAL_GROUP_PREFIX = 'personal-';
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 personalGroupFolderName(userId) {
75
- return `${PERSONAL_GROUP_PREFIX}${branchSegment(userId)}`;
160
+ export function personalPluginFolderName(userId) {
161
+ return `${PERSONAL_PLUGIN_PREFIX}${branchSegment(userId)}`;
76
162
  }
77
- /** Whether a `Groups/` child is somebody's personal folder. */
78
- export function isPersonalGroupFolder(folderName) {
79
- return folderName.startsWith(PERSONAL_GROUP_PREFIX);
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 group a repo-root-relative path belongs to, or `null` for content that
83
- * sits outside any group.
168
+ * The plugin a repo-root-relative path belongs to, or `null` for content that
169
+ * sits outside any plugin.
84
170
  *
85
- * Groups/GTM/heyreach-campaign/SKILL.md → 'GTM'
86
- * Groups/GTM/heyreach.tool → 'GTM'
87
- * Groups/loose-skill/SKILL.md → null (no group folder)
88
- * KnowledgeBase/Product/… → null (not a group root)
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 group is a property SOME paths
91
- * have. Callers bucket by it; nothing requires it. An ungrouped skill is a
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 groupOfPath(repoRelativePath) {
180
+ export function pluginOfPath(repoRelativePath) {
95
181
  const segments = repoRelativePath.split('/').filter(Boolean);
96
- if (segments[0] !== GROUPS_DIR)
182
+ if (segments[0] !== PLUGINS_DIR)
97
183
  return null;
98
- // Needs a segment for the group AND at least one below it, otherwise
99
- // `Groups/GTM` (the folder itself) would report itself as being in a group,
100
- // and a loose `Groups/slack.tool` would report a group named "slack.tool".
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;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,CAAC,MAAM,UAAU,GAAG,QAAQ,CAAC;AAEnC;;;;;;;;;;GAUG;AACH,MAAM,CAAC,MAAM,qBAAqB,GAAG,WAAW,CAAC;AAEjD;;;;;;;GAOG;AACH,MAAM,UAAU,uBAAuB,CAAC,MAAc;IACpD,OAAO,GAAG,qBAAqB,GAAG,aAAa,CAAC,MAAM,CAAC,EAAE,CAAC;AAC5D,CAAC;AAED,+DAA+D;AAC/D,MAAM,UAAU,qBAAqB,CAAC,UAAkB;IACtD,OAAO,UAAU,CAAC,UAAU,CAAC,qBAAqB,CAAC,CAAC;AACtD,CAAC;AAED;;;;;;;;;;;;GAYG;AACH,MAAM,UAAU,WAAW,CAAC,gBAAwB;IAClD,MAAM,QAAQ,GAAG,gBAAgB,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;IAC7D,IAAI,QAAQ,CAAC,CAAC,CAAC,KAAK,UAAU;QAAE,OAAO,IAAI,CAAC;IAC5C,qEAAqE;IACrE,4EAA4E;IAC5E,2EAA2E;IAC3E,OAAO,QAAQ,CAAC,MAAM,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;AAC7D,CAAC;AAED;;;;GAIG;AACH,MAAM,CAAC,MAAM,QAAQ,GAAG,MAAM,CAAC;AAE/B,0GAA0G;AAC1G,MAAM,CAAC,MAAM,UAAU,GAAG,QAAQ,CAAC;AAEnC,6GAA6G;AAC7G,MAAM,CAAC,MAAM,aAAa,GAAG,WAAW,CAAC;AAEzC;;;GAGG;AACH,MAAM,CAAC,MAAM,cAAc,GAAsB,CAAC,kBAAkB,EAAE,QAAQ,CAAC,CAAC;AAEhF,gFAAgF;AAChF,MAAM,CAAC,MAAM,aAAa,GAAG,WAAW,CAAC;AAEzC,qFAAqF;AACrF,MAAM,CAAC,MAAM,YAAY,GAAG,WAAW,CAAC;AAExC,+EAA+E;AAC/E,MAAM,CAAC,MAAM,gBAAgB,GAAG,IAAI,GAAG,CAAC,CAAC,aAAa,EAAE,YAAY,CAAC,CAAC,CAAC;AAUvE,8EAA8E;AAC9E,+EAA+E;AAC/E,2EAA2E;AAC3E,uEAAuE"}
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.7.5",
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 (group provisioning: any signed-in user may claim an
124
- * unused name under `Groups/`, and the seeded access.md governs
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;