@agentproto/role 0.1.0-alpha.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 +21 -0
- package/README.md +23 -0
- package/dist/chunk-U2HQWFCN.mjs +29 -0
- package/dist/chunk-U2HQWFCN.mjs.map +1 -0
- package/dist/index.d.ts +385 -0
- package/dist/index.mjs +363 -0
- package/dist/index.mjs.map +1 -0
- package/dist/manifest/index.d.ts +81 -0
- package/dist/manifest/index.mjs +28 -0
- package/dist/manifest/index.mjs.map +1 -0
- package/dist/types-CohqAgUN.d.ts +139 -0
- package/package.json +69 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 agentproto contributors
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# @agentproto/role
|
|
2
|
+
|
|
3
|
+
AIP-47 `ROLE.md` reference implementation. A single-doc markdown + frontmatter format for portable organizational roles — mission, responsibilities, capabilities, tools, KPIs, seniority, reporting line, lifecycle hooks. Sibling to AIP-25 PERSONA (face) and AIP-23 IDENTITY (substance); referenced by AIP-9 OPERATOR (`role:` field) and AIP-6 COMPANY (`roles/<slug>/ROLE.md` doctype). Roles describe what a job is — independent of who holds it (persona/identity) and which instance is hired (operator).
|
|
4
|
+
|
|
5
|
+
> **Status: 0.1.0-alpha.** Generated by `scripts/scaffold-aip.mjs` — `build()` and `validate()` bodies are TODOs.
|
|
6
|
+
|
|
7
|
+
Spec: <https://agentproto.sh/docs/aip-47>
|
|
8
|
+
|
|
9
|
+
## Usage
|
|
10
|
+
|
|
11
|
+
```ts
|
|
12
|
+
import { defineRole } from "@agentproto/role"
|
|
13
|
+
|
|
14
|
+
const x = defineRole({
|
|
15
|
+
id: "my-role",
|
|
16
|
+
description: "Short purpose.",
|
|
17
|
+
// ...
|
|
18
|
+
})
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
## License
|
|
22
|
+
|
|
23
|
+
MIT — see [LICENSE](./LICENSE).
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { createDoctype } from '@agentproto/define-doctype';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* @agentproto/role v0.1.0-alpha
|
|
6
|
+
* AIP-47 ROLE.md `defineRole` reference implementation.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
var roleFrontmatterSchema = z.object({ "schema": z.literal("role/v1").describe("Schema dispatch tag. MUST be 'role/v1' for this version of AIP-47."), "name": z.string().regex(new RegExp("^[a-z][a-z0-9-]*[a-z0-9]$")).min(2).max(64).describe("Machine identifier. Lowercase, digits, dashes. Must start with a letter, end with a letter or digit. Unique within the registry that hosts the role."), "title": z.string().min(1).max(120).describe("Human-readable display title, sentence case."), "description": z.string().min(1).max(2e3).describe("One-paragraph job description. The role's purpose, audience, and shape."), "version": z.string().regex(new RegExp("^\\d+\\.\\d+\\.\\d+(?:[-+][a-zA-Z0-9.-]+)?$")).describe("Semver. Bump on breaking change to responsibilities, KPIs, tools, or seniority."), "extends": z.string().min(1).describe("Reference to a parent ROLE. Triggers composition. Accepts any ref form in AIP-47 \xA7Reference syntax: bare slug, scoped slug (builtin/<slug>, file/<path>, db/<id>), ws:// URI, or fully-qualified URL. Path-form refs SHOULD end in 'ROLE.md'.").optional(), "department": z.string().regex(new RegExp("^[a-z][a-z0-9-]*[a-z0-9]$")).min(1).max(80).describe("Department slug. Lowercase kebab-case. Recommended values listed in AIP-47 \xA7Departments; free-form to accept domain-specific values.").optional(), "reports_to": z.string().min(1).describe("Role-to-role reporting link. Conventionally a 'ws://roles/<slug>' ref. Schema does not validate scheme; the loader resolves.").optional(), "seniority": z.enum(["intern", "junior", "mid", "senior", "lead", "principal", "executive"]).describe("Seniority level of the job. Operator instances inherit this; a promotion is re-binding the operator to a higher-seniority role."), "mission": z.string().min(1).max(2e3).describe("One-paragraph mission, markdown. The reason the role exists."), "responsibilities": z.array(z.string().min(1).max(280)).min(1).describe("Ordered imperative clauses. At least one. Lineage accumulates under 'extends' (append-and-dedupe)."), "capabilities": z.array(z.string().min(1).max(200)).refine((arr) => arr.every((item, i) => arr.indexOf(item) == i), { message: "All items must be unique!" }).describe("Competences this role is expected to have. Append-and-dedupe across 'extends'.").default([]), "tools": z.array(z.string().min(1)).refine((arr) => arr.every((item, i) => arr.indexOf(item) == i), { message: "All items must be unique!" }).describe("AIP-14 tool refs the role declares as intended. Append-and-dedupe across 'extends'. Governance (AIP-7) gates effect.").default([]), "skills": z.array(z.string().min(1)).refine((arr) => arr.every((item, i) => arr.indexOf(item) == i), { message: "All items must be unique!" }).describe("AIP-3 skill refs the role expects to load. Append-and-dedupe across 'extends'.").default([]), "kpis": z.array(z.string().min(1).max(120)).refine((arr) => arr.every((item, i) => arr.indexOf(item) == i), { message: "All items must be unique!" }).describe("Scorer slugs (forward AIP) \u2014 KPIs evaluated against operators in this role. Append-and-dedupe across 'extends'.").default([]), "strengths": z.array(z.string().min(1).max(200)).refine((arr) => arr.every((item, i) => arr.indexOf(item) == i), { message: "All items must be unique!" }).describe("Job-side strengths in prose. Append-and-dedupe across 'extends'.").default([]), "antiPatterns": z.array(z.string().min(1).max(200)).refine((arr) => arr.every((item, i) => arr.indexOf(item) == i), { message: "All items must be unique!" }).describe("What the role explicitly does NOT do. Append-and-dedupe across 'extends'.").default([]), "onPromotion": z.string().min(1).describe("AIP-39 action ref fired on promotion INTO this role.").optional(), "onDemotion": z.string().min(1).describe("AIP-39 action ref fired on demotion OUT of this role.").optional(), "onAssign": z.string().min(1).describe("AIP-39 action ref fired on first assignment of this role.").optional(), "appliesTo": z.array(z.string().min(1)).refine((arr) => arr.every((item, i) => arr.indexOf(item) == i), { message: "All items must be unique!" }).describe("Cross-AIP bindings \u2014 restrict the role to specific operators. Local-only under 'extends' (NOT inherited).").default([]), "defaultPersona": z.string().min(1).describe("AIP-25 PERSONA ref recommended for operators adopting this role. Advisory; the operator's own 'persona' field overrides.").optional(), "defaultIdentity": z.string().min(1).describe("AIP-23 IDENTITY ref recommended for operators adopting this role. Advisory; the operator's own 'identity' field overrides.").optional(), "defaultPolicy": z.string().min(1).describe("AIP-38 POLICY ref recommended for operators adopting this role. ADVISORY ONLY \u2014 role declares intent, policy decides effect. The runtime MUST NOT apply defaultPolicy to an operator without the operator's own 'policy:' field or a governance signature attesting the binding. See AIP-47 \xA7Role vs Policy vs Governance.").optional(), "knowledge": z.object({ "packs": z.array(z.string().min(1)).refine((arr) => arr.every((item, i) => arr.indexOf(item) == i), { message: "All items must be unique!" }).describe("AIP-10 knowledge-pack refs this role mounts as its generic corpus floor. The host resolves each ref to a pack and mounts it read-only UNDER the operator's own editable corpus (the host overlays them). Append-and-dedupe across 'extends'. Absent = the host's convention (e.g. a pack named after the role slug). Operator-level packs layer ABOVE these.").default([]) }).strict().describe("Generic knowledge this role consults \u2014 AIP-10 corpus packs mounted read-only as a floor beneath the operator's own corpus. Distinct from 'skills' (what the role knows how to DO): knowledge is what it CONSULTS. The host unions these with any operator-level packs.").optional(), "tags": z.array(z.string().regex(new RegExp("^[a-z][a-z0-9-]*[a-z0-9]$"))).refine((arr) => arr.every((item, i) => arr.indexOf(item) == i), { message: "All items must be unique!" }).describe("Catalog tags. Lowercase kebab-case. Append-and-dedupe across 'extends'.").default([]), "metadata": z.record(z.string(), z.any()).describe("Vendor extensions, namespaced under '<vendor>'. Hosts MUST tolerate unknown vendor namespaces; they MUST NOT honour metadata that overrides AIP-defined fields.").default({}) }).strict().describe("Validates the YAML frontmatter portion of an AIP-47 ROLE.md manifest. Single-doc, no oneOf \u2014 every role is the same shape. The body is markdown and not validated by this schema.");
|
|
10
|
+
var defineRole = createDoctype({
|
|
11
|
+
aip: 47,
|
|
12
|
+
name: "role",
|
|
13
|
+
readIdentity: (def) => def.name,
|
|
14
|
+
validate(def) {
|
|
15
|
+
const result = roleFrontmatterSchema.safeParse(def);
|
|
16
|
+
if (!result.success) {
|
|
17
|
+
throw new Error(
|
|
18
|
+
`defineRole (AIP-47): ${result.error.issues.map((i) => `${i.path.join(".")}: ${i.message}`).join("; ")}`
|
|
19
|
+
);
|
|
20
|
+
}
|
|
21
|
+
},
|
|
22
|
+
build(def) {
|
|
23
|
+
return { ...def };
|
|
24
|
+
}
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
export { defineRole, roleFrontmatterSchema };
|
|
28
|
+
//# sourceMappingURL=chunk-U2HQWFCN.mjs.map
|
|
29
|
+
//# sourceMappingURL=chunk-U2HQWFCN.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/schema.ts","../src/define-role.ts"],"names":[],"mappings":"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","file":"chunk-U2HQWFCN.mjs","sourcesContent":["/**\n * AIP-47 ROLE.md frontmatter zod schema.\n *\n * Generated from `resources/aip-47/draft/ROLE.schema.json` via\n * json-schema-to-zod. Imported by both `define-role.ts` (TS path\n * validation) and `manifest/index.ts` (.md path validation) so every\n * field-level constraint runs in both authoring paths from a single\n * source of truth — re-run scaffold-aip to refresh after spec changes.\n *\n * Cross-field rules (if/then/allOf in JSON Schema) don't translate\n * cleanly and live in `define-role.ts`'s `validate(def)` instead.\n */\n\nimport { z } from \"zod\"\n\nexport const roleFrontmatterSchema = z.object({ \"schema\": z.literal(\"role/v1\").describe(\"Schema dispatch tag. MUST be 'role/v1' for this version of AIP-47.\"), \"name\": z.string().regex(new RegExp(\"^[a-z][a-z0-9-]*[a-z0-9]$\")).min(2).max(64).describe(\"Machine identifier. Lowercase, digits, dashes. Must start with a letter, end with a letter or digit. Unique within the registry that hosts the role.\"), \"title\": z.string().min(1).max(120).describe(\"Human-readable display title, sentence case.\"), \"description\": z.string().min(1).max(2000).describe(\"One-paragraph job description. The role's purpose, audience, and shape.\"), \"version\": z.string().regex(new RegExp(\"^\\\\d+\\\\.\\\\d+\\\\.\\\\d+(?:[-+][a-zA-Z0-9.-]+)?$\")).describe(\"Semver. Bump on breaking change to responsibilities, KPIs, tools, or seniority.\"), \"extends\": z.string().min(1).describe(\"Reference to a parent ROLE. Triggers composition. Accepts any ref form in AIP-47 §Reference syntax: bare slug, scoped slug (builtin/<slug>, file/<path>, db/<id>), ws:// URI, or fully-qualified URL. Path-form refs SHOULD end in 'ROLE.md'.\").optional(), \"department\": z.string().regex(new RegExp(\"^[a-z][a-z0-9-]*[a-z0-9]$\")).min(1).max(80).describe(\"Department slug. Lowercase kebab-case. Recommended values listed in AIP-47 §Departments; free-form to accept domain-specific values.\").optional(), \"reports_to\": z.string().min(1).describe(\"Role-to-role reporting link. Conventionally a 'ws://roles/<slug>' ref. Schema does not validate scheme; the loader resolves.\").optional(), \"seniority\": z.enum([\"intern\",\"junior\",\"mid\",\"senior\",\"lead\",\"principal\",\"executive\"]).describe(\"Seniority level of the job. Operator instances inherit this; a promotion is re-binding the operator to a higher-seniority role.\"), \"mission\": z.string().min(1).max(2000).describe(\"One-paragraph mission, markdown. The reason the role exists.\"), \"responsibilities\": z.array(z.string().min(1).max(280)).min(1).describe(\"Ordered imperative clauses. At least one. Lineage accumulates under 'extends' (append-and-dedupe).\"), \"capabilities\": z.array(z.string().min(1).max(200)).refine((arr) => arr.every((item, i) => arr.indexOf(item) == i), { message: \"All items must be unique!\" }).describe(\"Competences this role is expected to have. Append-and-dedupe across 'extends'.\").default([] as never), \"tools\": z.array(z.string().min(1)).refine((arr) => arr.every((item, i) => arr.indexOf(item) == i), { message: \"All items must be unique!\" }).describe(\"AIP-14 tool refs the role declares as intended. Append-and-dedupe across 'extends'. Governance (AIP-7) gates effect.\").default([] as never), \"skills\": z.array(z.string().min(1)).refine((arr) => arr.every((item, i) => arr.indexOf(item) == i), { message: \"All items must be unique!\" }).describe(\"AIP-3 skill refs the role expects to load. Append-and-dedupe across 'extends'.\").default([] as never), \"kpis\": z.array(z.string().min(1).max(120)).refine((arr) => arr.every((item, i) => arr.indexOf(item) == i), { message: \"All items must be unique!\" }).describe(\"Scorer slugs (forward AIP) — KPIs evaluated against operators in this role. Append-and-dedupe across 'extends'.\").default([] as never), \"strengths\": z.array(z.string().min(1).max(200)).refine((arr) => arr.every((item, i) => arr.indexOf(item) == i), { message: \"All items must be unique!\" }).describe(\"Job-side strengths in prose. Append-and-dedupe across 'extends'.\").default([] as never), \"antiPatterns\": z.array(z.string().min(1).max(200)).refine((arr) => arr.every((item, i) => arr.indexOf(item) == i), { message: \"All items must be unique!\" }).describe(\"What the role explicitly does NOT do. Append-and-dedupe across 'extends'.\").default([] as never), \"onPromotion\": z.string().min(1).describe(\"AIP-39 action ref fired on promotion INTO this role.\").optional(), \"onDemotion\": z.string().min(1).describe(\"AIP-39 action ref fired on demotion OUT of this role.\").optional(), \"onAssign\": z.string().min(1).describe(\"AIP-39 action ref fired on first assignment of this role.\").optional(), \"appliesTo\": z.array(z.string().min(1)).refine((arr) => arr.every((item, i) => arr.indexOf(item) == i), { message: \"All items must be unique!\" }).describe(\"Cross-AIP bindings — restrict the role to specific operators. Local-only under 'extends' (NOT inherited).\").default([] as never), \"defaultPersona\": z.string().min(1).describe(\"AIP-25 PERSONA ref recommended for operators adopting this role. Advisory; the operator's own 'persona' field overrides.\").optional(), \"defaultIdentity\": z.string().min(1).describe(\"AIP-23 IDENTITY ref recommended for operators adopting this role. Advisory; the operator's own 'identity' field overrides.\").optional(), \"defaultPolicy\": z.string().min(1).describe(\"AIP-38 POLICY ref recommended for operators adopting this role. ADVISORY ONLY — role declares intent, policy decides effect. The runtime MUST NOT apply defaultPolicy to an operator without the operator's own 'policy:' field or a governance signature attesting the binding. See AIP-47 §Role vs Policy vs Governance.\").optional(), \"knowledge\": z.object({ \"packs\": z.array(z.string().min(1)).refine((arr) => arr.every((item, i) => arr.indexOf(item) == i), { message: \"All items must be unique!\" }).describe(\"AIP-10 knowledge-pack refs this role mounts as its generic corpus floor. The host resolves each ref to a pack and mounts it read-only UNDER the operator's own editable corpus (the host overlays them). Append-and-dedupe across 'extends'. Absent = the host's convention (e.g. a pack named after the role slug). Operator-level packs layer ABOVE these.\").default([] as never) }).strict().describe(\"Generic knowledge this role consults — AIP-10 corpus packs mounted read-only as a floor beneath the operator's own corpus. Distinct from 'skills' (what the role knows how to DO): knowledge is what it CONSULTS. The host unions these with any operator-level packs.\").optional(), \"tags\": z.array(z.string().regex(new RegExp(\"^[a-z][a-z0-9-]*[a-z0-9]$\"))).refine((arr) => arr.every((item, i) => arr.indexOf(item) == i), { message: \"All items must be unique!\" }).describe(\"Catalog tags. Lowercase kebab-case. Append-and-dedupe across 'extends'.\").default([] as never), \"metadata\": z.record(z.string(), z.any()).describe(\"Vendor extensions, namespaced under '<vendor>'. Hosts MUST tolerate unknown vendor namespaces; they MUST NOT honour metadata that overrides AIP-defined fields.\").default({} as never) }).strict().describe(\"Validates the YAML frontmatter portion of an AIP-47 ROLE.md manifest. Single-doc, no oneOf — every role is the same shape. The body is markdown and not validated by this schema.\")\n\nexport type RoleFrontmatter = z.infer<typeof roleFrontmatterSchema>\n","import { createDoctype } from \"@agentproto/define-doctype\"\nimport { roleFrontmatterSchema } from \"./schema.js\"\nimport type { RoleDefinition, RoleHandle } from \"./types.js\"\n\n/**\n * AIP-47 reference implementation of `defineRole`.\n *\n * Built on `createDoctype` so the cross-AIP invariants (id pattern,\n * description length, top-level freeze, \"defineRole (AIP-47): …\"\n * error prefix) run uniformly with every other AIP defineX.\n *\n * Field-level validation runs the schema-derived zod from\n * `./schema.ts` against the input. Same source of truth as the .md\n * path uses (`parseRoleManifest`), so a malformed TS-authored\n * definition fails with the same diagnostic as a malformed manifest.\n * Cross-field rules go in `validate(def)` after the zod check.\n *\n * Identity / description extractors detected from the JSON Schema:\n * readIdentity: def.name\n * readDescription: def.description.\n */\nexport const defineRole = createDoctype<RoleDefinition, RoleHandle>({\n aip: 47,\n name: \"role\",\n readIdentity: (def) => def.name,\n validate(def) {\n const result = roleFrontmatterSchema.safeParse(def)\n if (!result.success) {\n throw new Error(\n `defineRole (AIP-47): ${result.error.issues\n .map((i) => `${i.path.join(\".\")}: ${i.message}`)\n .join(\"; \")}`,\n )\n }\n // TODO: spec-47-specific cross-field rules (if/then/allOf in\n // the JSON Schema) — those don't translate to zod cleanly and\n // belong here. See @agentproto/operator's autonomy=gated rule.\n },\n build(def) {\n // Default build: spread the validated definition into a fresh object.\n // Hand-tune for nested freezing (Object.freeze on arrays/objects) and\n // for fields that need defaults applied — see @agentproto/operator\n // for a reference shape.\n return { ...def } as RoleHandle\n },\n})\n"]}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,385 @@
|
|
|
1
|
+
import { R as RoleDefinition, a as RoleHandle } from './types-CohqAgUN.js';
|
|
2
|
+
import { Registry } from '@agentproto/registry';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* AIP-47 reference implementation of `defineRole`.
|
|
6
|
+
*
|
|
7
|
+
* Built on `createDoctype` so the cross-AIP invariants (id pattern,
|
|
8
|
+
* description length, top-level freeze, "defineRole (AIP-47): …"
|
|
9
|
+
* error prefix) run uniformly with every other AIP defineX.
|
|
10
|
+
*
|
|
11
|
+
* Field-level validation runs the schema-derived zod from
|
|
12
|
+
* `./schema.ts` against the input. Same source of truth as the .md
|
|
13
|
+
* path uses (`parseRoleManifest`), so a malformed TS-authored
|
|
14
|
+
* definition fails with the same diagnostic as a malformed manifest.
|
|
15
|
+
* Cross-field rules go in `validate(def)` after the zod check.
|
|
16
|
+
*
|
|
17
|
+
* Identity / description extractors detected from the JSON Schema:
|
|
18
|
+
* readIdentity: def.name
|
|
19
|
+
* readDescription: def.description.
|
|
20
|
+
*/
|
|
21
|
+
declare const defineRole: (def: RoleDefinition) => Readonly<RoleDefinition>;
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* AIP-47 strategic merge for role inheritance.
|
|
25
|
+
*
|
|
26
|
+
* Pure function: parent + child → merged. No I/O.
|
|
27
|
+
*
|
|
28
|
+
* Merge strategy per AIP-47 §Merge strategy table:
|
|
29
|
+
* - scalars (name/title/description/version/department/reports_to/
|
|
30
|
+
* seniority/mission/onPromotion/onDemotion/onAssign/defaultPersona/
|
|
31
|
+
* defaultIdentity/defaultPolicy): override (child wins)
|
|
32
|
+
* - list-strategy fields (responsibilities/capabilities/tools/skills/
|
|
33
|
+
* kpis/strengths/antiPatterns/tags): append-and-dedupe, OR
|
|
34
|
+
* `{ add, remove }` patch form
|
|
35
|
+
* - extends + appliesTo: local-only (never inherited)
|
|
36
|
+
* - metadata: deep-merge
|
|
37
|
+
*
|
|
38
|
+
* Body merge is handled by `mergeBodies` (separate concern — handles
|
|
39
|
+
* `metadata['aip-47'].bodyMerge` switch).
|
|
40
|
+
*/
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* A child role's input may carry a list patch on a list-strategy field
|
|
44
|
+
* instead of a plain list. The patch is applied against the inherited
|
|
45
|
+
* accumulator at merge time.
|
|
46
|
+
*
|
|
47
|
+
* See AIP-47 §Merge strategy →
|
|
48
|
+
* "Explicit remove of inherited entries".
|
|
49
|
+
*/
|
|
50
|
+
type ListPatch<T> = readonly T[] | {
|
|
51
|
+
add?: readonly T[];
|
|
52
|
+
remove?: readonly T[];
|
|
53
|
+
};
|
|
54
|
+
/**
|
|
55
|
+
* The set of list-strategy field names per AIP-47 §Merge strategy.
|
|
56
|
+
* Every entry here is an `append-and-dedupe` field that admits the
|
|
57
|
+
* `{ add, remove }` patch form.
|
|
58
|
+
*/
|
|
59
|
+
declare const LIST_FIELDS: readonly ["responsibilities", "capabilities", "tools", "skills", "kpis", "strengths", "antiPatterns", "tags"];
|
|
60
|
+
type ListField = (typeof LIST_FIELDS)[number];
|
|
61
|
+
/**
|
|
62
|
+
* The set of fields that are NEVER inherited from a parent role.
|
|
63
|
+
* Used by the resolver to strip them before merging into the
|
|
64
|
+
* accumulator.
|
|
65
|
+
*/
|
|
66
|
+
declare const LOCAL_ONLY_FIELDS: readonly ["extends", "appliesTo"];
|
|
67
|
+
/**
|
|
68
|
+
* A child role's raw input. Same shape as `RoleDefinition` except
|
|
69
|
+
* that list-strategy fields admit the `{ add, remove }` patch form.
|
|
70
|
+
* The merger normalises patches into plain lists; the resolved output
|
|
71
|
+
* is always `RoleHandle` (plain lists only).
|
|
72
|
+
*/
|
|
73
|
+
type RoleChildInput = Omit<Partial<RoleDefinition>, ListField> & {
|
|
74
|
+
[K in ListField]?: K extends "responsibilities" ? ListPatch<string> | [string, ...string[]] : ListPatch<string>;
|
|
75
|
+
};
|
|
76
|
+
type MergeWarning = {
|
|
77
|
+
code: "role_merge_form_conflict";
|
|
78
|
+
message: string;
|
|
79
|
+
field: ListField;
|
|
80
|
+
} | {
|
|
81
|
+
code: "role_merge_remove_missed";
|
|
82
|
+
message: string;
|
|
83
|
+
field: ListField;
|
|
84
|
+
missing: string;
|
|
85
|
+
};
|
|
86
|
+
interface MergeResult {
|
|
87
|
+
/** The merged role frontmatter, always plain lists. */
|
|
88
|
+
role: RoleHandle;
|
|
89
|
+
/** Diagnostics emitted during merge. */
|
|
90
|
+
warnings: MergeWarning[];
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Strategic-merge a parent role (already resolved, plain handle) with
|
|
94
|
+
* a child role's raw input. Returns a fully-typed `RoleHandle` and any
|
|
95
|
+
* merge-time warnings.
|
|
96
|
+
*
|
|
97
|
+
* The merger does NOT validate against the canonical schema — that is
|
|
98
|
+
* the caller's responsibility (typically `resolveRole` validates the
|
|
99
|
+
* final merged role at the end of chain walking).
|
|
100
|
+
*
|
|
101
|
+
* Override fields (scalars + non-list maps + single bindings) follow
|
|
102
|
+
* `child wins if defined`. Local-only fields are NEVER inherited from
|
|
103
|
+
* the parent: the resolved role carries the local-only fields of the
|
|
104
|
+
* leaf (current) child, never of any ancestor.
|
|
105
|
+
*/
|
|
106
|
+
declare function mergeRoles(parent: RoleHandle, child: RoleChildInput): MergeResult;
|
|
107
|
+
/**
|
|
108
|
+
* Body merge for ROLE.md body markdown. The parent's body comes from
|
|
109
|
+
* the resolved parent manifest; the child's body comes from the
|
|
110
|
+
* current frontmatter parse. The default is `append-with-separator`;
|
|
111
|
+
* `metadata['aip-47'].bodyMerge === 'replace'` switches to replace.
|
|
112
|
+
*/
|
|
113
|
+
declare function mergeBodies(parentBody: string | undefined, childBody: string | undefined, mode?: "append-with-separator" | "replace"): string;
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* AIP-47 source loader interface.
|
|
117
|
+
*
|
|
118
|
+
* A `RoleSource` resolves a role ref (slug, ws:// ref, file path, http
|
|
119
|
+
* URL) to a raw manifest (frontmatter + body). The resolver assembles
|
|
120
|
+
* the `extends` chain by querying a list of sources in order, first
|
|
121
|
+
* match wins.
|
|
122
|
+
*
|
|
123
|
+
* The interface is intentionally minimal:
|
|
124
|
+
* - `scheme` — the scheme this source claims (used by the chain to
|
|
125
|
+
* dispatch by `<scheme>://...` refs)
|
|
126
|
+
* - `load(ref)` — return the parsed manifest, or `null` if not found
|
|
127
|
+
*
|
|
128
|
+
* Sources MUST enforce their own visibility / authorisation. The
|
|
129
|
+
* resolver does NOT inspect `metadata.guilde.visibility` — it trusts
|
|
130
|
+
* the source to only return manifests the caller may see.
|
|
131
|
+
*/
|
|
132
|
+
|
|
133
|
+
/**
|
|
134
|
+
* The raw manifest a source returns. Frontmatter is the parsed
|
|
135
|
+
* (NOT yet schema-validated) object; body is the markdown body
|
|
136
|
+
* verbatim. The resolver validates and merges; the source loads.
|
|
137
|
+
*/
|
|
138
|
+
interface RoleManifestRaw {
|
|
139
|
+
/** The role ref this manifest resolves (canonical / source-scoped). */
|
|
140
|
+
readonly ref: string;
|
|
141
|
+
/** Parsed YAML frontmatter — shape is per AIP-47 (may include patches). */
|
|
142
|
+
readonly frontmatter: unknown;
|
|
143
|
+
/** Markdown body — verbatim. */
|
|
144
|
+
readonly body: string;
|
|
145
|
+
/**
|
|
146
|
+
* The scheme that loaded this manifest. Useful for the resolution
|
|
147
|
+
* chain debug surface ("`role:builtin → role:file → role:db`").
|
|
148
|
+
*/
|
|
149
|
+
readonly scheme: string;
|
|
150
|
+
}
|
|
151
|
+
/**
|
|
152
|
+
* A role ref that has already been narrowed to a single source. The
|
|
153
|
+
* resolver MAY normalise bare slugs to a scoped form ("`builtin/seo-
|
|
154
|
+
* specialist`") when it walks the chain.
|
|
155
|
+
*/
|
|
156
|
+
type RoleRef = string;
|
|
157
|
+
interface RoleSource {
|
|
158
|
+
/**
|
|
159
|
+
* The scheme this source serves. Conventional values:
|
|
160
|
+
* - `builtin` — TS registry shipped by a runtime
|
|
161
|
+
* - `file` — file-system layout per AIP-47 §File location
|
|
162
|
+
* - `db` — a database table (typically the runtime's role
|
|
163
|
+
* table; see resources/aip-47/draft/ADAPTER.md)
|
|
164
|
+
* - `http` — remote registry (optional in v1)
|
|
165
|
+
*
|
|
166
|
+
* Custom schemes are welcome — the resolver dispatches on the
|
|
167
|
+
* `<scheme>://` prefix of a ref.
|
|
168
|
+
*/
|
|
169
|
+
readonly scheme: string;
|
|
170
|
+
/**
|
|
171
|
+
* Resolve a ref to a raw manifest. Returns `null` if the source
|
|
172
|
+
* does not have this ref — the resolver will continue down the
|
|
173
|
+
* chain. Throws on transport / corruption errors.
|
|
174
|
+
*/
|
|
175
|
+
load(ref: RoleRef): Promise<RoleManifestRaw | null>;
|
|
176
|
+
/**
|
|
177
|
+
* Enumerate ref ids this source can resolve. Optional — the
|
|
178
|
+
* resolver does not require enumeration to work, but UI surfaces
|
|
179
|
+
* (catalog browsing, "hire" flows) consume this.
|
|
180
|
+
*/
|
|
181
|
+
list?(): Promise<readonly RoleRef[]>;
|
|
182
|
+
}
|
|
183
|
+
/**
|
|
184
|
+
* Helper: a `BuiltinRoleSource` ships a TS map of `slug → RoleHandle`
|
|
185
|
+
* (already-resolved, already-validated). Loaded directly from a
|
|
186
|
+
* runtime package like `@agentproto/role-catalog`.
|
|
187
|
+
*/
|
|
188
|
+
interface BuiltinRoleEntry {
|
|
189
|
+
readonly slug: string;
|
|
190
|
+
readonly handle: RoleHandle;
|
|
191
|
+
readonly body?: string;
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
/**
|
|
195
|
+
* AIP-47 role resolver — walks the `extends` chain, merges, validates.
|
|
196
|
+
*
|
|
197
|
+
* Pipeline:
|
|
198
|
+
* 1. dispatch the ref through the source chain — first match wins
|
|
199
|
+
* 2. if the loaded manifest has `extends`, recurse to resolve the
|
|
200
|
+
* parent (cycle-detected, depth-capped, warnings on missing)
|
|
201
|
+
* 3. apply strategic merge (parent + child) per AIP-47 §Merge
|
|
202
|
+
* strategy via `merge.ts`
|
|
203
|
+
* 4. validate the merged frontmatter against the canonical zod
|
|
204
|
+
* schema (defensive — sources MAY ship raw / patch-form input)
|
|
205
|
+
* 5. return `{ role, body, chain, warnings }`
|
|
206
|
+
*
|
|
207
|
+
* Cycle detection: tracks visited refs during chain walk.
|
|
208
|
+
* Depth limit: max 8 (per spec recommendation).
|
|
209
|
+
* Missing parent: warning, fallback to the local manifest.
|
|
210
|
+
*/
|
|
211
|
+
|
|
212
|
+
type ResolveWarning = MergeWarning | {
|
|
213
|
+
code: "role_unresolvable";
|
|
214
|
+
message: string;
|
|
215
|
+
ref: string;
|
|
216
|
+
} | {
|
|
217
|
+
code: "role_extends_cycle";
|
|
218
|
+
message: string;
|
|
219
|
+
cycle: readonly string[];
|
|
220
|
+
} | {
|
|
221
|
+
code: "role_extends_depth_exceeded";
|
|
222
|
+
message: string;
|
|
223
|
+
depth: number;
|
|
224
|
+
ref: string;
|
|
225
|
+
} | {
|
|
226
|
+
code: "role_extends_missing";
|
|
227
|
+
message: string;
|
|
228
|
+
parent: string;
|
|
229
|
+
} | {
|
|
230
|
+
code: "role_validation_failed";
|
|
231
|
+
message: string;
|
|
232
|
+
ref: string;
|
|
233
|
+
issues: readonly string[];
|
|
234
|
+
};
|
|
235
|
+
interface ResolveOptions {
|
|
236
|
+
/** Source chain — consulted in order, first match wins. */
|
|
237
|
+
readonly sources: readonly RoleSource[];
|
|
238
|
+
/** Maximum `extends` chain depth. Default 8. */
|
|
239
|
+
readonly maxDepth?: number;
|
|
240
|
+
}
|
|
241
|
+
interface ResolvedRole {
|
|
242
|
+
/** Effective role after `extends`-chain merge. Always plain lists. */
|
|
243
|
+
readonly role: RoleHandle;
|
|
244
|
+
/** Merged body markdown — parent appended with `\n\n---\n\n` separator. */
|
|
245
|
+
readonly body: string;
|
|
246
|
+
/**
|
|
247
|
+
* Ordered list of refs walked, from leaf to root.
|
|
248
|
+
* `chain[0]` is the requested ref; the last entry is the root parent.
|
|
249
|
+
*/
|
|
250
|
+
readonly chain: readonly string[];
|
|
251
|
+
/** Diagnostics emitted during resolution + merge. */
|
|
252
|
+
readonly warnings: readonly ResolveWarning[];
|
|
253
|
+
}
|
|
254
|
+
/**
|
|
255
|
+
* Resolve a role ref through the source chain and merge any
|
|
256
|
+
* `extends` lineage. Throws iff the leaf ref cannot be loaded AND no
|
|
257
|
+
* partial result is recoverable (i.e. the top-level lookup fails).
|
|
258
|
+
*
|
|
259
|
+
* Intermediate failures (cycle, depth, missing parent) MUST NOT
|
|
260
|
+
* throw — they emit warnings and the resolver falls back to the
|
|
261
|
+
* local manifest. This is the AIP-47 spec contract:
|
|
262
|
+
*
|
|
263
|
+
* "Treat depth overflow and cycle detection as warnings, not
|
|
264
|
+
* errors. A role whose chain is malformed MUST still load — the
|
|
265
|
+
* runtime falls back to the local manifest only."
|
|
266
|
+
*/
|
|
267
|
+
declare function resolveRole(ref: RoleRef, opts: ResolveOptions): Promise<ResolvedRole>;
|
|
268
|
+
|
|
269
|
+
/**
|
|
270
|
+
* AIP-47 built-in role source.
|
|
271
|
+
*
|
|
272
|
+
* Wraps an AIP-43 `@agentproto/registry` instance keyed by role slug.
|
|
273
|
+
* Intended primarily for runtime-shipped catalogues
|
|
274
|
+
* (`@agentproto/role-catalog`, vendor-specific registries) where the
|
|
275
|
+
* roles are authored in TS and validated at module load time. The
|
|
276
|
+
* registry is mutable post-construction — `register` / `unregister` /
|
|
277
|
+
* `replace` let downstream apps extend the catalogue without forking
|
|
278
|
+
* the OSS package.
|
|
279
|
+
*
|
|
280
|
+
* Refs are matched in three forms:
|
|
281
|
+
* - bare slug: `seo-specialist`
|
|
282
|
+
* - scoped slug: `builtin/seo-specialist`
|
|
283
|
+
* - ws:// ref: `ws://roles/seo-specialist`
|
|
284
|
+
*
|
|
285
|
+
* All three resolve to the same entry. The `scheme` is `builtin`.
|
|
286
|
+
*/
|
|
287
|
+
|
|
288
|
+
declare class BuiltinRoleSource implements RoleSource {
|
|
289
|
+
readonly scheme = "builtin";
|
|
290
|
+
/**
|
|
291
|
+
* Underlying AIP-43 registry. Exposed for advanced consumers that
|
|
292
|
+
* want to use `lookup(predicate)`, `entries()`, or other registry
|
|
293
|
+
* primitives. The common operations are mirrored on the source
|
|
294
|
+
* itself for ergonomics.
|
|
295
|
+
*/
|
|
296
|
+
readonly registry: Registry<BuiltinRoleEntry>;
|
|
297
|
+
constructor(entries?: Iterable<BuiltinRoleEntry>);
|
|
298
|
+
load(ref: RoleRef): Promise<RoleManifestRaw | null>;
|
|
299
|
+
list(): Promise<readonly RoleRef[]>;
|
|
300
|
+
/**
|
|
301
|
+
* Register a new builtin entry. Throws `RegistryDuplicateError`
|
|
302
|
+
* if a handle with the same slug is already registered — use
|
|
303
|
+
* `replace` to swap atomically when a hot-reload picks up a
|
|
304
|
+
* redefined role.
|
|
305
|
+
*/
|
|
306
|
+
register(entry: BuiltinRoleEntry): void;
|
|
307
|
+
/**
|
|
308
|
+
* Replace an existing entry. Throws `RegistryNotFoundError` if no
|
|
309
|
+
* entry exists at the resolved slug. Use `register` for new slugs.
|
|
310
|
+
*/
|
|
311
|
+
replace(entry: BuiltinRoleEntry): void;
|
|
312
|
+
/**
|
|
313
|
+
* Remove a slug from the registry. Returns true if an entry was
|
|
314
|
+
* removed. Use sparingly — the registry is intended to be
|
|
315
|
+
* boot-time-stable.
|
|
316
|
+
*/
|
|
317
|
+
unregister(slug: string): boolean;
|
|
318
|
+
/** Returns true if the slug (any ref form) is registered. */
|
|
319
|
+
has(slug: string): boolean;
|
|
320
|
+
/** Number of entries currently registered. */
|
|
321
|
+
count(): number;
|
|
322
|
+
/**
|
|
323
|
+
* Filter entries by an arbitrary predicate. Runs in registration
|
|
324
|
+
* order. Useful for capability lookups like "every role with
|
|
325
|
+
* `metadata.aip-47.audience === 'ai-worker'`".
|
|
326
|
+
*/
|
|
327
|
+
lookup(predicate: (entry: BuiltinRoleEntry) => boolean): readonly BuiltinRoleEntry[];
|
|
328
|
+
}
|
|
329
|
+
/**
|
|
330
|
+
* Convenience: assemble a `BuiltinRoleSource` from a record map.
|
|
331
|
+
* Each entry's key becomes the slug.
|
|
332
|
+
*/
|
|
333
|
+
declare function builtinSourceFromRecord(record: Record<string, Omit<BuiltinRoleEntry, "slug">>): BuiltinRoleSource;
|
|
334
|
+
|
|
335
|
+
/**
|
|
336
|
+
* @agentproto/role — AIP-47 ROLE.md `defineRole` reference impl.
|
|
337
|
+
*
|
|
338
|
+
* A single-doc markdown + frontmatter format for portable organizational roles — mission, responsibilities, capabilities, tools, KPIs, seniority, reporting line, lifecycle hooks. Sibling to AIP-25 PERSONA (face) and AIP-23 IDENTITY (substance); referenced by AIP-9 OPERATOR (`role:` field) and AIP-6 COMPANY (`roles/<slug>/ROLE.md` doctype). Roles describe what a job is — independent of who holds it (persona/identity) and which instance is hired (operator).
|
|
339
|
+
*
|
|
340
|
+
* Spec: https://agentproto.sh/docs/aip-47
|
|
341
|
+
*
|
|
342
|
+
* Authoring paths:
|
|
343
|
+
* - TS: `defineRole({...})` → `RoleHandle`
|
|
344
|
+
* - MD: `parseRoleManifest(src) → roleFromManifest({...})` → `RoleHandle`
|
|
345
|
+
*
|
|
346
|
+
* Resolution:
|
|
347
|
+
* - `resolveRole(ref, { sources })` walks the `extends` chain, applies
|
|
348
|
+
* strategic merge per the spec, and returns the effective `RoleHandle`
|
|
349
|
+
* plus the merged body, the resolution chain, and any warnings.
|
|
350
|
+
*
|
|
351
|
+
* Composition (advisory, never grants access):
|
|
352
|
+
* - Operators consume the resolved role via AIP-9 OPERATOR `role:`
|
|
353
|
+
* field. Effective permissions come from AIP-38 POLICY, NOT from
|
|
354
|
+
* the role — see AIP-47 §Role vs Policy vs Governance.
|
|
355
|
+
*/
|
|
356
|
+
declare const SPEC_NAME: "agentrole/v1";
|
|
357
|
+
declare const SPEC_VERSION: "1.0.0-alpha";
|
|
358
|
+
/**
|
|
359
|
+
* Seniority levels per AIP-47 §Optional fields. Const tuple exported
|
|
360
|
+
* so consumers can derive zod / openapi enum schemas from the single
|
|
361
|
+
* source of truth — keep this in sync with `ROLE.schema.json`.
|
|
362
|
+
*/
|
|
363
|
+
declare const ROLE_SENIORITIES: readonly ["intern", "junior", "mid", "senior", "lead", "principal", "executive"];
|
|
364
|
+
type RoleSeniority = (typeof ROLE_SENIORITIES)[number];
|
|
365
|
+
/**
|
|
366
|
+
* Recommended departments per AIP-47 §Departments (informative).
|
|
367
|
+
* `department` on a ROLE.md is a free string — these values are
|
|
368
|
+
* suggested for cross-runtime alignment. Runtimes that group / chart
|
|
369
|
+
* roles by department SHOULD render this list as the default
|
|
370
|
+
* taxonomy and treat any out-of-list value as a domain-specific
|
|
371
|
+
* extension (legal, R&D, clinical, …).
|
|
372
|
+
*
|
|
373
|
+
* Order is significant: the array order is the recommended display
|
|
374
|
+
* order for org charts and "hire" UIs.
|
|
375
|
+
*/
|
|
376
|
+
declare const RECOMMENDED_DEPARTMENTS: readonly ["executive", "operations", "engineering", "product", "marketing", "sales", "customer", "finance", "people"];
|
|
377
|
+
type RecommendedDepartment = (typeof RECOMMENDED_DEPARTMENTS)[number];
|
|
378
|
+
/**
|
|
379
|
+
* Human-readable label for a department slug. Falls back to a
|
|
380
|
+
* Title-Case-ified version of the slug for departments outside the
|
|
381
|
+
* recommended list (custom org taxonomies).
|
|
382
|
+
*/
|
|
383
|
+
declare function departmentLabel(slug: string): string;
|
|
384
|
+
|
|
385
|
+
export { type BuiltinRoleEntry, BuiltinRoleSource, LIST_FIELDS, LOCAL_ONLY_FIELDS, type ListField, type ListPatch, type MergeResult, type MergeWarning, RECOMMENDED_DEPARTMENTS, ROLE_SENIORITIES, type RecommendedDepartment, type ResolveOptions, type ResolveWarning, type ResolvedRole, type RoleChildInput, RoleDefinition, RoleHandle, type RoleManifestRaw, type RoleRef, type RoleSeniority, type RoleSource, SPEC_NAME, SPEC_VERSION, builtinSourceFromRecord, defineRole, departmentLabel, mergeBodies, mergeRoles, resolveRole };
|
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,363 @@
|
|
|
1
|
+
import { roleFrontmatterSchema } from './chunk-U2HQWFCN.mjs';
|
|
2
|
+
export { defineRole } from './chunk-U2HQWFCN.mjs';
|
|
3
|
+
import { createRegistry } from '@agentproto/registry';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* @agentproto/role v0.1.0-alpha
|
|
7
|
+
* AIP-47 ROLE.md `defineRole` reference implementation.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
// src/merge.ts
|
|
11
|
+
var LIST_FIELDS = [
|
|
12
|
+
"responsibilities",
|
|
13
|
+
"capabilities",
|
|
14
|
+
"tools",
|
|
15
|
+
"skills",
|
|
16
|
+
"kpis",
|
|
17
|
+
"strengths",
|
|
18
|
+
"antiPatterns",
|
|
19
|
+
"tags"
|
|
20
|
+
];
|
|
21
|
+
var LOCAL_ONLY_FIELDS = ["extends", "appliesTo"];
|
|
22
|
+
function applyListPatch(field, inherited, child) {
|
|
23
|
+
if (child === void 0) {
|
|
24
|
+
return { value: [...inherited], warnings: [] };
|
|
25
|
+
}
|
|
26
|
+
if (Array.isArray(child)) {
|
|
27
|
+
return { value: [...child], warnings: [] };
|
|
28
|
+
}
|
|
29
|
+
const warnings = [];
|
|
30
|
+
const patch = child;
|
|
31
|
+
const removeSet = new Set(patch.remove ?? []);
|
|
32
|
+
const matched = /* @__PURE__ */ new Set();
|
|
33
|
+
const filtered = inherited.filter((item) => {
|
|
34
|
+
const should = !removeSet.has(item);
|
|
35
|
+
if (!should) matched.add(item);
|
|
36
|
+
return should;
|
|
37
|
+
});
|
|
38
|
+
for (const r of removeSet) {
|
|
39
|
+
if (!matched.has(r)) {
|
|
40
|
+
warnings.push({
|
|
41
|
+
code: "role_merge_remove_missed",
|
|
42
|
+
message: `${field}: remove entry not found in inherited list`,
|
|
43
|
+
field,
|
|
44
|
+
missing: String(r)
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
const out = [...filtered];
|
|
49
|
+
for (const a of patch.add ?? []) {
|
|
50
|
+
if (!out.includes(a)) out.push(a);
|
|
51
|
+
}
|
|
52
|
+
return { value: out, warnings };
|
|
53
|
+
}
|
|
54
|
+
function deepMerge(parent, child) {
|
|
55
|
+
if (child === void 0) return parent;
|
|
56
|
+
if (typeof parent !== "object" || parent === null || Array.isArray(parent)) {
|
|
57
|
+
return child;
|
|
58
|
+
}
|
|
59
|
+
if (typeof child !== "object" || child === null || Array.isArray(child)) {
|
|
60
|
+
return child;
|
|
61
|
+
}
|
|
62
|
+
const out = { ...parent };
|
|
63
|
+
for (const [k, v] of Object.entries(child)) {
|
|
64
|
+
out[k] = deepMerge(parent[k], v);
|
|
65
|
+
}
|
|
66
|
+
return out;
|
|
67
|
+
}
|
|
68
|
+
function mergeRoles(parent, child) {
|
|
69
|
+
const warnings = [];
|
|
70
|
+
const pick = (key) => {
|
|
71
|
+
const c = child[key];
|
|
72
|
+
return c !== void 0 ? c : parent[key];
|
|
73
|
+
};
|
|
74
|
+
const lists = {};
|
|
75
|
+
for (const field of LIST_FIELDS) {
|
|
76
|
+
const inherited = field === "responsibilities" ? parent.responsibilities : parent[field] ?? [];
|
|
77
|
+
const childField = child[field];
|
|
78
|
+
const result = applyListPatch(field, inherited, childField);
|
|
79
|
+
warnings.push(...result.warnings);
|
|
80
|
+
lists[field] = result.value;
|
|
81
|
+
}
|
|
82
|
+
if (lists.responsibilities.length === 0) {
|
|
83
|
+
lists.responsibilities = [...parent.responsibilities];
|
|
84
|
+
}
|
|
85
|
+
const mergedPacks = [
|
|
86
|
+
...parent.knowledge?.packs ?? [],
|
|
87
|
+
...child.knowledge?.packs ?? []
|
|
88
|
+
].filter((p, i, a) => a.indexOf(p) === i);
|
|
89
|
+
const knowledge = parent.knowledge || child.knowledge ? { packs: mergedPacks } : void 0;
|
|
90
|
+
const merged = {
|
|
91
|
+
// Doctype identity — child wins if set.
|
|
92
|
+
schema: "role/v1",
|
|
93
|
+
name: pick("name"),
|
|
94
|
+
title: pick("title"),
|
|
95
|
+
description: pick("description"),
|
|
96
|
+
version: pick("version"),
|
|
97
|
+
seniority: pick("seniority"),
|
|
98
|
+
mission: pick("mission"),
|
|
99
|
+
// Org placement — overrides.
|
|
100
|
+
department: pick("department"),
|
|
101
|
+
reports_to: pick("reports_to"),
|
|
102
|
+
// Lifecycle hooks — overrides.
|
|
103
|
+
onPromotion: pick("onPromotion"),
|
|
104
|
+
onDemotion: pick("onDemotion"),
|
|
105
|
+
onAssign: pick("onAssign"),
|
|
106
|
+
// Single bindings — overrides.
|
|
107
|
+
defaultPersona: pick("defaultPersona"),
|
|
108
|
+
defaultIdentity: pick("defaultIdentity"),
|
|
109
|
+
defaultPolicy: pick("defaultPolicy"),
|
|
110
|
+
// Nested knowledge binding — append-and-dedupe union (computed above).
|
|
111
|
+
...knowledge ? { knowledge } : {},
|
|
112
|
+
// Local-only fields — child's value carries; parent's is dropped.
|
|
113
|
+
extends: child.extends,
|
|
114
|
+
appliesTo: child.appliesTo,
|
|
115
|
+
// List-strategy.
|
|
116
|
+
responsibilities: lists.responsibilities,
|
|
117
|
+
capabilities: lists.capabilities,
|
|
118
|
+
tools: lists.tools,
|
|
119
|
+
skills: lists.skills,
|
|
120
|
+
kpis: lists.kpis,
|
|
121
|
+
strengths: lists.strengths,
|
|
122
|
+
antiPatterns: lists.antiPatterns,
|
|
123
|
+
tags: lists.tags,
|
|
124
|
+
// Deep-merged maps.
|
|
125
|
+
metadata: deepMerge(parent.metadata ?? {}, child.metadata)
|
|
126
|
+
};
|
|
127
|
+
if (child.extends === void 0) delete merged.extends;
|
|
128
|
+
if (child.appliesTo === void 0)
|
|
129
|
+
delete merged.appliesTo;
|
|
130
|
+
return { role: merged, warnings };
|
|
131
|
+
}
|
|
132
|
+
function mergeBodies(parentBody, childBody, mode = "append-with-separator") {
|
|
133
|
+
if (!parentBody) return childBody ?? "";
|
|
134
|
+
if (!childBody) return parentBody;
|
|
135
|
+
if (mode === "replace") return childBody;
|
|
136
|
+
return `${parentBody.trimEnd()}
|
|
137
|
+
|
|
138
|
+
---
|
|
139
|
+
|
|
140
|
+
${childBody.trimStart()}`;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
// src/resolve.ts
|
|
144
|
+
var DEFAULT_MAX_DEPTH = 8;
|
|
145
|
+
async function resolveRole(ref, opts) {
|
|
146
|
+
const maxDepth = opts.maxDepth ?? DEFAULT_MAX_DEPTH;
|
|
147
|
+
const visited = /* @__PURE__ */ new Set();
|
|
148
|
+
const warnings = [];
|
|
149
|
+
const chain = [];
|
|
150
|
+
const load = async (current) => {
|
|
151
|
+
for (const src of opts.sources) {
|
|
152
|
+
const m = await src.load(current);
|
|
153
|
+
if (m !== null) return m;
|
|
154
|
+
}
|
|
155
|
+
return null;
|
|
156
|
+
};
|
|
157
|
+
const walk = async (current, depth, isParentRef) => {
|
|
158
|
+
if (depth > maxDepth) {
|
|
159
|
+
warnings.push({
|
|
160
|
+
code: "role_extends_depth_exceeded",
|
|
161
|
+
message: `extends chain depth exceeded ${maxDepth} at '${current}'`,
|
|
162
|
+
depth,
|
|
163
|
+
ref: current
|
|
164
|
+
});
|
|
165
|
+
return null;
|
|
166
|
+
}
|
|
167
|
+
if (visited.has(current)) {
|
|
168
|
+
warnings.push({
|
|
169
|
+
code: "role_extends_cycle",
|
|
170
|
+
message: `extends cycle detected at '${current}'`,
|
|
171
|
+
cycle: [...visited, current]
|
|
172
|
+
});
|
|
173
|
+
return null;
|
|
174
|
+
}
|
|
175
|
+
visited.add(current);
|
|
176
|
+
const manifest = await load(current);
|
|
177
|
+
if (!manifest) {
|
|
178
|
+
if (isParentRef) {
|
|
179
|
+
warnings.push({
|
|
180
|
+
code: "role_extends_missing",
|
|
181
|
+
message: `parent ref '${current}' did not resolve`,
|
|
182
|
+
parent: current
|
|
183
|
+
});
|
|
184
|
+
}
|
|
185
|
+
return null;
|
|
186
|
+
}
|
|
187
|
+
chain.push(manifest.ref);
|
|
188
|
+
const fm = manifest.frontmatter;
|
|
189
|
+
const extendsRef = fm.extends;
|
|
190
|
+
if (!extendsRef) {
|
|
191
|
+
return { role: fm, body: manifest.body };
|
|
192
|
+
}
|
|
193
|
+
const parent = await walk(extendsRef, depth + 1, true);
|
|
194
|
+
if (!parent) {
|
|
195
|
+
return { role: fm, body: manifest.body };
|
|
196
|
+
}
|
|
197
|
+
const merged = mergeRoles(parent.role, fm);
|
|
198
|
+
warnings.push(...merged.warnings);
|
|
199
|
+
const bodyMode = fm.metadata?.["aip-47"]?.bodyMerge ?? "append-with-separator";
|
|
200
|
+
const body = mergeBodies(parent.body, manifest.body, bodyMode);
|
|
201
|
+
return { role: merged.role, body };
|
|
202
|
+
};
|
|
203
|
+
const result = await walk(ref, 0, false);
|
|
204
|
+
if (!result) {
|
|
205
|
+
const w = {
|
|
206
|
+
code: "role_unresolvable",
|
|
207
|
+
message: `role ref '${ref}' did not resolve in any source`,
|
|
208
|
+
ref
|
|
209
|
+
};
|
|
210
|
+
warnings.push(w);
|
|
211
|
+
throw Object.assign(new Error(w.message), { warnings, chain });
|
|
212
|
+
}
|
|
213
|
+
const validated = roleFrontmatterSchema.safeParse(result.role);
|
|
214
|
+
if (!validated.success) {
|
|
215
|
+
const issues = validated.error.issues.map(
|
|
216
|
+
(i) => `${i.path.join(".")}: ${i.message}`
|
|
217
|
+
);
|
|
218
|
+
warnings.push({
|
|
219
|
+
code: "role_validation_failed",
|
|
220
|
+
message: `merged role failed schema validation`,
|
|
221
|
+
ref,
|
|
222
|
+
issues
|
|
223
|
+
});
|
|
224
|
+
}
|
|
225
|
+
return {
|
|
226
|
+
role: validated.success ? validated.data : result.role,
|
|
227
|
+
body: result.body,
|
|
228
|
+
chain,
|
|
229
|
+
warnings
|
|
230
|
+
};
|
|
231
|
+
}
|
|
232
|
+
var WS_REF_PREFIX = "ws://roles/";
|
|
233
|
+
var BUILTIN_PREFIX = "builtin/";
|
|
234
|
+
var REGISTRY_FAMILY = "role-builtin";
|
|
235
|
+
function normaliseSlug(ref) {
|
|
236
|
+
if (ref.startsWith(WS_REF_PREFIX)) return ref.slice(WS_REF_PREFIX.length);
|
|
237
|
+
if (ref.startsWith(BUILTIN_PREFIX)) return ref.slice(BUILTIN_PREFIX.length);
|
|
238
|
+
return ref;
|
|
239
|
+
}
|
|
240
|
+
var BuiltinRoleSource = class {
|
|
241
|
+
scheme = "builtin";
|
|
242
|
+
/**
|
|
243
|
+
* Underlying AIP-43 registry. Exposed for advanced consumers that
|
|
244
|
+
* want to use `lookup(predicate)`, `entries()`, or other registry
|
|
245
|
+
* primitives. The common operations are mirrored on the source
|
|
246
|
+
* itself for ergonomics.
|
|
247
|
+
*/
|
|
248
|
+
registry;
|
|
249
|
+
constructor(entries = []) {
|
|
250
|
+
this.registry = createRegistry({
|
|
251
|
+
family: REGISTRY_FAMILY,
|
|
252
|
+
keyBy: (e) => e.slug
|
|
253
|
+
});
|
|
254
|
+
for (const e of entries) {
|
|
255
|
+
this.registry.register(e);
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
async load(ref) {
|
|
259
|
+
const slug = normaliseSlug(ref);
|
|
260
|
+
const entry = this.registry.get(slug);
|
|
261
|
+
if (!entry) return null;
|
|
262
|
+
return {
|
|
263
|
+
ref: `builtin/${slug}`,
|
|
264
|
+
frontmatter: entry.handle,
|
|
265
|
+
body: entry.body ?? "",
|
|
266
|
+
scheme: "builtin"
|
|
267
|
+
};
|
|
268
|
+
}
|
|
269
|
+
async list() {
|
|
270
|
+
return this.registry.list().map((e) => `builtin/${e.slug}`);
|
|
271
|
+
}
|
|
272
|
+
/* ─── mutation surface (AIP-43 primitive operations) ─────────── */
|
|
273
|
+
/**
|
|
274
|
+
* Register a new builtin entry. Throws `RegistryDuplicateError`
|
|
275
|
+
* if a handle with the same slug is already registered — use
|
|
276
|
+
* `replace` to swap atomically when a hot-reload picks up a
|
|
277
|
+
* redefined role.
|
|
278
|
+
*/
|
|
279
|
+
register(entry) {
|
|
280
|
+
this.registry.register(entry);
|
|
281
|
+
}
|
|
282
|
+
/**
|
|
283
|
+
* Replace an existing entry. Throws `RegistryNotFoundError` if no
|
|
284
|
+
* entry exists at the resolved slug. Use `register` for new slugs.
|
|
285
|
+
*/
|
|
286
|
+
replace(entry) {
|
|
287
|
+
this.registry.replace(entry);
|
|
288
|
+
}
|
|
289
|
+
/**
|
|
290
|
+
* Remove a slug from the registry. Returns true if an entry was
|
|
291
|
+
* removed. Use sparingly — the registry is intended to be
|
|
292
|
+
* boot-time-stable.
|
|
293
|
+
*/
|
|
294
|
+
unregister(slug) {
|
|
295
|
+
return this.registry.unregister(normaliseSlug(slug));
|
|
296
|
+
}
|
|
297
|
+
/** Returns true if the slug (any ref form) is registered. */
|
|
298
|
+
has(slug) {
|
|
299
|
+
return this.registry.has(normaliseSlug(slug));
|
|
300
|
+
}
|
|
301
|
+
/** Number of entries currently registered. */
|
|
302
|
+
count() {
|
|
303
|
+
return this.registry.count();
|
|
304
|
+
}
|
|
305
|
+
/**
|
|
306
|
+
* Filter entries by an arbitrary predicate. Runs in registration
|
|
307
|
+
* order. Useful for capability lookups like "every role with
|
|
308
|
+
* `metadata.aip-47.audience === 'ai-worker'`".
|
|
309
|
+
*/
|
|
310
|
+
lookup(predicate) {
|
|
311
|
+
return this.registry.lookup(predicate);
|
|
312
|
+
}
|
|
313
|
+
};
|
|
314
|
+
function builtinSourceFromRecord(record) {
|
|
315
|
+
return new BuiltinRoleSource(
|
|
316
|
+
Object.entries(record).map(([slug, rest]) => ({ slug, ...rest }))
|
|
317
|
+
);
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
// src/index.ts
|
|
321
|
+
var SPEC_NAME = "agentrole/v1";
|
|
322
|
+
var SPEC_VERSION = "1.0.0-alpha";
|
|
323
|
+
var ROLE_SENIORITIES = [
|
|
324
|
+
"intern",
|
|
325
|
+
"junior",
|
|
326
|
+
"mid",
|
|
327
|
+
"senior",
|
|
328
|
+
"lead",
|
|
329
|
+
"principal",
|
|
330
|
+
"executive"
|
|
331
|
+
];
|
|
332
|
+
var RECOMMENDED_DEPARTMENTS = [
|
|
333
|
+
"executive",
|
|
334
|
+
"operations",
|
|
335
|
+
"engineering",
|
|
336
|
+
"product",
|
|
337
|
+
"marketing",
|
|
338
|
+
"sales",
|
|
339
|
+
"customer",
|
|
340
|
+
"finance",
|
|
341
|
+
"people"
|
|
342
|
+
];
|
|
343
|
+
function departmentLabel(slug) {
|
|
344
|
+
const labels = {
|
|
345
|
+
executive: "Executive",
|
|
346
|
+
operations: "Operations",
|
|
347
|
+
engineering: "Engineering",
|
|
348
|
+
product: "Product",
|
|
349
|
+
marketing: "Marketing",
|
|
350
|
+
sales: "Sales",
|
|
351
|
+
customer: "Customer",
|
|
352
|
+
finance: "Finance",
|
|
353
|
+
people: "People"
|
|
354
|
+
};
|
|
355
|
+
if (labels[slug] !== void 0) {
|
|
356
|
+
return labels[slug];
|
|
357
|
+
}
|
|
358
|
+
return slug.split("-").map((s) => s.length === 0 ? s : s[0].toUpperCase() + s.slice(1)).join(" ");
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
export { BuiltinRoleSource, LIST_FIELDS, LOCAL_ONLY_FIELDS, RECOMMENDED_DEPARTMENTS, ROLE_SENIORITIES, SPEC_NAME, SPEC_VERSION, builtinSourceFromRecord, departmentLabel, mergeBodies, mergeRoles, resolveRole };
|
|
362
|
+
//# sourceMappingURL=index.mjs.map
|
|
363
|
+
//# sourceMappingURL=index.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/merge.ts","../src/resolve.ts","../src/sources/builtin.ts","../src/index.ts"],"names":[],"mappings":";;;;;;;;;;AAoCO,IAAM,WAAA,GAAc;AAAA,EACzB,kBAAA;AAAA,EACA,cAAA;AAAA,EACA,OAAA;AAAA,EACA,QAAA;AAAA,EACA,MAAA;AAAA,EACA,WAAA;AAAA,EACA,cAAA;AAAA,EACA;AACF;AASO,IAAM,iBAAA,GAAoB,CAAC,SAAA,EAAW,WAAW;AAkDxD,SAAS,cAAA,CACP,KAAA,EACA,SAAA,EACA,KAAA,EAC0C;AAC1C,EAAA,IAAI,UAAU,MAAA,EAAW;AACvB,IAAA,OAAO,EAAE,OAAO,CAAC,GAAG,SAAS,CAAA,EAAG,QAAA,EAAU,EAAC,EAAE;AAAA,EAC/C;AAGA,EAAA,IAAI,KAAA,CAAM,OAAA,CAAQ,KAAK,CAAA,EAAG;AACxB,IAAA,OAAO,EAAE,OAAO,CAAC,GAAG,KAAK,CAAA,EAAG,QAAA,EAAU,EAAC,EAAE;AAAA,EAC3C;AAGA,EAAA,MAAM,WAA2B,EAAC;AAClC,EAAA,MAAM,KAAA,GAAQ,KAAA;AACd,EAAA,MAAM,YAAY,IAAI,GAAA,CAAI,KAAA,CAAM,MAAA,IAAU,EAAE,CAAA;AAG5C,EAAA,MAAM,OAAA,uBAAc,GAAA,EAAO;AAC3B,EAAA,MAAM,QAAA,GAAW,SAAA,CAAU,MAAA,CAAO,CAAC,IAAA,KAAS;AAC1C,IAAA,MAAM,MAAA,GAAS,CAAC,SAAA,CAAU,GAAA,CAAI,IAAI,CAAA;AAClC,IAAA,IAAI,CAAC,MAAA,EAAQ,OAAA,CAAQ,GAAA,CAAI,IAAI,CAAA;AAC7B,IAAA,OAAO,MAAA;AAAA,EACT,CAAC,CAAA;AAED,EAAA,KAAA,MAAW,KAAK,SAAA,EAAW;AACzB,IAAA,IAAI,CAAC,OAAA,CAAQ,GAAA,CAAI,CAAC,CAAA,EAAG;AACnB,MAAA,QAAA,CAAS,IAAA,CAAK;AAAA,QACZ,IAAA,EAAM,0BAAA;AAAA,QACN,OAAA,EAAS,GAAG,KAAK,CAAA,0CAAA,CAAA;AAAA,QACjB,KAAA;AAAA,QACA,OAAA,EAAS,OAAO,CAAC;AAAA,OAClB,CAAA;AAAA,IACH;AAAA,EACF;AAGA,EAAA,MAAM,GAAA,GAAM,CAAC,GAAG,QAAQ,CAAA;AACxB,EAAA,KAAA,MAAW,CAAA,IAAK,KAAA,CAAM,GAAA,IAAO,EAAC,EAAG;AAC/B,IAAA,IAAI,CAAC,GAAA,CAAI,QAAA,CAAS,CAAC,CAAA,EAAG,GAAA,CAAI,KAAK,CAAC,CAAA;AAAA,EAClC;AAEA,EAAA,OAAO,EAAE,KAAA,EAAO,GAAA,EAAK,QAAA,EAAS;AAChC;AAOA,SAAS,SAAA,CAAU,QAAiB,KAAA,EAAyB;AAC3D,EAAA,IAAI,KAAA,KAAU,QAAW,OAAO,MAAA;AAChC,EAAA,IAAI,OAAO,WAAW,QAAA,IAAY,MAAA,KAAW,QAAQ,KAAA,CAAM,OAAA,CAAQ,MAAM,CAAA,EAAG;AAC1E,IAAA,OAAO,KAAA;AAAA,EACT;AACA,EAAA,IAAI,OAAO,UAAU,QAAA,IAAY,KAAA,KAAU,QAAQ,KAAA,CAAM,OAAA,CAAQ,KAAK,CAAA,EAAG;AACvE,IAAA,OAAO,KAAA;AAAA,EACT;AACA,EAAA,MAAM,GAAA,GAA+B,EAAE,GAAI,MAAA,EAAmC;AAC9E,EAAA,KAAA,MAAW,CAAC,CAAA,EAAG,CAAC,KAAK,MAAA,CAAO,OAAA,CAAQ,KAAgC,CAAA,EAAG;AACrE,IAAA,GAAA,CAAI,CAAC,CAAA,GAAI,SAAA,CAAW,MAAA,CAAmC,CAAC,GAAG,CAAC,CAAA;AAAA,EAC9D;AACA,EAAA,OAAO,GAAA;AACT;AAgBO,SAAS,UAAA,CAAW,QAAoB,KAAA,EAAoC;AACjF,EAAA,MAAM,WAA2B,EAAC;AAIlC,EAAA,MAAM,IAAA,GAAO,CAAiC,GAAA,KAA8B;AAC1E,IAAA,MAAM,CAAA,GAAK,MAAkC,GAAG,CAAA;AAChD,IAAA,OAAO,CAAA,KAAM,MAAA,GAAY,CAAA,GAAI,MAAA,CAAO,GAAG,CAAA;AAAA,EACzC,CAAA;AAGA,EAAA,MAAM,QAAwC,EAAC;AAC/C,EAAA,KAAA,MAAW,SAAS,WAAA,EAAa;AAC/B,IAAA,MAAM,SAAA,GACJ,UAAU,kBAAA,GACL,MAAA,CAAO,mBACP,MAAA,CAAO,KAAK,KAAuC,EAAC;AAC3D,IAAA,MAAM,UAAA,GAAc,MAAyB,KAAK,CAAA;AAGlD,IAAA,MAAM,MAAA,GAAS,cAAA,CAAe,KAAA,EAAO,SAAA,EAAW,UAAU,CAAA;AAC1D,IAAA,QAAA,CAAS,IAAA,CAAK,GAAG,MAAA,CAAO,QAAQ,CAAA;AAChC,IAAA,KAAA,CAAM,KAAK,IAAI,MAAA,CAAO,KAAA;AAAA,EACxB;AAIA,EAAA,IAAI,KAAA,CAAM,gBAAA,CAAiB,MAAA,KAAW,CAAA,EAAG;AAIvC,IAAA,KAAA,CAAM,gBAAA,GAAmB,CAAC,GAAG,MAAA,CAAO,gBAAgB,CAAA;AAAA,EACtD;AAMA,EAAA,MAAM,WAAA,GAAc;AAAA,IAClB,GAAI,MAAA,CAAO,SAAA,EAAW,KAAA,IAAS,EAAC;AAAA,IAChC,GAAI,KAAA,CAAM,SAAA,EAAW,KAAA,IAAS;AAAC,GACjC,CAAE,MAAA,CAAO,CAAC,CAAA,EAAG,CAAA,EAAG,MAAM,CAAA,CAAE,OAAA,CAAQ,CAAC,CAAA,KAAM,CAAC,CAAA;AACxC,EAAA,MAAM,SAAA,GACJ,OAAO,SAAA,IAAa,KAAA,CAAM,YAAY,EAAE,KAAA,EAAO,aAAY,GAAI,MAAA;AAEjE,EAAA,MAAM,MAAA,GAAyB;AAAA;AAAA,IAE7B,MAAA,EAAQ,SAAA;AAAA,IACR,IAAA,EAAM,KAAK,MAAM,CAAA;AAAA,IACjB,KAAA,EAAO,KAAK,OAAO,CAAA;AAAA,IACnB,WAAA,EAAa,KAAK,aAAa,CAAA;AAAA,IAC/B,OAAA,EAAS,KAAK,SAAS,CAAA;AAAA,IACvB,SAAA,EAAW,KAAK,WAAW,CAAA;AAAA,IAC3B,OAAA,EAAS,KAAK,SAAS,CAAA;AAAA;AAAA,IAGvB,UAAA,EAAY,KAAK,YAAY,CAAA;AAAA,IAC7B,UAAA,EAAY,KAAK,YAAY,CAAA;AAAA;AAAA,IAG7B,WAAA,EAAa,KAAK,aAAa,CAAA;AAAA,IAC/B,UAAA,EAAY,KAAK,YAAY,CAAA;AAAA,IAC7B,QAAA,EAAU,KAAK,UAAU,CAAA;AAAA;AAAA,IAGzB,cAAA,EAAgB,KAAK,gBAAgB,CAAA;AAAA,IACrC,eAAA,EAAiB,KAAK,iBAAiB,CAAA;AAAA,IACvC,aAAA,EAAe,KAAK,eAAe,CAAA;AAAA;AAAA,IAGnC,GAAI,SAAA,GAAY,EAAE,SAAA,KAAc,EAAC;AAAA;AAAA,IAGjC,SAAS,KAAA,CAAM,OAAA;AAAA,IACf,WAAW,KAAA,CAAM,SAAA;AAAA;AAAA,IAGjB,kBAAkB,KAAA,CAAM,gBAAA;AAAA,IACxB,cAAc,KAAA,CAAM,YAAA;AAAA,IACpB,OAAO,KAAA,CAAM,KAAA;AAAA,IACb,QAAQ,KAAA,CAAM,MAAA;AAAA,IACd,MAAM,KAAA,CAAM,IAAA;AAAA,IACZ,WAAW,KAAA,CAAM,SAAA;AAAA,IACjB,cAAc,KAAA,CAAM,YAAA;AAAA,IACpB,MAAM,KAAA,CAAM,IAAA;AAAA;AAAA,IAGZ,UAAU,SAAA,CAAU,MAAA,CAAO,YAAY,EAAC,EAAG,MAAM,QAAQ;AAAA,GAI3D;AAIA,EAAA,IAAI,KAAA,CAAM,OAAA,KAAY,MAAA,EAAW,OAAQ,MAAA,CAAmC,OAAA;AAC5E,EAAA,IAAI,MAAM,SAAA,KAAc,MAAA;AACtB,IAAA,OAAQ,MAAA,CAAmC,SAAA;AAE7C,EAAA,OAAO,EAAE,IAAA,EAAM,MAAA,EAAsB,QAAA,EAAS;AAChD;AAQO,SAAS,WAAA,CACd,UAAA,EACA,SAAA,EACA,IAAA,GAA4C,uBAAA,EACpC;AACR,EAAA,IAAI,CAAC,UAAA,EAAY,OAAO,SAAA,IAAa,EAAA;AACrC,EAAA,IAAI,CAAC,WAAW,OAAO,UAAA;AACvB,EAAA,IAAI,IAAA,KAAS,WAAW,OAAO,SAAA;AAC/B,EAAA,OAAO,CAAA,EAAG,UAAA,CAAW,OAAA,EAAS;;AAAA;;AAAA,EAAc,SAAA,CAAU,WAAW,CAAA,CAAA;AACnE;;;ACvRA,IAAM,iBAAA,GAAoB,CAAA;AAkE1B,eAAsB,WAAA,CACpB,KACA,IAAA,EACuB;AACvB,EAAA,MAAM,QAAA,GAAW,KAAK,QAAA,IAAY,iBAAA;AAClC,EAAA,MAAM,OAAA,uBAAc,GAAA,EAAY;AAChC,EAAA,MAAM,WAA6B,EAAC;AACpC,EAAA,MAAM,QAAkB,EAAC;AAEzB,EAAA,MAAM,IAAA,GAAO,OAAO,OAAA,KAAsD;AACxE,IAAA,KAAA,MAAW,GAAA,IAAO,KAAK,OAAA,EAAS;AAC9B,MAAA,MAAM,CAAA,GAAI,MAAM,GAAA,CAAI,IAAA,CAAK,OAAO,CAAA;AAChC,MAAA,IAAI,CAAA,KAAM,MAAM,OAAO,CAAA;AAAA,IACzB;AACA,IAAA,OAAO,IAAA;AAAA,EACT,CAAA;AASA,EAAA,MAAM,IAAA,GAAO,OACX,OAAA,EACA,KAAA,EACA,WAAA,KACuD;AACvD,IAAA,IAAI,QAAQ,QAAA,EAAU;AACpB,MAAA,QAAA,CAAS,IAAA,CAAK;AAAA,QACZ,IAAA,EAAM,6BAAA;AAAA,QACN,OAAA,EAAS,CAAA,6BAAA,EAAgC,QAAQ,CAAA,KAAA,EAAQ,OAAO,CAAA,CAAA,CAAA;AAAA,QAChE,KAAA;AAAA,QACA,GAAA,EAAK;AAAA,OACN,CAAA;AACD,MAAA,OAAO,IAAA;AAAA,IACT;AACA,IAAA,IAAI,OAAA,CAAQ,GAAA,CAAI,OAAO,CAAA,EAAG;AACxB,MAAA,QAAA,CAAS,IAAA,CAAK;AAAA,QACZ,IAAA,EAAM,oBAAA;AAAA,QACN,OAAA,EAAS,8BAA8B,OAAO,CAAA,CAAA,CAAA;AAAA,QAC9C,KAAA,EAAO,CAAC,GAAG,OAAA,EAAS,OAAO;AAAA,OAC5B,CAAA;AACD,MAAA,OAAO,IAAA;AAAA,IACT;AACA,IAAA,OAAA,CAAQ,IAAI,OAAO,CAAA;AAEnB,IAAA,MAAM,QAAA,GAAW,MAAM,IAAA,CAAK,OAAO,CAAA;AACnC,IAAA,IAAI,CAAC,QAAA,EAAU;AAGb,MAAA,IAAI,WAAA,EAAa;AACf,QAAA,QAAA,CAAS,IAAA,CAAK;AAAA,UACZ,IAAA,EAAM,sBAAA;AAAA,UACN,OAAA,EAAS,eAAe,OAAO,CAAA,iBAAA,CAAA;AAAA,UAC/B,MAAA,EAAQ;AAAA,SACT,CAAA;AAAA,MACH;AACA,MAAA,OAAO,IAAA;AAAA,IACT;AACA,IAAA,KAAA,CAAM,IAAA,CAAK,SAAS,GAAG,CAAA;AAEvB,IAAA,MAAM,KAAK,QAAA,CAAS,WAAA;AACpB,IAAA,MAAM,aAAa,EAAA,CAAG,OAAA;AAEtB,IAAA,IAAI,CAAC,UAAA,EAAY;AACf,MAAA,OAAO,EAAE,IAAA,EAAM,EAAA,EAAkB,IAAA,EAAM,SAAS,IAAA,EAAK;AAAA,IACvD;AAEA,IAAA,MAAM,SAAS,MAAM,IAAA,CAAK,UAAA,EAAY,KAAA,GAAQ,GAAG,IAAI,CAAA;AACrD,IAAA,IAAI,CAAC,MAAA,EAAQ;AAGX,MAAA,OAAO,EAAE,IAAA,EAAM,EAAA,EAAkB,IAAA,EAAM,SAAS,IAAA,EAAK;AAAA,IACvD;AAGA,IAAA,MAAM,MAAA,GAAS,UAAA,CAAW,MAAA,CAAO,IAAA,EAAM,EAAE,CAAA;AACzC,IAAA,QAAA,CAAS,IAAA,CAAK,GAAG,MAAA,CAAO,QAAQ,CAAA;AAGhC,IAAA,MAAM,QAAA,GACF,EAAA,CAAG,QAAA,GAAmD,QAAQ,GAEhD,SAAA,IAAa,uBAAA;AAC/B,IAAA,MAAM,OAAO,WAAA,CAAY,MAAA,CAAO,IAAA,EAAM,QAAA,CAAS,MAAM,QAAQ,CAAA;AAE7D,IAAA,OAAO,EAAE,IAAA,EAAM,MAAA,CAAO,IAAA,EAAM,IAAA,EAAK;AAAA,EACnC,CAAA;AAEA,EAAA,MAAM,MAAA,GAAS,MAAM,IAAA,CAAK,GAAA,EAAK,GAAG,KAAK,CAAA;AACvC,EAAA,IAAI,CAAC,MAAA,EAAQ;AAIX,IAAA,MAAM,CAAA,GAAoB;AAAA,MACxB,IAAA,EAAM,mBAAA;AAAA,MACN,OAAA,EAAS,aAAa,GAAG,CAAA,+BAAA,CAAA;AAAA,MACzB;AAAA,KACF;AACA,IAAA,QAAA,CAAS,KAAK,CAAC,CAAA;AACf,IAAA,MAAM,MAAA,CAAO,MAAA,CAAO,IAAI,KAAA,CAAM,CAAA,CAAE,OAAO,CAAA,EAAG,EAAE,QAAA,EAAU,KAAA,EAAO,CAAA;AAAA,EAC/D;AAGA,EAAA,MAAM,SAAA,GAAY,qBAAA,CAAsB,SAAA,CAAU,MAAA,CAAO,IAAI,CAAA;AAC7D,EAAA,IAAI,CAAC,UAAU,OAAA,EAAS;AACtB,IAAA,MAAM,MAAA,GAAS,SAAA,CAAU,KAAA,CAAM,MAAA,CAAO,GAAA;AAAA,MACpC,CAAC,CAAA,KAAM,CAAA,EAAG,CAAA,CAAE,IAAA,CAAK,KAAK,GAAG,CAAC,CAAA,EAAA,EAAK,CAAA,CAAE,OAAO,CAAA;AAAA,KAC1C;AACA,IAAA,QAAA,CAAS,IAAA,CAAK;AAAA,MACZ,IAAA,EAAM,wBAAA;AAAA,MACN,OAAA,EAAS,CAAA,oCAAA,CAAA;AAAA,MACT,GAAA;AAAA,MACA;AAAA,KACD,CAAA;AAAA,EAGH;AAEA,EAAA,OAAO;AAAA,IACL,IAAA,EAAM,SAAA,CAAU,OAAA,GAAW,SAAA,CAAU,OAAsB,MAAA,CAAO,IAAA;AAAA,IAClE,MAAM,MAAA,CAAO,IAAA;AAAA,IACb,KAAA;AAAA,IACA;AAAA,GACF;AACF;AC7LA,IAAM,aAAA,GAAgB,aAAA;AACtB,IAAM,cAAA,GAAiB,UAAA;AACvB,IAAM,eAAA,GAAkB,cAAA;AAExB,SAAS,cAAc,GAAA,EAAsB;AAC3C,EAAA,IAAI,GAAA,CAAI,WAAW,aAAa,CAAA,SAAU,GAAA,CAAI,KAAA,CAAM,cAAc,MAAM,CAAA;AACxE,EAAA,IAAI,GAAA,CAAI,WAAW,cAAc,CAAA,SAAU,GAAA,CAAI,KAAA,CAAM,eAAe,MAAM,CAAA;AAC1E,EAAA,OAAO,GAAA;AACT;AAEO,IAAM,oBAAN,MAA8C;AAAA,EAC1C,MAAA,GAAS,SAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQT,QAAA;AAAA,EAET,WAAA,CAAY,OAAA,GAAsC,EAAC,EAAG;AACpD,IAAA,IAAA,CAAK,WAAW,cAAA,CAAiC;AAAA,MAC/C,MAAA,EAAQ,eAAA;AAAA,MACR,KAAA,EAAO,CAAC,CAAA,KAAM,CAAA,CAAE;AAAA,KACjB,CAAA;AACD,IAAA,KAAA,MAAW,KAAK,OAAA,EAAS;AACvB,MAAA,IAAA,CAAK,QAAA,CAAS,SAAS,CAAC,CAAA;AAAA,IAC1B;AAAA,EACF;AAAA,EAEA,MAAM,KAAK,GAAA,EAA+C;AACxD,IAAA,MAAM,IAAA,GAAO,cAAc,GAAG,CAAA;AAC9B,IAAA,MAAM,KAAA,GAAQ,IAAA,CAAK,QAAA,CAAS,GAAA,CAAI,IAAI,CAAA;AACpC,IAAA,IAAI,CAAC,OAAO,OAAO,IAAA;AACnB,IAAA,OAAO;AAAA,MACL,GAAA,EAAK,WAAW,IAAI,CAAA,CAAA;AAAA,MACpB,aAAa,KAAA,CAAM,MAAA;AAAA,MACnB,IAAA,EAAM,MAAM,IAAA,IAAQ,EAAA;AAAA,MACpB,MAAA,EAAQ;AAAA,KACV;AAAA,EACF;AAAA,EAEA,MAAM,IAAA,GAAoC;AACxC,IAAA,OAAO,IAAA,CAAK,QAAA,CAAS,IAAA,EAAK,CAAE,GAAA,CAAI,CAAC,CAAA,KAAM,CAAA,QAAA,EAAW,CAAA,CAAE,IAAI,CAAA,CAAE,CAAA;AAAA,EAC5D;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAUA,SAAS,KAAA,EAA+B;AACtC,IAAA,IAAA,CAAK,QAAA,CAAS,SAAS,KAAK,CAAA;AAAA,EAC9B;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,QAAQ,KAAA,EAA+B;AACrC,IAAA,IAAA,CAAK,QAAA,CAAS,QAAQ,KAAK,CAAA;AAAA,EAC7B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,WAAW,IAAA,EAAuB;AAChC,IAAA,OAAO,IAAA,CAAK,QAAA,CAAS,UAAA,CAAW,aAAA,CAAc,IAAI,CAAC,CAAA;AAAA,EACrD;AAAA;AAAA,EAGA,IAAI,IAAA,EAAuB;AACzB,IAAA,OAAO,IAAA,CAAK,QAAA,CAAS,GAAA,CAAI,aAAA,CAAc,IAAI,CAAC,CAAA;AAAA,EAC9C;AAAA;AAAA,EAGA,KAAA,GAAgB;AACd,IAAA,OAAO,IAAA,CAAK,SAAS,KAAA,EAAM;AAAA,EAC7B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,OACE,SAAA,EAC6B;AAC7B,IAAA,OAAO,IAAA,CAAK,QAAA,CAAS,MAAA,CAAO,SAAS,CAAA;AAAA,EACvC;AACF;AAMO,SAAS,wBACd,MAAA,EACmB;AACnB,EAAA,OAAO,IAAI,iBAAA;AAAA,IACT,MAAA,CAAO,OAAA,CAAQ,MAAM,CAAA,CAAE,IAAI,CAAC,CAAC,IAAA,EAAM,IAAI,CAAA,MAAO,EAAE,IAAA,EAAM,GAAG,MAAK,CAAE;AAAA,GAClE;AACF;;;ACjHO,IAAM,SAAA,GAAY;AAClB,IAAM,YAAA,GAAe;AAOrB,IAAM,gBAAA,GAAmB;AAAA,EAC9B,QAAA;AAAA,EACA,QAAA;AAAA,EACA,KAAA;AAAA,EACA,QAAA;AAAA,EACA,MAAA;AAAA,EACA,WAAA;AAAA,EACA;AACF;AAcO,IAAM,uBAAA,GAA0B;AAAA,EACrC,WAAA;AAAA,EACA,YAAA;AAAA,EACA,aAAA;AAAA,EACA,SAAA;AAAA,EACA,WAAA;AAAA,EACA,OAAA;AAAA,EACA,UAAA;AAAA,EACA,SAAA;AAAA,EACA;AACF;AAQO,SAAS,gBAAgB,IAAA,EAAsB;AACpD,EAAA,MAAM,MAAA,GAA0D;AAAA,IAC9D,SAAA,EAAW,WAAA;AAAA,IACX,UAAA,EAAY,YAAA;AAAA,IACZ,WAAA,EAAa,aAAA;AAAA,IACb,OAAA,EAAS,SAAA;AAAA,IACT,SAAA,EAAW,WAAA;AAAA,IACX,KAAA,EAAO,OAAA;AAAA,IACP,QAAA,EAAU,UAAA;AAAA,IACV,OAAA,EAAS,SAAA;AAAA,IACT,MAAA,EAAQ;AAAA,GACV;AACA,EAAA,IAAK,MAAA,CAAkC,IAAI,CAAA,KAAM,MAAA,EAAW;AAC1D,IAAA,OAAQ,OAAkC,IAAI,CAAA;AAAA,EAChD;AACA,EAAA,OAAO,IAAA,CACJ,MAAM,GAAG,CAAA,CACT,IAAI,CAAC,CAAA,KAAO,CAAA,CAAE,MAAA,KAAW,CAAA,GAAI,CAAA,GAAI,EAAE,CAAC,CAAA,CAAG,aAAY,GAAI,CAAA,CAAE,MAAM,CAAC,CAAE,CAAA,CAClE,IAAA,CAAK,GAAG,CAAA;AACb","file":"index.mjs","sourcesContent":["/**\n * AIP-47 strategic merge for role inheritance.\n *\n * Pure function: parent + child → merged. No I/O.\n *\n * Merge strategy per AIP-47 §Merge strategy table:\n * - scalars (name/title/description/version/department/reports_to/\n * seniority/mission/onPromotion/onDemotion/onAssign/defaultPersona/\n * defaultIdentity/defaultPolicy): override (child wins)\n * - list-strategy fields (responsibilities/capabilities/tools/skills/\n * kpis/strengths/antiPatterns/tags): append-and-dedupe, OR\n * `{ add, remove }` patch form\n * - extends + appliesTo: local-only (never inherited)\n * - metadata: deep-merge\n *\n * Body merge is handled by `mergeBodies` (separate concern — handles\n * `metadata['aip-47'].bodyMerge` switch).\n */\n\nimport type { RoleDefinition, RoleHandle } from \"./types.js\"\n\n/**\n * A child role's input may carry a list patch on a list-strategy field\n * instead of a plain list. The patch is applied against the inherited\n * accumulator at merge time.\n *\n * See AIP-47 §Merge strategy →\n * \"Explicit remove of inherited entries\".\n */\nexport type ListPatch<T> = readonly T[] | { add?: readonly T[]; remove?: readonly T[] }\n\n/**\n * The set of list-strategy field names per AIP-47 §Merge strategy.\n * Every entry here is an `append-and-dedupe` field that admits the\n * `{ add, remove }` patch form.\n */\nexport const LIST_FIELDS = [\n \"responsibilities\",\n \"capabilities\",\n \"tools\",\n \"skills\",\n \"kpis\",\n \"strengths\",\n \"antiPatterns\",\n \"tags\",\n] as const\n\nexport type ListField = (typeof LIST_FIELDS)[number]\n\n/**\n * The set of fields that are NEVER inherited from a parent role.\n * Used by the resolver to strip them before merging into the\n * accumulator.\n */\nexport const LOCAL_ONLY_FIELDS = [\"extends\", \"appliesTo\"] as const\n\n/**\n * A child role's raw input. Same shape as `RoleDefinition` except\n * that list-strategy fields admit the `{ add, remove }` patch form.\n * The merger normalises patches into plain lists; the resolved output\n * is always `RoleHandle` (plain lists only).\n */\nexport type RoleChildInput = Omit<Partial<RoleDefinition>, ListField> & {\n [K in ListField]?: K extends \"responsibilities\"\n ? ListPatch<string> | [string, ...string[]]\n : ListPatch<string>\n}\n\nexport type MergeWarning =\n | {\n code: \"role_merge_form_conflict\"\n message: string\n field: ListField\n }\n | {\n code: \"role_merge_remove_missed\"\n message: string\n field: ListField\n missing: string\n }\n\nexport interface MergeResult {\n /** The merged role frontmatter, always plain lists. */\n role: RoleHandle\n /** Diagnostics emitted during merge. */\n warnings: MergeWarning[]\n}\n\n/**\n * Apply a list patch onto an inherited accumulator.\n *\n * - If `child` is a plain array → REPLACE the inherited list entirely.\n * - If `child` is `{ add, remove }` → APPEND-AND-DEDUPE additions and\n * exact-string-REMOVE inherited entries.\n * - If `child` is `undefined` → return the inherited accumulator as-is.\n *\n * The \"replace\" semantics for the plain-array form matches the\n * AIP-47 spec exactly: a child author writing the field in long form\n * (plain list) overrides the lineage; the `{ add, remove }` form is\n * the only way to patch.\n *\n * Returns the resolved list AND any warnings (e.g. `remove` entries\n * that did not match anything in the accumulator).\n */\nfunction applyListPatch<T>(\n field: ListField,\n inherited: readonly T[],\n child: ListPatch<T> | undefined,\n): { value: T[]; warnings: MergeWarning[] } {\n if (child === undefined) {\n return { value: [...inherited], warnings: [] }\n }\n\n // Plain array → replace.\n if (Array.isArray(child)) {\n return { value: [...child], warnings: [] }\n }\n\n // Patch form.\n const warnings: MergeWarning[] = []\n const patch = child as { add?: readonly T[]; remove?: readonly T[] }\n const removeSet = new Set(patch.remove ?? [])\n\n // Track which `remove` entries actually matched something inherited.\n const matched = new Set<T>()\n const filtered = inherited.filter((item) => {\n const should = !removeSet.has(item)\n if (!should) matched.add(item)\n return should\n })\n\n for (const r of removeSet) {\n if (!matched.has(r)) {\n warnings.push({\n code: \"role_merge_remove_missed\",\n message: `${field}: remove entry not found in inherited list`,\n field,\n missing: String(r),\n })\n }\n }\n\n // Append additions (dedupe against the already-filtered accumulator).\n const out = [...filtered]\n for (const a of patch.add ?? []) {\n if (!out.includes(a)) out.push(a)\n }\n\n return { value: out, warnings }\n}\n\n/**\n * Deep-merge two plain objects (used for `metadata`). Arrays at any\n * depth are replaced by the child's array (NOT concatenated) — same\n * semantics as Helm strategic merge for non-list-strategy maps.\n */\nfunction deepMerge(parent: unknown, child: unknown): unknown {\n if (child === undefined) return parent\n if (typeof parent !== \"object\" || parent === null || Array.isArray(parent)) {\n return child\n }\n if (typeof child !== \"object\" || child === null || Array.isArray(child)) {\n return child\n }\n const out: Record<string, unknown> = { ...(parent as Record<string, unknown>) }\n for (const [k, v] of Object.entries(child as Record<string, unknown>)) {\n out[k] = deepMerge((parent as Record<string, unknown>)[k], v)\n }\n return out\n}\n\n/**\n * Strategic-merge a parent role (already resolved, plain handle) with\n * a child role's raw input. Returns a fully-typed `RoleHandle` and any\n * merge-time warnings.\n *\n * The merger does NOT validate against the canonical schema — that is\n * the caller's responsibility (typically `resolveRole` validates the\n * final merged role at the end of chain walking).\n *\n * Override fields (scalars + non-list maps + single bindings) follow\n * `child wins if defined`. Local-only fields are NEVER inherited from\n * the parent: the resolved role carries the local-only fields of the\n * leaf (current) child, never of any ancestor.\n */\nexport function mergeRoles(parent: RoleHandle, child: RoleChildInput): MergeResult {\n const warnings: MergeWarning[] = []\n\n // Helper: apply a child override (scalar / single ref) using\n // `child wins if defined` semantics.\n const pick = <K extends keyof RoleDefinition>(key: K): RoleDefinition[K] => {\n const c = (child as Partial<RoleDefinition>)[key]\n return c !== undefined ? c : parent[key]\n }\n\n // List-strategy fields — patch or replace per spec.\n const lists: { [K in ListField]: string[] } = {} as never\n for (const field of LIST_FIELDS) {\n const inherited =\n field === \"responsibilities\"\n ? (parent.responsibilities as readonly string[])\n : (parent[field] as readonly string[] | undefined) ?? []\n const childField = (child as RoleChildInput)[field] as\n | ListPatch<string>\n | undefined\n const result = applyListPatch(field, inherited, childField)\n warnings.push(...result.warnings)\n lists[field] = result.value\n }\n\n // `responsibilities` is `[string, ...string[]]` in the canonical\n // schema. The merger preserves the constraint by typing the output.\n if (lists.responsibilities.length === 0) {\n // Should never happen — parent.responsibilities is required ≥ 1,\n // and append-and-dedupe never empties it. A plain-array override\n // with an empty list would; we defensively keep the parent's.\n lists.responsibilities = [...parent.responsibilities]\n }\n\n // knowledge.packs — append-and-dedupe across lineage (nested, so not a\n // LIST_FIELD; child packs append onto the inherited floor). Only emit a\n // `knowledge` block when some layer declared one, so packless roles stay\n // clean (and the host's slug convention still applies).\n const mergedPacks = [\n ...(parent.knowledge?.packs ?? []),\n ...(child.knowledge?.packs ?? []),\n ].filter((p, i, a) => a.indexOf(p) === i)\n const knowledge =\n parent.knowledge || child.knowledge ? { packs: mergedPacks } : undefined\n\n const merged: RoleDefinition = {\n // Doctype identity — child wins if set.\n schema: \"role/v1\",\n name: pick(\"name\") as string,\n title: pick(\"title\") as string,\n description: pick(\"description\") as string,\n version: pick(\"version\") as string,\n seniority: pick(\"seniority\") as RoleDefinition[\"seniority\"],\n mission: pick(\"mission\") as string,\n\n // Org placement — overrides.\n department: pick(\"department\") as string | undefined,\n reports_to: pick(\"reports_to\") as string | undefined,\n\n // Lifecycle hooks — overrides.\n onPromotion: pick(\"onPromotion\") as string | undefined,\n onDemotion: pick(\"onDemotion\") as string | undefined,\n onAssign: pick(\"onAssign\") as string | undefined,\n\n // Single bindings — overrides.\n defaultPersona: pick(\"defaultPersona\") as string | undefined,\n defaultIdentity: pick(\"defaultIdentity\") as string | undefined,\n defaultPolicy: pick(\"defaultPolicy\") as string | undefined,\n\n // Nested knowledge binding — append-and-dedupe union (computed above).\n ...(knowledge ? { knowledge } : {}),\n\n // Local-only fields — child's value carries; parent's is dropped.\n extends: child.extends,\n appliesTo: child.appliesTo as string[] | undefined,\n\n // List-strategy.\n responsibilities: lists.responsibilities as [string, ...string[]],\n capabilities: lists.capabilities,\n tools: lists.tools,\n skills: lists.skills,\n kpis: lists.kpis,\n strengths: lists.strengths,\n antiPatterns: lists.antiPatterns,\n tags: lists.tags,\n\n // Deep-merged maps.\n metadata: deepMerge(parent.metadata ?? {}, child.metadata) as Record<\n string,\n unknown\n >,\n }\n\n // Strip the local-only fields if the child didn't set them — we\n // never want them to leak from the parent into the merged role.\n if (child.extends === undefined) delete (merged as Partial<RoleDefinition>).extends\n if (child.appliesTo === undefined)\n delete (merged as Partial<RoleDefinition>).appliesTo\n\n return { role: merged as RoleHandle, warnings }\n}\n\n/**\n * Body merge for ROLE.md body markdown. The parent's body comes from\n * the resolved parent manifest; the child's body comes from the\n * current frontmatter parse. The default is `append-with-separator`;\n * `metadata['aip-47'].bodyMerge === 'replace'` switches to replace.\n */\nexport function mergeBodies(\n parentBody: string | undefined,\n childBody: string | undefined,\n mode: \"append-with-separator\" | \"replace\" = \"append-with-separator\",\n): string {\n if (!parentBody) return childBody ?? \"\"\n if (!childBody) return parentBody\n if (mode === \"replace\") return childBody\n return `${parentBody.trimEnd()}\\n\\n---\\n\\n${childBody.trimStart()}`\n}\n","/**\n * AIP-47 role resolver — walks the `extends` chain, merges, validates.\n *\n * Pipeline:\n * 1. dispatch the ref through the source chain — first match wins\n * 2. if the loaded manifest has `extends`, recurse to resolve the\n * parent (cycle-detected, depth-capped, warnings on missing)\n * 3. apply strategic merge (parent + child) per AIP-47 §Merge\n * strategy via `merge.ts`\n * 4. validate the merged frontmatter against the canonical zod\n * schema (defensive — sources MAY ship raw / patch-form input)\n * 5. return `{ role, body, chain, warnings }`\n *\n * Cycle detection: tracks visited refs during chain walk.\n * Depth limit: max 8 (per spec recommendation).\n * Missing parent: warning, fallback to the local manifest.\n */\n\nimport { roleFrontmatterSchema } from \"./schema.js\"\nimport { mergeBodies, mergeRoles, type MergeWarning } from \"./merge.js\"\nimport type { RoleDefinition, RoleHandle } from \"./types.js\"\nimport type { RoleManifestRaw, RoleRef, RoleSource } from \"./sources/types.js\"\n\nconst DEFAULT_MAX_DEPTH = 8\n\nexport type ResolveWarning =\n | MergeWarning\n | {\n code: \"role_unresolvable\"\n message: string\n ref: string\n }\n | {\n code: \"role_extends_cycle\"\n message: string\n cycle: readonly string[]\n }\n | {\n code: \"role_extends_depth_exceeded\"\n message: string\n depth: number\n ref: string\n }\n | {\n code: \"role_extends_missing\"\n message: string\n parent: string\n }\n | {\n code: \"role_validation_failed\"\n message: string\n ref: string\n issues: readonly string[]\n }\n\nexport interface ResolveOptions {\n /** Source chain — consulted in order, first match wins. */\n readonly sources: readonly RoleSource[]\n /** Maximum `extends` chain depth. Default 8. */\n readonly maxDepth?: number\n}\n\nexport interface ResolvedRole {\n /** Effective role after `extends`-chain merge. Always plain lists. */\n readonly role: RoleHandle\n /** Merged body markdown — parent appended with `\\n\\n---\\n\\n` separator. */\n readonly body: string\n /**\n * Ordered list of refs walked, from leaf to root.\n * `chain[0]` is the requested ref; the last entry is the root parent.\n */\n readonly chain: readonly string[]\n /** Diagnostics emitted during resolution + merge. */\n readonly warnings: readonly ResolveWarning[]\n}\n\n/**\n * Resolve a role ref through the source chain and merge any\n * `extends` lineage. Throws iff the leaf ref cannot be loaded AND no\n * partial result is recoverable (i.e. the top-level lookup fails).\n *\n * Intermediate failures (cycle, depth, missing parent) MUST NOT\n * throw — they emit warnings and the resolver falls back to the\n * local manifest. This is the AIP-47 spec contract:\n *\n * \"Treat depth overflow and cycle detection as warnings, not\n * errors. A role whose chain is malformed MUST still load — the\n * runtime falls back to the local manifest only.\"\n */\nexport async function resolveRole(\n ref: RoleRef,\n opts: ResolveOptions,\n): Promise<ResolvedRole> {\n const maxDepth = opts.maxDepth ?? DEFAULT_MAX_DEPTH\n const visited = new Set<string>()\n const warnings: ResolveWarning[] = []\n const chain: string[] = []\n\n const load = async (current: RoleRef): Promise<RoleManifestRaw | null> => {\n for (const src of opts.sources) {\n const m = await src.load(current)\n if (m !== null) return m\n }\n return null\n }\n\n // Recursive walker. Returns the merged role (or null on hard failure).\n // The leaf is loaded first; the parent chain is walked top-down so\n // we merge child onto parent (parent is the accumulator base).\n //\n // `isParentRef` discriminates leaf-miss (caller throws role_unresolvable)\n // from parent-miss (we warn role_extends_missing and the caller falls\n // back to its local manifest).\n const walk = async (\n current: RoleRef,\n depth: number,\n isParentRef: boolean,\n ): Promise<{ role: RoleHandle; body: string } | null> => {\n if (depth > maxDepth) {\n warnings.push({\n code: \"role_extends_depth_exceeded\",\n message: `extends chain depth exceeded ${maxDepth} at '${current}'`,\n depth,\n ref: current,\n })\n return null\n }\n if (visited.has(current)) {\n warnings.push({\n code: \"role_extends_cycle\",\n message: `extends cycle detected at '${current}'`,\n cycle: [...visited, current],\n })\n return null\n }\n visited.add(current)\n\n const manifest = await load(current)\n if (!manifest) {\n // Parent-miss is a warning (caller falls back); leaf-miss is\n // surfaced by the top-level caller as role_unresolvable.\n if (isParentRef) {\n warnings.push({\n code: \"role_extends_missing\",\n message: `parent ref '${current}' did not resolve`,\n parent: current,\n })\n }\n return null\n }\n chain.push(manifest.ref)\n\n const fm = manifest.frontmatter as Partial<RoleDefinition>\n const extendsRef = fm.extends\n\n if (!extendsRef) {\n return { role: fm as RoleHandle, body: manifest.body }\n }\n\n const parent = await walk(extendsRef, depth + 1, true)\n if (!parent) {\n // Parent chain broken — fall back to the local manifest only.\n // The warning was already pushed by the recursive call.\n return { role: fm as RoleHandle, body: manifest.body }\n }\n\n // Apply strategic merge.\n const merged = mergeRoles(parent.role, fm)\n warnings.push(...merged.warnings)\n\n // Body merge — read bodyMerge mode from child metadata.\n const bodyMode =\n ((fm.metadata as Record<string, unknown> | undefined)?.[\"aip-47\"] as\n | { bodyMerge?: \"append-with-separator\" | \"replace\" }\n | undefined)?.bodyMerge ?? \"append-with-separator\"\n const body = mergeBodies(parent.body, manifest.body, bodyMode)\n\n return { role: merged.role, body }\n }\n\n const result = await walk(ref, 0, false)\n if (!result) {\n // Leaf miss (or hard chain failure with no fallback). Per AIP-47,\n // the resolver MUST surface `role_unresolvable` and throw — the\n // caller cannot proceed without a role.\n const w: ResolveWarning = {\n code: \"role_unresolvable\",\n message: `role ref '${ref}' did not resolve in any source`,\n ref,\n }\n warnings.push(w)\n throw Object.assign(new Error(w.message), { warnings, chain })\n }\n\n // Defensive validation of the merged frontmatter.\n const validated = roleFrontmatterSchema.safeParse(result.role)\n if (!validated.success) {\n const issues = validated.error.issues.map(\n (i) => `${i.path.join(\".\")}: ${i.message}`,\n )\n warnings.push({\n code: \"role_validation_failed\",\n message: `merged role failed schema validation`,\n ref,\n issues,\n })\n // Still return the merged role — validators downstream may want\n // to surface it. The warning makes the failure observable.\n }\n\n return {\n role: validated.success ? (validated.data as RoleHandle) : result.role,\n body: result.body,\n chain,\n warnings,\n }\n}\n","/**\n * AIP-47 built-in role source.\n *\n * Wraps an AIP-43 `@agentproto/registry` instance keyed by role slug.\n * Intended primarily for runtime-shipped catalogues\n * (`@agentproto/role-catalog`, vendor-specific registries) where the\n * roles are authored in TS and validated at module load time. The\n * registry is mutable post-construction — `register` / `unregister` /\n * `replace` let downstream apps extend the catalogue without forking\n * the OSS package.\n *\n * Refs are matched in three forms:\n * - bare slug: `seo-specialist`\n * - scoped slug: `builtin/seo-specialist`\n * - ws:// ref: `ws://roles/seo-specialist`\n *\n * All three resolve to the same entry. The `scheme` is `builtin`.\n */\n\nimport { createRegistry, type Registry } from \"@agentproto/registry\"\nimport type {\n BuiltinRoleEntry,\n RoleManifestRaw,\n RoleRef,\n RoleSource,\n} from \"./types.js\"\n\nconst WS_REF_PREFIX = \"ws://roles/\"\nconst BUILTIN_PREFIX = \"builtin/\"\nconst REGISTRY_FAMILY = \"role-builtin\"\n\nfunction normaliseSlug(ref: RoleRef): string {\n if (ref.startsWith(WS_REF_PREFIX)) return ref.slice(WS_REF_PREFIX.length)\n if (ref.startsWith(BUILTIN_PREFIX)) return ref.slice(BUILTIN_PREFIX.length)\n return ref\n}\n\nexport class BuiltinRoleSource implements RoleSource {\n readonly scheme = \"builtin\"\n\n /**\n * Underlying AIP-43 registry. Exposed for advanced consumers that\n * want to use `lookup(predicate)`, `entries()`, or other registry\n * primitives. The common operations are mirrored on the source\n * itself for ergonomics.\n */\n readonly registry: Registry<BuiltinRoleEntry>\n\n constructor(entries: Iterable<BuiltinRoleEntry> = []) {\n this.registry = createRegistry<BuiltinRoleEntry>({\n family: REGISTRY_FAMILY,\n keyBy: (e) => e.slug,\n })\n for (const e of entries) {\n this.registry.register(e)\n }\n }\n\n async load(ref: RoleRef): Promise<RoleManifestRaw | null> {\n const slug = normaliseSlug(ref)\n const entry = this.registry.get(slug)\n if (!entry) return null\n return {\n ref: `builtin/${slug}`,\n frontmatter: entry.handle,\n body: entry.body ?? \"\",\n scheme: \"builtin\",\n }\n }\n\n async list(): Promise<readonly RoleRef[]> {\n return this.registry.list().map((e) => `builtin/${e.slug}`)\n }\n\n /* ─── mutation surface (AIP-43 primitive operations) ─────────── */\n\n /**\n * Register a new builtin entry. Throws `RegistryDuplicateError`\n * if a handle with the same slug is already registered — use\n * `replace` to swap atomically when a hot-reload picks up a\n * redefined role.\n */\n register(entry: BuiltinRoleEntry): void {\n this.registry.register(entry)\n }\n\n /**\n * Replace an existing entry. Throws `RegistryNotFoundError` if no\n * entry exists at the resolved slug. Use `register` for new slugs.\n */\n replace(entry: BuiltinRoleEntry): void {\n this.registry.replace(entry)\n }\n\n /**\n * Remove a slug from the registry. Returns true if an entry was\n * removed. Use sparingly — the registry is intended to be\n * boot-time-stable.\n */\n unregister(slug: string): boolean {\n return this.registry.unregister(normaliseSlug(slug))\n }\n\n /** Returns true if the slug (any ref form) is registered. */\n has(slug: string): boolean {\n return this.registry.has(normaliseSlug(slug))\n }\n\n /** Number of entries currently registered. */\n count(): number {\n return this.registry.count()\n }\n\n /**\n * Filter entries by an arbitrary predicate. Runs in registration\n * order. Useful for capability lookups like \"every role with\n * `metadata.aip-47.audience === 'ai-worker'`\".\n */\n lookup(\n predicate: (entry: BuiltinRoleEntry) => boolean,\n ): readonly BuiltinRoleEntry[] {\n return this.registry.lookup(predicate)\n }\n}\n\n/**\n * Convenience: assemble a `BuiltinRoleSource` from a record map.\n * Each entry's key becomes the slug.\n */\nexport function builtinSourceFromRecord(\n record: Record<string, Omit<BuiltinRoleEntry, \"slug\">>,\n): BuiltinRoleSource {\n return new BuiltinRoleSource(\n Object.entries(record).map(([slug, rest]) => ({ slug, ...rest })),\n )\n}\n","/**\n * @agentproto/role — AIP-47 ROLE.md `defineRole` reference impl.\n *\n * A single-doc markdown + frontmatter format for portable organizational roles — mission, responsibilities, capabilities, tools, KPIs, seniority, reporting line, lifecycle hooks. Sibling to AIP-25 PERSONA (face) and AIP-23 IDENTITY (substance); referenced by AIP-9 OPERATOR (`role:` field) and AIP-6 COMPANY (`roles/<slug>/ROLE.md` doctype). Roles describe what a job is — independent of who holds it (persona/identity) and which instance is hired (operator).\n *\n * Spec: https://agentproto.sh/docs/aip-47\n *\n * Authoring paths:\n * - TS: `defineRole({...})` → `RoleHandle`\n * - MD: `parseRoleManifest(src) → roleFromManifest({...})` → `RoleHandle`\n *\n * Resolution:\n * - `resolveRole(ref, { sources })` walks the `extends` chain, applies\n * strategic merge per the spec, and returns the effective `RoleHandle`\n * plus the merged body, the resolution chain, and any warnings.\n *\n * Composition (advisory, never grants access):\n * - Operators consume the resolved role via AIP-9 OPERATOR `role:`\n * field. Effective permissions come from AIP-38 POLICY, NOT from\n * the role — see AIP-47 §Role vs Policy vs Governance.\n */\n\nexport const SPEC_NAME = \"agentrole/v1\" as const\nexport const SPEC_VERSION = \"1.0.0-alpha\" as const\n\n/**\n * Seniority levels per AIP-47 §Optional fields. Const tuple exported\n * so consumers can derive zod / openapi enum schemas from the single\n * source of truth — keep this in sync with `ROLE.schema.json`.\n */\nexport const ROLE_SENIORITIES = [\n \"intern\",\n \"junior\",\n \"mid\",\n \"senior\",\n \"lead\",\n \"principal\",\n \"executive\",\n] as const\nexport type RoleSeniority = (typeof ROLE_SENIORITIES)[number]\n\n/**\n * Recommended departments per AIP-47 §Departments (informative).\n * `department` on a ROLE.md is a free string — these values are\n * suggested for cross-runtime alignment. Runtimes that group / chart\n * roles by department SHOULD render this list as the default\n * taxonomy and treat any out-of-list value as a domain-specific\n * extension (legal, R&D, clinical, …).\n *\n * Order is significant: the array order is the recommended display\n * order for org charts and \"hire\" UIs.\n */\nexport const RECOMMENDED_DEPARTMENTS = [\n \"executive\",\n \"operations\",\n \"engineering\",\n \"product\",\n \"marketing\",\n \"sales\",\n \"customer\",\n \"finance\",\n \"people\",\n] as const\nexport type RecommendedDepartment = (typeof RECOMMENDED_DEPARTMENTS)[number]\n\n/**\n * Human-readable label for a department slug. Falls back to a\n * Title-Case-ified version of the slug for departments outside the\n * recommended list (custom org taxonomies).\n */\nexport function departmentLabel(slug: string): string {\n const labels: Readonly<Record<RecommendedDepartment, string>> = {\n executive: \"Executive\",\n operations: \"Operations\",\n engineering: \"Engineering\",\n product: \"Product\",\n marketing: \"Marketing\",\n sales: \"Sales\",\n customer: \"Customer\",\n finance: \"Finance\",\n people: \"People\",\n }\n if ((labels as Record<string, string>)[slug] !== undefined) {\n return (labels as Record<string, string>)[slug]!\n }\n return slug\n .split(\"-\")\n .map((s) => (s.length === 0 ? s : s[0]!.toUpperCase() + s.slice(1)))\n .join(\" \")\n}\n\nexport { defineRole } from \"./define-role.js\"\nexport type { RoleDefinition, RoleHandle } from \"./types.js\"\n\n// Resolution / merge — the heart of role composition.\nexport { resolveRole } from \"./resolve.js\"\nexport type {\n ResolveOptions,\n ResolveWarning,\n ResolvedRole,\n} from \"./resolve.js\"\n\nexport {\n mergeRoles,\n mergeBodies,\n LIST_FIELDS,\n LOCAL_ONLY_FIELDS,\n} from \"./merge.js\"\nexport type {\n ListField,\n ListPatch,\n MergeResult,\n MergeWarning,\n RoleChildInput,\n} from \"./merge.js\"\n\n// Source loaders (in-memory builtin shipped here; fs/db live in adapters).\nexport {\n BuiltinRoleSource,\n builtinSourceFromRecord,\n} from \"./sources/builtin.js\"\nexport type {\n BuiltinRoleEntry,\n RoleManifestRaw,\n RoleRef,\n RoleSource,\n} from \"./sources/types.js\"\n"]}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { a as RoleHandle } from '../types-CohqAgUN.js';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* AIP-47 ROLE.md frontmatter zod schema.
|
|
6
|
+
*
|
|
7
|
+
* Generated from `resources/aip-47/draft/ROLE.schema.json` via
|
|
8
|
+
* json-schema-to-zod. Imported by both `define-role.ts` (TS path
|
|
9
|
+
* validation) and `manifest/index.ts` (.md path validation) so every
|
|
10
|
+
* field-level constraint runs in both authoring paths from a single
|
|
11
|
+
* source of truth — re-run scaffold-aip to refresh after spec changes.
|
|
12
|
+
*
|
|
13
|
+
* Cross-field rules (if/then/allOf in JSON Schema) don't translate
|
|
14
|
+
* cleanly and live in `define-role.ts`'s `validate(def)` instead.
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
declare const roleFrontmatterSchema: z.ZodObject<{
|
|
18
|
+
schema: z.ZodLiteral<"role/v1">;
|
|
19
|
+
name: z.ZodString;
|
|
20
|
+
title: z.ZodString;
|
|
21
|
+
description: z.ZodString;
|
|
22
|
+
version: z.ZodString;
|
|
23
|
+
extends: z.ZodOptional<z.ZodString>;
|
|
24
|
+
department: z.ZodOptional<z.ZodString>;
|
|
25
|
+
reports_to: z.ZodOptional<z.ZodString>;
|
|
26
|
+
seniority: z.ZodEnum<{
|
|
27
|
+
intern: "intern";
|
|
28
|
+
junior: "junior";
|
|
29
|
+
mid: "mid";
|
|
30
|
+
senior: "senior";
|
|
31
|
+
lead: "lead";
|
|
32
|
+
principal: "principal";
|
|
33
|
+
executive: "executive";
|
|
34
|
+
}>;
|
|
35
|
+
mission: z.ZodString;
|
|
36
|
+
responsibilities: z.ZodArray<z.ZodString>;
|
|
37
|
+
capabilities: z.ZodDefault<z.ZodArray<z.ZodString>>;
|
|
38
|
+
tools: z.ZodDefault<z.ZodArray<z.ZodString>>;
|
|
39
|
+
skills: z.ZodDefault<z.ZodArray<z.ZodString>>;
|
|
40
|
+
kpis: z.ZodDefault<z.ZodArray<z.ZodString>>;
|
|
41
|
+
strengths: z.ZodDefault<z.ZodArray<z.ZodString>>;
|
|
42
|
+
antiPatterns: z.ZodDefault<z.ZodArray<z.ZodString>>;
|
|
43
|
+
onPromotion: z.ZodOptional<z.ZodString>;
|
|
44
|
+
onDemotion: z.ZodOptional<z.ZodString>;
|
|
45
|
+
onAssign: z.ZodOptional<z.ZodString>;
|
|
46
|
+
appliesTo: z.ZodDefault<z.ZodArray<z.ZodString>>;
|
|
47
|
+
defaultPersona: z.ZodOptional<z.ZodString>;
|
|
48
|
+
defaultIdentity: z.ZodOptional<z.ZodString>;
|
|
49
|
+
defaultPolicy: z.ZodOptional<z.ZodString>;
|
|
50
|
+
knowledge: z.ZodOptional<z.ZodObject<{
|
|
51
|
+
packs: z.ZodDefault<z.ZodArray<z.ZodString>>;
|
|
52
|
+
}, z.core.$strict>>;
|
|
53
|
+
tags: z.ZodDefault<z.ZodArray<z.ZodString>>;
|
|
54
|
+
metadata: z.ZodDefault<z.ZodRecord<z.ZodString, z.ZodAny>>;
|
|
55
|
+
}, z.core.$strict>;
|
|
56
|
+
type RoleFrontmatter = z.infer<typeof roleFrontmatterSchema>;
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* AIP-47 ROLE.md sidecar parser + manifest-to-handle constructor.
|
|
60
|
+
*
|
|
61
|
+
* Mirror of `@agentproto/tool/manifest` and `@agentproto/driver/manifest`:
|
|
62
|
+
* the .md provides metadata; the TS module supplies any spec-specific
|
|
63
|
+
* runtime bits (schemas, execute bodies, …) that can't live in
|
|
64
|
+
* frontmatter. Both inputs end up in `defineRole` so the cross-AIP
|
|
65
|
+
* invariants run uniformly.
|
|
66
|
+
*
|
|
67
|
+
*
|
|
68
|
+
* The frontmatter zod schema below was generated from
|
|
69
|
+
* `resources/aip-47/draft/ROLE.schema.json` via json-schema-to-zod.
|
|
70
|
+
* Re-run scaffold-aip to refresh after spec changes (or hand-tune
|
|
71
|
+
* any constraint the converter doesn't capture cleanly).
|
|
72
|
+
*/
|
|
73
|
+
|
|
74
|
+
interface RoleManifest {
|
|
75
|
+
frontmatter: RoleFrontmatter;
|
|
76
|
+
body: string;
|
|
77
|
+
}
|
|
78
|
+
declare function parseRoleManifest(source: string): RoleManifest;
|
|
79
|
+
declare function roleFromManifest(manifest: RoleManifest): RoleHandle;
|
|
80
|
+
|
|
81
|
+
export { type RoleFrontmatter, type RoleManifest, parseRoleManifest, roleFromManifest, roleFrontmatterSchema };
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { roleFrontmatterSchema, defineRole } from '../chunk-U2HQWFCN.mjs';
|
|
2
|
+
export { roleFrontmatterSchema } from '../chunk-U2HQWFCN.mjs';
|
|
3
|
+
import matter from 'gray-matter';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* @agentproto/role v0.1.0-alpha
|
|
7
|
+
* AIP-47 ROLE.md `defineRole` reference implementation.
|
|
8
|
+
*/
|
|
9
|
+
function parseRoleManifest(source) {
|
|
10
|
+
const parsed = matter(source);
|
|
11
|
+
if (Object.keys(parsed.data).length === 0) {
|
|
12
|
+
throw new Error("parseRoleManifest: missing or empty frontmatter");
|
|
13
|
+
}
|
|
14
|
+
const result = roleFrontmatterSchema.safeParse(parsed.data);
|
|
15
|
+
if (!result.success) {
|
|
16
|
+
throw new Error(
|
|
17
|
+
`parseRoleManifest: invalid frontmatter \u2014 ${result.error.issues.map((i) => `${i.path.join(".")}: ${i.message}`).join("; ")}`
|
|
18
|
+
);
|
|
19
|
+
}
|
|
20
|
+
return { frontmatter: result.data, body: parsed.content };
|
|
21
|
+
}
|
|
22
|
+
function roleFromManifest(manifest) {
|
|
23
|
+
return defineRole(manifest.frontmatter);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export { parseRoleManifest, roleFromManifest };
|
|
27
|
+
//# sourceMappingURL=index.mjs.map
|
|
28
|
+
//# sourceMappingURL=index.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/manifest/index.ts"],"names":[],"mappings":";;;;;;;;AA8BO,SAAS,kBAAkB,MAAA,EAA8B;AAC9D,EAAA,MAAM,MAAA,GAAS,OAAO,MAAM,CAAA;AAC5B,EAAA,IAAI,OAAO,IAAA,CAAK,MAAA,CAAO,IAAI,CAAA,CAAE,WAAW,CAAA,EAAG;AACzC,IAAA,MAAM,IAAI,MAAM,iDAAiD,CAAA;AAAA,EACnE;AACA,EAAA,MAAM,MAAA,GAAS,qBAAA,CAAsB,SAAA,CAAU,MAAA,CAAO,IAAI,CAAA;AAC1D,EAAA,IAAI,CAAC,OAAO,OAAA,EAAS;AACnB,IAAA,MAAM,IAAI,KAAA;AAAA,MACR,CAAA,8CAAA,EAA4C,OAAO,KAAA,CAAM,MAAA,CACtD,IAAI,CAAC,CAAA,KAAM,GAAG,CAAA,CAAE,IAAA,CAAK,KAAK,GAAG,CAAC,KAAK,CAAA,CAAE,OAAO,EAAE,CAAA,CAC9C,IAAA,CAAK,IAAI,CAAC,CAAA;AAAA,KACf;AAAA,EACF;AACA,EAAA,OAAO,EAAE,WAAA,EAAa,MAAA,CAAO,IAAA,EAAM,IAAA,EAAM,OAAO,OAAA,EAAQ;AAC1D;AAEO,SAAS,iBAAiB,QAAA,EAAoC;AAKnE,EAAA,OAAO,UAAA,CAAW,SAAS,WAAwC,CAAA;AACrE","file":"index.mjs","sourcesContent":["/**\n * AIP-47 ROLE.md sidecar parser + manifest-to-handle constructor.\n *\n * Mirror of `@agentproto/tool/manifest` and `@agentproto/driver/manifest`:\n * the .md provides metadata; the TS module supplies any spec-specific\n * runtime bits (schemas, execute bodies, …) that can't live in\n * frontmatter. Both inputs end up in `defineRole` so the cross-AIP\n * invariants run uniformly.\n *\n *\n * The frontmatter zod schema below was generated from\n * `resources/aip-47/draft/ROLE.schema.json` via json-schema-to-zod.\n * Re-run scaffold-aip to refresh after spec changes (or hand-tune\n * any constraint the converter doesn't capture cleanly).\n */\n\nimport matter from \"gray-matter\"\nimport { roleFrontmatterSchema, type RoleFrontmatter } from \"../schema.js\"\nimport { defineRole } from \"../define-role.js\"\nimport type { RoleDefinition, RoleHandle } from \"../types.js\"\n\n// Re-export so consumers can import the schema + inferred type either\n// from \"@@agentproto/role/manifest\" or directly from \"@@agentproto/role/schema\".\nexport { roleFrontmatterSchema, type RoleFrontmatter }\n\nexport interface RoleManifest {\n frontmatter: RoleFrontmatter\n body: string\n}\n\nexport function parseRoleManifest(source: string): RoleManifest {\n const parsed = matter(source)\n if (Object.keys(parsed.data).length === 0) {\n throw new Error(\"parseRoleManifest: missing or empty frontmatter\")\n }\n const result = roleFrontmatterSchema.safeParse(parsed.data)\n if (!result.success) {\n throw new Error(\n `parseRoleManifest: invalid frontmatter — ${result.error.issues\n .map((i) => `${i.path.join(\".\")}: ${i.message}`)\n .join(\"; \")}`,\n )\n }\n return { frontmatter: result.data, body: parsed.content }\n}\n\nexport function roleFromManifest(manifest: RoleManifest): RoleHandle {\n // The zod-validated frontmatter is structurally compatible with\n // RoleDefinition; the cast pins the typing once the manifest\n // schema and the TS interface diverge (e.g. handle has frozen fields\n // a literal config doesn't carry yet).\n return defineRole(manifest.frontmatter as unknown as RoleDefinition)\n}\n"]}
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AIP-47 RoleDefinition + RoleHandle.
|
|
3
|
+
*
|
|
4
|
+
* `RoleDefinition` was generated from
|
|
5
|
+
* `resources/aip-47/draft/ROLE.schema.json` via json-schema-to-typescript.
|
|
6
|
+
* `RoleHandle` is the readonly view of the same shape; tighten it
|
|
7
|
+
* by hand for fields that get defaults applied in build().
|
|
8
|
+
*/
|
|
9
|
+
/**
|
|
10
|
+
* Validates the YAML frontmatter portion of an AIP-47 ROLE.md manifest. Single-doc, no oneOf — every role is the same shape. The body is markdown and not validated by this schema.
|
|
11
|
+
*/
|
|
12
|
+
interface RoleDefinition {
|
|
13
|
+
/**
|
|
14
|
+
* Schema dispatch tag. MUST be 'role/v1' for this version of AIP-47.
|
|
15
|
+
*/
|
|
16
|
+
schema: "role/v1";
|
|
17
|
+
/**
|
|
18
|
+
* Machine identifier. Lowercase, digits, dashes. Must start with a letter, end with a letter or digit. Unique within the registry that hosts the role.
|
|
19
|
+
*/
|
|
20
|
+
name: string;
|
|
21
|
+
/**
|
|
22
|
+
* Human-readable display title, sentence case.
|
|
23
|
+
*/
|
|
24
|
+
title: string;
|
|
25
|
+
/**
|
|
26
|
+
* One-paragraph job description. The role's purpose, audience, and shape.
|
|
27
|
+
*/
|
|
28
|
+
description: string;
|
|
29
|
+
/**
|
|
30
|
+
* Semver. Bump on breaking change to responsibilities, KPIs, tools, or seniority.
|
|
31
|
+
*/
|
|
32
|
+
version: string;
|
|
33
|
+
/**
|
|
34
|
+
* Relative path to a parent ROLE.md. Triggers composition. Path MUST end in 'ROLE.md'.
|
|
35
|
+
*/
|
|
36
|
+
extends?: string;
|
|
37
|
+
/**
|
|
38
|
+
* Department slug. Lowercase kebab-case. Recommended values listed in AIP-47 §Departments; free-form to accept domain-specific values.
|
|
39
|
+
*/
|
|
40
|
+
department?: string;
|
|
41
|
+
/**
|
|
42
|
+
* Role-to-role reporting link. Conventionally a 'ws://roles/<slug>' ref. Schema does not validate scheme; the loader resolves.
|
|
43
|
+
*/
|
|
44
|
+
reports_to?: string;
|
|
45
|
+
/**
|
|
46
|
+
* Seniority level of the job. Operator instances inherit this; a promotion is re-binding the operator to a higher-seniority role.
|
|
47
|
+
*/
|
|
48
|
+
seniority: "intern" | "junior" | "mid" | "senior" | "lead" | "principal" | "executive";
|
|
49
|
+
/**
|
|
50
|
+
* One-paragraph mission, markdown. The reason the role exists.
|
|
51
|
+
*/
|
|
52
|
+
mission: string;
|
|
53
|
+
/**
|
|
54
|
+
* Ordered imperative clauses. At least one. Lineage accumulates under 'extends' (append-and-dedupe).
|
|
55
|
+
*
|
|
56
|
+
* @minItems 1
|
|
57
|
+
*/
|
|
58
|
+
responsibilities: [string, ...string[]];
|
|
59
|
+
/**
|
|
60
|
+
* Competences this role is expected to have. Append-and-dedupe across 'extends'.
|
|
61
|
+
*/
|
|
62
|
+
capabilities?: string[];
|
|
63
|
+
/**
|
|
64
|
+
* AIP-14 tool refs the role declares as intended. Append-and-dedupe across 'extends'. Governance (AIP-7) gates effect.
|
|
65
|
+
*/
|
|
66
|
+
tools?: string[];
|
|
67
|
+
/**
|
|
68
|
+
* AIP-3 skill refs the role expects to load. Append-and-dedupe across 'extends'.
|
|
69
|
+
*/
|
|
70
|
+
skills?: string[];
|
|
71
|
+
/**
|
|
72
|
+
* Scorer slugs (forward AIP) — KPIs evaluated against operators in this role. Append-and-dedupe across 'extends'.
|
|
73
|
+
*/
|
|
74
|
+
kpis?: string[];
|
|
75
|
+
/**
|
|
76
|
+
* Job-side strengths in prose. Append-and-dedupe across 'extends'.
|
|
77
|
+
*/
|
|
78
|
+
strengths?: string[];
|
|
79
|
+
/**
|
|
80
|
+
* What the role explicitly does NOT do. Append-and-dedupe across 'extends'.
|
|
81
|
+
*/
|
|
82
|
+
antiPatterns?: string[];
|
|
83
|
+
/**
|
|
84
|
+
* AIP-39 action ref fired on promotion INTO this role.
|
|
85
|
+
*/
|
|
86
|
+
onPromotion?: string;
|
|
87
|
+
/**
|
|
88
|
+
* AIP-39 action ref fired on demotion OUT of this role.
|
|
89
|
+
*/
|
|
90
|
+
onDemotion?: string;
|
|
91
|
+
/**
|
|
92
|
+
* AIP-39 action ref fired on first assignment of this role.
|
|
93
|
+
*/
|
|
94
|
+
onAssign?: string;
|
|
95
|
+
/**
|
|
96
|
+
* Cross-AIP bindings — restrict the role to specific operators. Local-only under 'extends' (NOT inherited).
|
|
97
|
+
*/
|
|
98
|
+
appliesTo?: string[];
|
|
99
|
+
/**
|
|
100
|
+
* AIP-25 PERSONA ref recommended for operators adopting this role. Advisory; the operator's own 'persona' field overrides.
|
|
101
|
+
*/
|
|
102
|
+
defaultPersona?: string;
|
|
103
|
+
/**
|
|
104
|
+
* AIP-23 IDENTITY ref recommended for operators adopting this role. Advisory; the operator's own 'identity' field overrides.
|
|
105
|
+
*/
|
|
106
|
+
defaultIdentity?: string;
|
|
107
|
+
/**
|
|
108
|
+
* AIP-38 POLICY ref recommended for operators adopting this role. ADVISORY ONLY — role declares intent, policy decides effect. The runtime MUST NOT apply defaultPolicy to an operator without the operator's own 'policy:' field or a governance signature attesting the binding. See AIP-47 §Role vs Policy vs Governance.
|
|
109
|
+
*/
|
|
110
|
+
defaultPolicy?: string;
|
|
111
|
+
/**
|
|
112
|
+
* Generic knowledge this role consults — AIP-10 corpus packs mounted
|
|
113
|
+
* read-only as a floor beneath the operator's own corpus. Distinct from
|
|
114
|
+
* 'skills' (what the role knows how to DO): knowledge is what it CONSULTS.
|
|
115
|
+
* The host unions these with any operator-level packs.
|
|
116
|
+
*/
|
|
117
|
+
knowledge?: {
|
|
118
|
+
/**
|
|
119
|
+
* AIP-10 knowledge-pack refs this role mounts as its generic corpus
|
|
120
|
+
* floor. The host resolves each ref to a pack and mounts it read-only
|
|
121
|
+
* UNDER the operator's own editable corpus (the host overlays them).
|
|
122
|
+
* Append-and-dedupe across 'extends'. Absent = the host's convention
|
|
123
|
+
* (e.g. a pack named after the role slug). Operator-level packs layer
|
|
124
|
+
* ABOVE these.
|
|
125
|
+
*/
|
|
126
|
+
packs?: string[];
|
|
127
|
+
};
|
|
128
|
+
/**
|
|
129
|
+
* Catalog tags. Lowercase kebab-case. Append-and-dedupe across 'extends'.
|
|
130
|
+
*/
|
|
131
|
+
tags?: string[];
|
|
132
|
+
/**
|
|
133
|
+
* Vendor extensions, namespaced under '<vendor>'. Hosts MUST tolerate unknown vendor namespaces; they MUST NOT honour metadata that overrides AIP-defined fields.
|
|
134
|
+
*/
|
|
135
|
+
metadata?: Record<string, unknown>;
|
|
136
|
+
}
|
|
137
|
+
type RoleHandle = Readonly<RoleDefinition>;
|
|
138
|
+
|
|
139
|
+
export type { RoleDefinition as R, RoleHandle as a };
|
package/package.json
ADDED
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@agentproto/role",
|
|
3
|
+
"version": "0.1.0-alpha.0",
|
|
4
|
+
"description": "@agentproto/role — AIP-47 ROLE.md reference implementation. A single-doc markdown + frontmatter format for portable organizational roles — mission, responsibilities, capabilities, tools, KPIs, seniority, reporting line, lifecycle hooks. Sibling to AIP-25 PERSONA (face) and AIP-23 IDENTITY (substance); referenced by AIP-9 OPERATOR (`role:` field) and AIP-6 COMPANY (`roles/<slug>/ROLE.md` doctype). Roles describe what a job is — independent of who holds it (persona/identity) and which instance is hired (operator).",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"agentproto",
|
|
7
|
+
"aip-47",
|
|
8
|
+
"role",
|
|
9
|
+
"defineRole",
|
|
10
|
+
"open-standard",
|
|
11
|
+
"agentic"
|
|
12
|
+
],
|
|
13
|
+
"homepage": "https://agentproto.sh/docs/aip-47",
|
|
14
|
+
"repository": {
|
|
15
|
+
"type": "git",
|
|
16
|
+
"url": "https://github.com/agentproto/ts",
|
|
17
|
+
"directory": "packages/role"
|
|
18
|
+
},
|
|
19
|
+
"bugs": {
|
|
20
|
+
"url": "https://github.com/agentproto/ts/issues"
|
|
21
|
+
},
|
|
22
|
+
"license": "MIT",
|
|
23
|
+
"type": "module",
|
|
24
|
+
"main": "dist/index.mjs",
|
|
25
|
+
"module": "dist/index.mjs",
|
|
26
|
+
"types": "dist/index.d.ts",
|
|
27
|
+
"exports": {
|
|
28
|
+
".": {
|
|
29
|
+
"types": "./dist/index.d.ts",
|
|
30
|
+
"import": "./dist/index.mjs",
|
|
31
|
+
"default": "./dist/index.mjs"
|
|
32
|
+
},
|
|
33
|
+
"./manifest": {
|
|
34
|
+
"types": "./dist/manifest/index.d.ts",
|
|
35
|
+
"import": "./dist/manifest/index.mjs",
|
|
36
|
+
"default": "./dist/manifest/index.mjs"
|
|
37
|
+
},
|
|
38
|
+
"./package.json": "./package.json"
|
|
39
|
+
},
|
|
40
|
+
"files": [
|
|
41
|
+
"dist",
|
|
42
|
+
"README.md",
|
|
43
|
+
"LICENSE"
|
|
44
|
+
],
|
|
45
|
+
"publishConfig": {
|
|
46
|
+
"access": "public"
|
|
47
|
+
},
|
|
48
|
+
"dependencies": {
|
|
49
|
+
"gray-matter": "^4.0.3",
|
|
50
|
+
"zod": "^4.3.6",
|
|
51
|
+
"@agentproto/define-doctype": "0.1.0",
|
|
52
|
+
"@agentproto/registry": "0.1.0-alpha.1"
|
|
53
|
+
},
|
|
54
|
+
"devDependencies": {
|
|
55
|
+
"@types/node": "^25.1.0",
|
|
56
|
+
"tsup": "^8.5.1",
|
|
57
|
+
"typescript": "^5.9.3",
|
|
58
|
+
"vitest": "^3.2.4",
|
|
59
|
+
"@agentproto/tooling": "0.1.0-alpha.0"
|
|
60
|
+
},
|
|
61
|
+
"scripts": {
|
|
62
|
+
"dev": "tsup --watch",
|
|
63
|
+
"build": "tsup",
|
|
64
|
+
"clean": "rm -rf dist",
|
|
65
|
+
"check-types": "tsc --noEmit",
|
|
66
|
+
"test": "vitest run --passWithNoTests",
|
|
67
|
+
"test:watch": "vitest"
|
|
68
|
+
}
|
|
69
|
+
}
|