@clawmasons/shared 0.1.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/dist/index.d.ts +8 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +11 -0
- package/dist/index.js.map +1 -0
- package/dist/role/adapter.d.ts +29 -0
- package/dist/role/adapter.d.ts.map +1 -0
- package/dist/role/adapter.js +149 -0
- package/dist/role/adapter.js.map +1 -0
- package/dist/role/discovery.d.ts +38 -0
- package/dist/role/discovery.d.ts.map +1 -0
- package/dist/role/discovery.js +209 -0
- package/dist/role/discovery.js.map +1 -0
- package/dist/role/index.d.ts.map +1 -0
- package/dist/role/index.js +13 -0
- package/dist/role/index.js.map +1 -0
- package/dist/role/package-reader.d.ts +30 -0
- package/dist/role/package-reader.d.ts.map +1 -0
- package/dist/role/package-reader.js +223 -0
- package/dist/role/package-reader.js.map +1 -0
- package/dist/role/parser.d.ts +45 -0
- package/dist/role/parser.d.ts.map +1 -0
- package/dist/role/parser.js +241 -0
- package/dist/role/parser.js.map +1 -0
- package/dist/role/resource-scanner.d.ts +16 -0
- package/dist/role/resource-scanner.d.ts.map +1 -0
- package/dist/role/resource-scanner.js +43 -0
- package/dist/role/resource-scanner.js.map +1 -0
- package/dist/schemas/index.d.ts +7 -0
- package/dist/schemas/index.d.ts.map +1 -0
- package/dist/schemas/index.js +8 -0
- package/dist/schemas/index.js.map +1 -0
- package/dist/schemas/role-types.d.ts +564 -0
- package/dist/schemas/role-types.d.ts.map +1 -0
- package/dist/schemas/role-types.js +93 -0
- package/dist/schemas/role-types.js.map +1 -0
- package/dist/toolfilter.d.ts.map +1 -0
- package/dist/toolfilter.js +55 -0
- package/dist/toolfilter.js.map +1 -0
- package/dist/types/role.d.ts +14 -0
- package/dist/types/role.d.ts.map +1 -0
- package/dist/types/role.js +2 -0
- package/dist/types/role.js.map +1 -0
- package/dist/types.d.ts +106 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/package.json +29 -0
|
@@ -0,0 +1,223 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Package Reader — reads an NPM role package and produces a Role object.
|
|
3
|
+
*
|
|
4
|
+
* Steps:
|
|
5
|
+
* 1. Read package.json and verify chapter.type === "role"
|
|
6
|
+
* 2. Read the bundled ROLE.md from the package directory
|
|
7
|
+
* 3. Parse frontmatter and body (reuses parseFrontmatter from parser.ts)
|
|
8
|
+
* 4. Normalize fields using dialect mapping if chapter.dialect is specified,
|
|
9
|
+
* otherwise use generic ROLE_TYPES field names directly
|
|
10
|
+
* 5. Resolve all paths relative to the package directory
|
|
11
|
+
* 6. Set source.type = 'package' and source.packageName
|
|
12
|
+
* 7. Validate through roleSchema
|
|
13
|
+
*/
|
|
14
|
+
import { readFile } from "node:fs/promises";
|
|
15
|
+
import { join, basename, resolve } from "node:path";
|
|
16
|
+
import { roleSchema } from "../schemas/role-types.js";
|
|
17
|
+
import { parseFrontmatter } from "./parser.js";
|
|
18
|
+
import { scanBundledResources } from "./resource-scanner.js";
|
|
19
|
+
import { getDialect } from "./dialect-registry.js";
|
|
20
|
+
/**
|
|
21
|
+
* Error thrown when a role NPM package cannot be read.
|
|
22
|
+
*/
|
|
23
|
+
export class PackageReadError extends Error {
|
|
24
|
+
packagePath;
|
|
25
|
+
constructor(message, packagePath) {
|
|
26
|
+
super(`${message} (at ${packagePath})`);
|
|
27
|
+
this.packagePath = packagePath;
|
|
28
|
+
this.name = "PackageReadError";
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Generic field mapping — packaged roles use ROLE_TYPES generic names directly.
|
|
33
|
+
*/
|
|
34
|
+
const GENERIC_FIELD_MAPPING = {
|
|
35
|
+
name: "generic",
|
|
36
|
+
directory: "",
|
|
37
|
+
fieldMapping: {
|
|
38
|
+
tasks: "tasks",
|
|
39
|
+
apps: "apps",
|
|
40
|
+
skills: "skills",
|
|
41
|
+
},
|
|
42
|
+
};
|
|
43
|
+
/**
|
|
44
|
+
* Read an NPM role package and produce a validated Role object.
|
|
45
|
+
*
|
|
46
|
+
* @param packagePath - Absolute path to the package directory (e.g., node_modules/@acme/role-create-prd)
|
|
47
|
+
* @returns Validated Role with source.type = 'package'
|
|
48
|
+
* @throws PackageReadError if the package is missing required files or has wrong chapter.type
|
|
49
|
+
*/
|
|
50
|
+
export async function readPackagedRole(packagePath) {
|
|
51
|
+
// 1. Read and validate package.json
|
|
52
|
+
const pkgJson = await readPackageJson(packagePath);
|
|
53
|
+
if (!pkgJson.chapter || pkgJson.chapter.type !== "role") {
|
|
54
|
+
throw new PackageReadError(`Package "${pkgJson.name}" does not have chapter.type = "role" (got: ${pkgJson.chapter?.type ?? "undefined"})`, packagePath);
|
|
55
|
+
}
|
|
56
|
+
// 2. Read ROLE.md
|
|
57
|
+
const roleMdPath = join(packagePath, "ROLE.md");
|
|
58
|
+
let roleMdContent;
|
|
59
|
+
try {
|
|
60
|
+
roleMdContent = await readFile(roleMdPath, "utf-8");
|
|
61
|
+
}
|
|
62
|
+
catch {
|
|
63
|
+
throw new PackageReadError(`Package "${pkgJson.name}" is missing ROLE.md`, packagePath);
|
|
64
|
+
}
|
|
65
|
+
// 3. Parse frontmatter and body
|
|
66
|
+
const { frontmatter, body } = parseFrontmatter(roleMdContent, roleMdPath);
|
|
67
|
+
// 4. Determine field mapping
|
|
68
|
+
const dialect = resolveDialect(pkgJson, packagePath);
|
|
69
|
+
// 5. Extract metadata
|
|
70
|
+
const roleName = frontmatter.name ?? pkgJson.name;
|
|
71
|
+
const metadata = {
|
|
72
|
+
name: roleName,
|
|
73
|
+
description: frontmatter.description,
|
|
74
|
+
version: frontmatter.version ?? pkgJson.version,
|
|
75
|
+
scope: frontmatter.scope,
|
|
76
|
+
};
|
|
77
|
+
if (!metadata.description) {
|
|
78
|
+
throw new PackageReadError(`Package "${pkgJson.name}" ROLE.md is missing required field: description`, packagePath);
|
|
79
|
+
}
|
|
80
|
+
// 6. Normalize fields using dialect mapping
|
|
81
|
+
const tasks = normalizeField(frontmatter, dialect.fieldMapping.tasks);
|
|
82
|
+
const apps = normalizeApps(frontmatter, dialect.fieldMapping.apps);
|
|
83
|
+
const skills = normalizeSkills(frontmatter, dialect.fieldMapping.skills, packagePath);
|
|
84
|
+
// 7. Container requirements (pass-through)
|
|
85
|
+
const container = frontmatter.container ?? {};
|
|
86
|
+
// 8. Governance (assembled from top-level fields)
|
|
87
|
+
const governance = {};
|
|
88
|
+
if (frontmatter.risk !== undefined)
|
|
89
|
+
governance.risk = frontmatter.risk;
|
|
90
|
+
if (frontmatter.credentials !== undefined)
|
|
91
|
+
governance.credentials = frontmatter.credentials;
|
|
92
|
+
if (frontmatter.constraints !== undefined)
|
|
93
|
+
governance.constraints = frontmatter.constraints;
|
|
94
|
+
// 9. Scan bundled resources
|
|
95
|
+
const resources = await scanBundledResources(packagePath);
|
|
96
|
+
// 10. Build and validate
|
|
97
|
+
const roleData = {
|
|
98
|
+
metadata,
|
|
99
|
+
instructions: body,
|
|
100
|
+
type: frontmatter.type,
|
|
101
|
+
tasks,
|
|
102
|
+
apps,
|
|
103
|
+
skills,
|
|
104
|
+
container,
|
|
105
|
+
governance,
|
|
106
|
+
resources,
|
|
107
|
+
source: {
|
|
108
|
+
type: "package",
|
|
109
|
+
packageName: pkgJson.name,
|
|
110
|
+
},
|
|
111
|
+
};
|
|
112
|
+
return roleSchema.parse(roleData);
|
|
113
|
+
}
|
|
114
|
+
// ---------------------------------------------------------------------------
|
|
115
|
+
// Helpers
|
|
116
|
+
// ---------------------------------------------------------------------------
|
|
117
|
+
/**
|
|
118
|
+
* Read and parse package.json from a package directory.
|
|
119
|
+
*/
|
|
120
|
+
async function readPackageJson(packagePath) {
|
|
121
|
+
const pkgJsonPath = join(packagePath, "package.json");
|
|
122
|
+
let raw;
|
|
123
|
+
try {
|
|
124
|
+
raw = await readFile(pkgJsonPath, "utf-8");
|
|
125
|
+
}
|
|
126
|
+
catch {
|
|
127
|
+
throw new PackageReadError("Missing package.json", packagePath);
|
|
128
|
+
}
|
|
129
|
+
try {
|
|
130
|
+
const parsed = JSON.parse(raw);
|
|
131
|
+
if (!parsed.name) {
|
|
132
|
+
throw new PackageReadError("package.json is missing required field: name", packagePath);
|
|
133
|
+
}
|
|
134
|
+
return parsed;
|
|
135
|
+
}
|
|
136
|
+
catch (err) {
|
|
137
|
+
if (err instanceof PackageReadError)
|
|
138
|
+
throw err;
|
|
139
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
140
|
+
throw new PackageReadError(`Invalid package.json: ${msg}`, packagePath);
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
/**
|
|
144
|
+
* Resolve the dialect to use for field normalization.
|
|
145
|
+
* If chapter.dialect is specified, use that dialect's mapping.
|
|
146
|
+
* Otherwise, use generic ROLE_TYPES field names.
|
|
147
|
+
*/
|
|
148
|
+
function resolveDialect(pkgJson, packagePath) {
|
|
149
|
+
const dialectName = pkgJson.chapter?.dialect;
|
|
150
|
+
if (!dialectName)
|
|
151
|
+
return GENERIC_FIELD_MAPPING;
|
|
152
|
+
const dialect = getDialect(dialectName);
|
|
153
|
+
if (!dialect) {
|
|
154
|
+
throw new PackageReadError(`Unknown dialect "${dialectName}" specified in chapter.dialect`, packagePath);
|
|
155
|
+
}
|
|
156
|
+
return dialect;
|
|
157
|
+
}
|
|
158
|
+
/**
|
|
159
|
+
* Normalize a simple list field (tasks).
|
|
160
|
+
*/
|
|
161
|
+
function normalizeField(frontmatter, fieldName) {
|
|
162
|
+
const raw = frontmatter[fieldName];
|
|
163
|
+
if (!raw)
|
|
164
|
+
return [];
|
|
165
|
+
if (!Array.isArray(raw)) {
|
|
166
|
+
return [{ name: String(raw) }];
|
|
167
|
+
}
|
|
168
|
+
return raw.map((item) => {
|
|
169
|
+
if (typeof item === "string") {
|
|
170
|
+
return { name: item };
|
|
171
|
+
}
|
|
172
|
+
if (typeof item === "object" && item !== null && "name" in item) {
|
|
173
|
+
return item;
|
|
174
|
+
}
|
|
175
|
+
return { name: String(item) };
|
|
176
|
+
});
|
|
177
|
+
}
|
|
178
|
+
/**
|
|
179
|
+
* Normalize apps field.
|
|
180
|
+
*/
|
|
181
|
+
function normalizeApps(frontmatter, fieldName) {
|
|
182
|
+
const raw = frontmatter[fieldName];
|
|
183
|
+
if (!raw)
|
|
184
|
+
return [];
|
|
185
|
+
if (!Array.isArray(raw))
|
|
186
|
+
return [];
|
|
187
|
+
return raw.map((item) => {
|
|
188
|
+
if (typeof item === "object" && item !== null) {
|
|
189
|
+
return item;
|
|
190
|
+
}
|
|
191
|
+
return { name: String(item) };
|
|
192
|
+
});
|
|
193
|
+
}
|
|
194
|
+
/**
|
|
195
|
+
* Normalize skills field with path resolution relative to package directory.
|
|
196
|
+
*/
|
|
197
|
+
function normalizeSkills(frontmatter, fieldName, packageDir) {
|
|
198
|
+
const raw = frontmatter[fieldName];
|
|
199
|
+
if (!raw)
|
|
200
|
+
return [];
|
|
201
|
+
if (!Array.isArray(raw))
|
|
202
|
+
return [];
|
|
203
|
+
return raw.map((item) => {
|
|
204
|
+
if (typeof item === "string") {
|
|
205
|
+
// Local path reference — resolve relative to package directory
|
|
206
|
+
if (item.startsWith("./") || item.startsWith("../")) {
|
|
207
|
+
const resolvedPath = resolve(packageDir, item);
|
|
208
|
+
const name = basename(resolvedPath);
|
|
209
|
+
return { name, ref: resolvedPath };
|
|
210
|
+
}
|
|
211
|
+
// Package reference — extract short name
|
|
212
|
+
const name = item.startsWith("@")
|
|
213
|
+
? item.split("/").pop() ?? item
|
|
214
|
+
: item;
|
|
215
|
+
return { name, ref: item };
|
|
216
|
+
}
|
|
217
|
+
if (typeof item === "object" && item !== null && "name" in item) {
|
|
218
|
+
return item;
|
|
219
|
+
}
|
|
220
|
+
return { name: String(item) };
|
|
221
|
+
});
|
|
222
|
+
}
|
|
223
|
+
//# sourceMappingURL=package-reader.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"package-reader.js","sourceRoot":"","sources":["../../src/role/package-reader.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ROLE.md Parser — reads a local ROLE.md file and produces a Role object.
|
|
3
|
+
*
|
|
4
|
+
* Steps:
|
|
5
|
+
* 1. Detect the agent dialect from the parent directory structure
|
|
6
|
+
* 2. Parse YAML frontmatter and extract markdown body as instructions
|
|
7
|
+
* 3. Normalize agent-specific field names to generic ROLE_TYPES names
|
|
8
|
+
* 4. Resolve bundled resource paths
|
|
9
|
+
* 5. Resolve dependency references
|
|
10
|
+
* 6. Validate through roleSchema
|
|
11
|
+
*/
|
|
12
|
+
import type { Role } from "../types/role.js";
|
|
13
|
+
import { type DialectEntry } from "./dialect-registry.js";
|
|
14
|
+
/**
|
|
15
|
+
* Parse error thrown when ROLE.md is malformed.
|
|
16
|
+
*/
|
|
17
|
+
export declare class RoleParseError extends Error {
|
|
18
|
+
readonly rolePath: string;
|
|
19
|
+
constructor(message: string, rolePath: string);
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Read a local ROLE.md file and produce a validated Role object.
|
|
23
|
+
*
|
|
24
|
+
* @param rolePath - Absolute path to the ROLE.md file
|
|
25
|
+
* @returns Validated Role
|
|
26
|
+
* @throws RoleParseError if the file is malformed or dialect cannot be detected
|
|
27
|
+
*/
|
|
28
|
+
export declare function readMaterializedRole(rolePath: string): Promise<Role>;
|
|
29
|
+
interface ParsedFrontmatter {
|
|
30
|
+
frontmatter: Record<string, unknown>;
|
|
31
|
+
body: string;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Parse YAML frontmatter delimited by `---` markers.
|
|
35
|
+
*/
|
|
36
|
+
export declare function parseFrontmatter(content: string, rolePath: string): ParsedFrontmatter;
|
|
37
|
+
/**
|
|
38
|
+
* Detect the agent dialect from the role's directory structure.
|
|
39
|
+
*
|
|
40
|
+
* Expected pattern: `<project>/.<agent>/roles/<role-name>/`
|
|
41
|
+
* We walk up from the role directory looking for a known agent directory.
|
|
42
|
+
*/
|
|
43
|
+
export declare function detectDialect(roleDir: string, rolePath: string): DialectEntry;
|
|
44
|
+
export {};
|
|
45
|
+
//# sourceMappingURL=parser.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"parser.d.ts","sourceRoot":"","sources":["../../src/role/parser.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAMH,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAC;AAC7C,OAAO,EAGL,KAAK,YAAY,EAClB,MAAM,uBAAuB,CAAC;AAG/B;;GAEG;AACH,qBAAa,cAAe,SAAQ,KAAK;aACM,QAAQ,EAAE,MAAM;gBAAjD,OAAO,EAAE,MAAM,EAAkB,QAAQ,EAAE,MAAM;CAI9D;AAED;;;;;;GAMG;AACH,wBAAsB,oBAAoB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAkE1E;AAMD,UAAU,iBAAiB;IACzB,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACrC,IAAI,EAAE,MAAM,CAAC;CACd;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,iBAAiB,CAyCrF;AAMD;;;;;GAKG;AACH,wBAAgB,aAAa,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,YAAY,CAiC7E"}
|
|
@@ -0,0 +1,241 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ROLE.md Parser — reads a local ROLE.md file and produces a Role object.
|
|
3
|
+
*
|
|
4
|
+
* Steps:
|
|
5
|
+
* 1. Detect the agent dialect from the parent directory structure
|
|
6
|
+
* 2. Parse YAML frontmatter and extract markdown body as instructions
|
|
7
|
+
* 3. Normalize agent-specific field names to generic ROLE_TYPES names
|
|
8
|
+
* 4. Resolve bundled resource paths
|
|
9
|
+
* 5. Resolve dependency references
|
|
10
|
+
* 6. Validate through roleSchema
|
|
11
|
+
*/
|
|
12
|
+
import { readFile } from "node:fs/promises";
|
|
13
|
+
import { dirname, basename, resolve } from "node:path";
|
|
14
|
+
import { load as yamlLoad } from "js-yaml";
|
|
15
|
+
import { roleSchema } from "../schemas/role-types.js";
|
|
16
|
+
import { getDialectByDirectory, getKnownDirectories, } from "./dialect-registry.js";
|
|
17
|
+
import { scanBundledResources } from "./resource-scanner.js";
|
|
18
|
+
/**
|
|
19
|
+
* Parse error thrown when ROLE.md is malformed.
|
|
20
|
+
*/
|
|
21
|
+
export class RoleParseError extends Error {
|
|
22
|
+
rolePath;
|
|
23
|
+
constructor(message, rolePath) {
|
|
24
|
+
super(`${message} (at ${rolePath})`);
|
|
25
|
+
this.rolePath = rolePath;
|
|
26
|
+
this.name = "RoleParseError";
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Read a local ROLE.md file and produce a validated Role object.
|
|
31
|
+
*
|
|
32
|
+
* @param rolePath - Absolute path to the ROLE.md file
|
|
33
|
+
* @returns Validated Role
|
|
34
|
+
* @throws RoleParseError if the file is malformed or dialect cannot be detected
|
|
35
|
+
*/
|
|
36
|
+
export async function readMaterializedRole(rolePath) {
|
|
37
|
+
// Read the file
|
|
38
|
+
const content = await readFile(rolePath, "utf-8");
|
|
39
|
+
// Parse frontmatter and body
|
|
40
|
+
const { frontmatter, body } = parseFrontmatter(content, rolePath);
|
|
41
|
+
// Detect dialect from directory structure
|
|
42
|
+
const roleDir = dirname(rolePath);
|
|
43
|
+
const dialect = detectDialect(roleDir, rolePath);
|
|
44
|
+
// Extract metadata
|
|
45
|
+
const roleName = frontmatter.name ?? basename(roleDir);
|
|
46
|
+
const metadata = {
|
|
47
|
+
name: roleName,
|
|
48
|
+
description: frontmatter.description,
|
|
49
|
+
version: frontmatter.version,
|
|
50
|
+
scope: frontmatter.scope,
|
|
51
|
+
};
|
|
52
|
+
if (!metadata.description) {
|
|
53
|
+
throw new RoleParseError("Missing required field: description", rolePath);
|
|
54
|
+
}
|
|
55
|
+
// Normalize fields using dialect mapping
|
|
56
|
+
const tasks = normalizeTasks(frontmatter, dialect);
|
|
57
|
+
const apps = normalizeApps(frontmatter, dialect);
|
|
58
|
+
const skills = normalizeSkills(frontmatter, dialect, roleDir);
|
|
59
|
+
// Container requirements (pass-through, no normalization needed)
|
|
60
|
+
const container = frontmatter.container ?? {};
|
|
61
|
+
// Governance (assembled from top-level fields)
|
|
62
|
+
const governance = {};
|
|
63
|
+
if (frontmatter.risk !== undefined)
|
|
64
|
+
governance.risk = frontmatter.risk;
|
|
65
|
+
if (frontmatter.credentials !== undefined)
|
|
66
|
+
governance.credentials = frontmatter.credentials;
|
|
67
|
+
if (frontmatter.constraints !== undefined)
|
|
68
|
+
governance.constraints = frontmatter.constraints;
|
|
69
|
+
// Scan bundled resources
|
|
70
|
+
const resources = await scanBundledResources(roleDir);
|
|
71
|
+
// Extract sources (canonical mason field)
|
|
72
|
+
const sources = Array.isArray(frontmatter.sources)
|
|
73
|
+
? frontmatter.sources
|
|
74
|
+
: [];
|
|
75
|
+
// Build the role object and validate through Zod
|
|
76
|
+
const roleData = {
|
|
77
|
+
metadata,
|
|
78
|
+
instructions: body,
|
|
79
|
+
type: frontmatter.type,
|
|
80
|
+
tasks,
|
|
81
|
+
apps,
|
|
82
|
+
skills,
|
|
83
|
+
sources,
|
|
84
|
+
container,
|
|
85
|
+
governance,
|
|
86
|
+
resources,
|
|
87
|
+
source: {
|
|
88
|
+
type: "local",
|
|
89
|
+
agentDialect: dialect.name,
|
|
90
|
+
path: roleDir,
|
|
91
|
+
},
|
|
92
|
+
};
|
|
93
|
+
return roleSchema.parse(roleData);
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Parse YAML frontmatter delimited by `---` markers.
|
|
97
|
+
*/
|
|
98
|
+
export function parseFrontmatter(content, rolePath) {
|
|
99
|
+
const trimmed = content.trimStart();
|
|
100
|
+
if (!trimmed.startsWith("---")) {
|
|
101
|
+
throw new RoleParseError("ROLE.md must start with YAML frontmatter (---)", rolePath);
|
|
102
|
+
}
|
|
103
|
+
// Find the closing ---
|
|
104
|
+
const endIndex = trimmed.indexOf("\n---", 3);
|
|
105
|
+
if (endIndex === -1) {
|
|
106
|
+
throw new RoleParseError("ROLE.md frontmatter is not closed (missing closing ---)", rolePath);
|
|
107
|
+
}
|
|
108
|
+
const yamlStr = trimmed.substring(3, endIndex).trim();
|
|
109
|
+
const body = trimmed.substring(endIndex + 4).trim(); // skip \n---
|
|
110
|
+
let frontmatter;
|
|
111
|
+
try {
|
|
112
|
+
frontmatter = yamlLoad(yamlStr);
|
|
113
|
+
}
|
|
114
|
+
catch (err) {
|
|
115
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
116
|
+
throw new RoleParseError(`Invalid YAML in frontmatter: ${msg}`, rolePath);
|
|
117
|
+
}
|
|
118
|
+
if (typeof frontmatter !== "object" || frontmatter === null || Array.isArray(frontmatter)) {
|
|
119
|
+
throw new RoleParseError("Frontmatter must be a YAML mapping (key-value pairs)", rolePath);
|
|
120
|
+
}
|
|
121
|
+
return {
|
|
122
|
+
frontmatter: frontmatter,
|
|
123
|
+
body,
|
|
124
|
+
};
|
|
125
|
+
}
|
|
126
|
+
// ---------------------------------------------------------------------------
|
|
127
|
+
// Dialect detection
|
|
128
|
+
// ---------------------------------------------------------------------------
|
|
129
|
+
/**
|
|
130
|
+
* Detect the agent dialect from the role's directory structure.
|
|
131
|
+
*
|
|
132
|
+
* Expected pattern: `<project>/.<agent>/roles/<role-name>/`
|
|
133
|
+
* We walk up from the role directory looking for a known agent directory.
|
|
134
|
+
*/
|
|
135
|
+
export function detectDialect(roleDir, rolePath) {
|
|
136
|
+
// roleDir = /path/to/project/.claude/roles/my-role
|
|
137
|
+
// We expect the parent of "roles" to be the agent directory
|
|
138
|
+
const rolesParent = dirname(roleDir); // .../roles
|
|
139
|
+
const agentDir = dirname(rolesParent); // .../.claude
|
|
140
|
+
// Check that we're inside a "roles" directory
|
|
141
|
+
if (basename(rolesParent) !== "roles") {
|
|
142
|
+
throw new RoleParseError(`ROLE.md must be inside a roles/ directory (expected <project>/.<agent>/roles/<role-name>/ROLE.md)`, rolePath);
|
|
143
|
+
}
|
|
144
|
+
// Get the agent directory name (e.g., ".claude" → "claude")
|
|
145
|
+
const agentDirName = basename(agentDir);
|
|
146
|
+
if (!agentDirName.startsWith(".")) {
|
|
147
|
+
throw new RoleParseError(`Agent directory must start with a dot (got "${agentDirName}")`, rolePath);
|
|
148
|
+
}
|
|
149
|
+
const directoryKey = agentDirName.substring(1); // strip the dot
|
|
150
|
+
const dialect = getDialectByDirectory(directoryKey);
|
|
151
|
+
if (!dialect) {
|
|
152
|
+
throw new RoleParseError(`Unknown agent dialect for directory "${agentDirName}". Known directories: ${getKnownDirsForError()}`, rolePath);
|
|
153
|
+
}
|
|
154
|
+
return dialect;
|
|
155
|
+
}
|
|
156
|
+
function getKnownDirsForError() {
|
|
157
|
+
return getKnownDirectories()
|
|
158
|
+
.map((d) => `.${d}/`)
|
|
159
|
+
.join(", ");
|
|
160
|
+
}
|
|
161
|
+
// ---------------------------------------------------------------------------
|
|
162
|
+
// Field normalization
|
|
163
|
+
// ---------------------------------------------------------------------------
|
|
164
|
+
/**
|
|
165
|
+
* Normalize the dialect-specific tasks field.
|
|
166
|
+
* Claude: commands, Codex: instructions, Aider: conventions
|
|
167
|
+
* Returns raw objects — Zod validates and applies defaults.
|
|
168
|
+
*/
|
|
169
|
+
function normalizeTasks(frontmatter, dialect) {
|
|
170
|
+
const fieldName = dialect.fieldMapping.tasks;
|
|
171
|
+
const raw = frontmatter[fieldName];
|
|
172
|
+
if (!raw)
|
|
173
|
+
return [];
|
|
174
|
+
if (!Array.isArray(raw)) {
|
|
175
|
+
return [{ name: String(raw) }];
|
|
176
|
+
}
|
|
177
|
+
return raw.map((item) => {
|
|
178
|
+
if (typeof item === "string") {
|
|
179
|
+
return { name: item };
|
|
180
|
+
}
|
|
181
|
+
if (typeof item === "object" && item !== null && "name" in item) {
|
|
182
|
+
return item;
|
|
183
|
+
}
|
|
184
|
+
return { name: String(item) };
|
|
185
|
+
});
|
|
186
|
+
}
|
|
187
|
+
/**
|
|
188
|
+
* Normalize the dialect-specific apps field.
|
|
189
|
+
* All dialects currently use mcp_servers.
|
|
190
|
+
* Returns raw objects — Zod validates and applies defaults.
|
|
191
|
+
*/
|
|
192
|
+
function normalizeApps(frontmatter, dialect) {
|
|
193
|
+
const fieldName = dialect.fieldMapping.apps;
|
|
194
|
+
const raw = frontmatter[fieldName];
|
|
195
|
+
if (!raw)
|
|
196
|
+
return [];
|
|
197
|
+
if (!Array.isArray(raw))
|
|
198
|
+
return [];
|
|
199
|
+
return raw.map((item) => {
|
|
200
|
+
if (typeof item === "object" && item !== null) {
|
|
201
|
+
return item;
|
|
202
|
+
}
|
|
203
|
+
// String shorthand — just a server name
|
|
204
|
+
return { name: String(item) };
|
|
205
|
+
});
|
|
206
|
+
}
|
|
207
|
+
/**
|
|
208
|
+
* Normalize the dialect-specific skills field.
|
|
209
|
+
* All dialects currently use "skills".
|
|
210
|
+
* Returns raw objects — Zod validates and applies defaults.
|
|
211
|
+
*/
|
|
212
|
+
function normalizeSkills(frontmatter, dialect, roleDir) {
|
|
213
|
+
const fieldName = dialect.fieldMapping.skills;
|
|
214
|
+
const raw = frontmatter[fieldName];
|
|
215
|
+
if (!raw)
|
|
216
|
+
return [];
|
|
217
|
+
if (!Array.isArray(raw))
|
|
218
|
+
return [];
|
|
219
|
+
// Find the project root (parent of the agent directory)
|
|
220
|
+
const projectRoot = resolve(roleDir, "..", "..", "..");
|
|
221
|
+
return raw.map((item) => {
|
|
222
|
+
if (typeof item === "string") {
|
|
223
|
+
// Local path reference — resolve relative to project root
|
|
224
|
+
if (item.startsWith("./") || item.startsWith("../")) {
|
|
225
|
+
const resolvedPath = resolve(projectRoot, item);
|
|
226
|
+
const name = basename(resolvedPath);
|
|
227
|
+
return { name, ref: resolvedPath };
|
|
228
|
+
}
|
|
229
|
+
// Package reference — extract short name
|
|
230
|
+
const name = item.startsWith("@")
|
|
231
|
+
? item.split("/").pop() ?? item
|
|
232
|
+
: item;
|
|
233
|
+
return { name, ref: item };
|
|
234
|
+
}
|
|
235
|
+
if (typeof item === "object" && item !== null && "name" in item) {
|
|
236
|
+
return item;
|
|
237
|
+
}
|
|
238
|
+
return { name: String(item) };
|
|
239
|
+
});
|
|
240
|
+
}
|
|
241
|
+
//# sourceMappingURL=parser.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"parser.js","sourceRoot":"","sources":["../../src/role/parser.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAC5C,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACvD,OAAO,EAAE,IAAI,IAAI,QAAQ,EAAE,MAAM,SAAS,CAAC;AAC3C,OAAO,EAAE,UAAU,EAAE,MAAM,0BAA0B,CAAC;AAEtD,OAAO,EACL,qBAAqB,EACrB,mBAAmB,GAEpB,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EAAE,oBAAoB,EAAE,MAAM,uBAAuB,CAAC;AAE7D;;GAEG;AACH,MAAM,OAAO,cAAe,SAAQ,KAAK;IACM;IAA7C,YAAY,OAAe,EAAkB,QAAgB;QAC3D,KAAK,CAAC,GAAG,OAAO,QAAQ,QAAQ,GAAG,CAAC,CAAC;QADM,aAAQ,GAAR,QAAQ,CAAQ;QAE3D,IAAI,CAAC,IAAI,GAAG,gBAAgB,CAAC;IAC/B,CAAC;CACF;AAED;;;;;;GAMG;AACH,MAAM,CAAC,KAAK,UAAU,oBAAoB,CAAC,QAAgB;IACzD,gBAAgB;IAChB,MAAM,OAAO,GAAG,MAAM,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;IAElD,6BAA6B;IAC7B,MAAM,EAAE,WAAW,EAAE,IAAI,EAAE,GAAG,gBAAgB,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC;IAElE,0CAA0C;IAC1C,MAAM,OAAO,GAAG,OAAO,CAAC,QAAQ,CAAC,CAAC;IAClC,MAAM,OAAO,GAAG,aAAa,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC;IAEjD,mBAAmB;IACnB,MAAM,QAAQ,GAAG,WAAW,CAAC,IAAI,IAAI,QAAQ,CAAC,OAAO,CAAC,CAAC;IACvD,MAAM,QAAQ,GAAG;QACf,IAAI,EAAE,QAAQ;QACd,WAAW,EAAE,WAAW,CAAC,WAAiC;QAC1D,OAAO,EAAE,WAAW,CAAC,OAA6B;QAClD,KAAK,EAAE,WAAW,CAAC,KAA2B;KAC/C,CAAC;IAEF,IAAI,CAAC,QAAQ,CAAC,WAAW,EAAE,CAAC;QAC1B,MAAM,IAAI,cAAc,CAAC,qCAAqC,EAAE,QAAQ,CAAC,CAAC;IAC5E,CAAC;IAED,yCAAyC;IACzC,MAAM,KAAK,GAAG,cAAc,CAAC,WAAW,EAAE,OAAO,CAAC,CAAC;IACnD,MAAM,IAAI,GAAG,aAAa,CAAC,WAAW,EAAE,OAAO,CAAC,CAAC;IACjD,MAAM,MAAM,GAAG,eAAe,CAAC,WAAW,EAAE,OAAO,EAAE,OAAO,CAAC,CAAC;IAE9D,iEAAiE;IACjE,MAAM,SAAS,GAAG,WAAW,CAAC,SAAS,IAAI,EAAE,CAAC;IAE9C,+CAA+C;IAC/C,MAAM,UAAU,GAA4B,EAAE,CAAC;IAC/C,IAAI,WAAW,CAAC,IAAI,KAAK,SAAS;QAAE,UAAU,CAAC,IAAI,GAAG,WAAW,CAAC,IAAI,CAAC;IACvE,IAAI,WAAW,CAAC,WAAW,KAAK,SAAS;QAAE,UAAU,CAAC,WAAW,GAAG,WAAW,CAAC,WAAW,CAAC;IAC5F,IAAI,WAAW,CAAC,WAAW,KAAK,SAAS;QAAE,UAAU,CAAC,WAAW,GAAG,WAAW,CAAC,WAAW,CAAC;IAE5F,yBAAyB;IACzB,MAAM,SAAS,GAAG,MAAM,oBAAoB,CAAC,OAAO,CAAC,CAAC;IAEtD,0CAA0C;IAC1C,MAAM,OAAO,GAAG,KAAK,CAAC,OAAO,CAAC,WAAW,CAAC,OAAO,CAAC;QAChD,CAAC,CAAE,WAAW,CAAC,OAAoB;QACnC,CAAC,CAAC,EAAE,CAAC;IAEP,iDAAiD;IACjD,MAAM,QAAQ,GAAG;QACf,QAAQ;QACR,YAAY,EAAE,IAAI;QAClB,IAAI,EAAE,WAAW,CAAC,IAA0B;QAC5C,KAAK;QACL,IAAI;QACJ,MAAM;QACN,OAAO;QACP,SAAS;QACT,UAAU;QACV,SAAS;QACT,MAAM,EAAE;YACN,IAAI,EAAE,OAAgB;YACtB,YAAY,EAAE,OAAO,CAAC,IAAI;YAC1B,IAAI,EAAE,OAAO;SACd;KACF,CAAC;IAEF,OAAO,UAAU,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;AACpC,CAAC;AAWD;;GAEG;AACH,MAAM,UAAU,gBAAgB,CAAC,OAAe,EAAE,QAAgB;IAChE,MAAM,OAAO,GAAG,OAAO,CAAC,SAAS,EAAE,CAAC;IAEpC,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,KAAK,CAAC,EAAE,CAAC;QAC/B,MAAM,IAAI,cAAc,CACtB,gDAAgD,EAChD,QAAQ,CACT,CAAC;IACJ,CAAC;IAED,uBAAuB;IACvB,MAAM,QAAQ,GAAG,OAAO,CAAC,OAAO,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC;IAC7C,IAAI,QAAQ,KAAK,CAAC,CAAC,EAAE,CAAC;QACpB,MAAM,IAAI,cAAc,CACtB,yDAAyD,EACzD,QAAQ,CACT,CAAC;IACJ,CAAC;IAED,MAAM,OAAO,GAAG,OAAO,CAAC,SAAS,CAAC,CAAC,EAAE,QAAQ,CAAC,CAAC,IAAI,EAAE,CAAC;IACtD,MAAM,IAAI,GAAG,OAAO,CAAC,SAAS,CAAC,QAAQ,GAAG,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,aAAa;IAElE,IAAI,WAAoB,CAAC;IACzB,IAAI,CAAC;QACH,WAAW,GAAG,QAAQ,CAAC,OAAO,CAAC,CAAC;IAClC,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,MAAM,GAAG,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;QAC7D,MAAM,IAAI,cAAc,CAAC,gCAAgC,GAAG,EAAE,EAAE,QAAQ,CAAC,CAAC;IAC5E,CAAC;IAED,IAAI,OAAO,WAAW,KAAK,QAAQ,IAAI,WAAW,KAAK,IAAI,IAAI,KAAK,CAAC,OAAO,CAAC,WAAW,CAAC,EAAE,CAAC;QAC1F,MAAM,IAAI,cAAc,CACtB,sDAAsD,EACtD,QAAQ,CACT,CAAC;IACJ,CAAC;IAED,OAAO;QACL,WAAW,EAAE,WAAsC;QACnD,IAAI;KACL,CAAC;AACJ,CAAC;AAED,8EAA8E;AAC9E,oBAAoB;AACpB,8EAA8E;AAE9E;;;;;GAKG;AACH,MAAM,UAAU,aAAa,CAAC,OAAe,EAAE,QAAgB;IAC7D,mDAAmD;IACnD,4DAA4D;IAC5D,MAAM,WAAW,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC,CAAE,YAAY;IACnD,MAAM,QAAQ,GAAG,OAAO,CAAC,WAAW,CAAC,CAAC,CAAC,cAAc;IAErD,8CAA8C;IAC9C,IAAI,QAAQ,CAAC,WAAW,CAAC,KAAK,OAAO,EAAE,CAAC;QACtC,MAAM,IAAI,cAAc,CACtB,mGAAmG,EACnG,QAAQ,CACT,CAAC;IACJ,CAAC;IAED,4DAA4D;IAC5D,MAAM,YAAY,GAAG,QAAQ,CAAC,QAAQ,CAAC,CAAC;IACxC,IAAI,CAAC,YAAY,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;QAClC,MAAM,IAAI,cAAc,CACtB,+CAA+C,YAAY,IAAI,EAC/D,QAAQ,CACT,CAAC;IACJ,CAAC;IAED,MAAM,YAAY,GAAG,YAAY,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,gBAAgB;IAChE,MAAM,OAAO,GAAG,qBAAqB,CAAC,YAAY,CAAC,CAAC;IACpD,IAAI,CAAC,OAAO,EAAE,CAAC;QACb,MAAM,IAAI,cAAc,CACtB,wCAAwC,YAAY,yBAAyB,oBAAoB,EAAE,EAAE,EACrG,QAAQ,CACT,CAAC;IACJ,CAAC;IAED,OAAO,OAAO,CAAC;AACjB,CAAC;AAED,SAAS,oBAAoB;IAC3B,OAAO,mBAAmB,EAAE;SACzB,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC;SACpB,IAAI,CAAC,IAAI,CAAC,CAAC;AAChB,CAAC;AAED,8EAA8E;AAC9E,sBAAsB;AACtB,8EAA8E;AAE9E;;;;GAIG;AACH,SAAS,cAAc,CACrB,WAAoC,EACpC,OAAqB;IAErB,MAAM,SAAS,GAAG,OAAO,CAAC,YAAY,CAAC,KAAK,CAAC;IAC7C,MAAM,GAAG,GAAG,WAAW,CAAC,SAAS,CAAC,CAAC;IACnC,IAAI,CAAC,GAAG;QAAE,OAAO,EAAE,CAAC;IAEpB,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC;QACxB,OAAO,CAAC,EAAE,IAAI,EAAE,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IACjC,CAAC;IAED,OAAO,GAAG,CAAC,GAAG,CAAC,CAAC,IAAa,EAAE,EAAE;QAC/B,IAAI,OAAO,IAAI,KAAK,QAAQ,EAAE,CAAC;YAC7B,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC;QACxB,CAAC;QACD,IAAI,OAAO,IAAI,KAAK,QAAQ,IAAI,IAAI,KAAK,IAAI,IAAI,MAAM,IAAI,IAAI,EAAE,CAAC;YAChE,OAAO,IAA+B,CAAC;QACzC,CAAC;QACD,OAAO,EAAE,IAAI,EAAE,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC;IAChC,CAAC,CAAC,CAAC;AACL,CAAC;AAED;;;;GAIG;AACH,SAAS,aAAa,CACpB,WAAoC,EACpC,OAAqB;IAErB,MAAM,SAAS,GAAG,OAAO,CAAC,YAAY,CAAC,IAAI,CAAC;IAC5C,MAAM,GAAG,GAAG,WAAW,CAAC,SAAS,CAAC,CAAC;IACnC,IAAI,CAAC,GAAG;QAAE,OAAO,EAAE,CAAC;IAEpB,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC;QAAE,OAAO,EAAE,CAAC;IAEnC,OAAO,GAAG,CAAC,GAAG,CAAC,CAAC,IAAa,EAAE,EAAE;QAC/B,IAAI,OAAO,IAAI,KAAK,QAAQ,IAAI,IAAI,KAAK,IAAI,EAAE,CAAC;YAC9C,OAAO,IAA+B,CAAC;QACzC,CAAC;QACD,wCAAwC;QACxC,OAAO,EAAE,IAAI,EAAE,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC;IAChC,CAAC,CAAC,CAAC;AACL,CAAC;AAED;;;;GAIG;AACH,SAAS,eAAe,CACtB,WAAoC,EACpC,OAAqB,EACrB,OAAe;IAEf,MAAM,SAAS,GAAG,OAAO,CAAC,YAAY,CAAC,MAAM,CAAC;IAC9C,MAAM,GAAG,GAAG,WAAW,CAAC,SAAS,CAAC,CAAC;IACnC,IAAI,CAAC,GAAG;QAAE,OAAO,EAAE,CAAC;IAEpB,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC;QAAE,OAAO,EAAE,CAAC;IAEnC,wDAAwD;IACxD,MAAM,WAAW,GAAG,OAAO,CAAC,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC;IAEvD,OAAO,GAAG,CAAC,GAAG,CAAC,CAAC,IAAa,EAAE,EAAE;QAC/B,IAAI,OAAO,IAAI,KAAK,QAAQ,EAAE,CAAC;YAC7B,0DAA0D;YAC1D,IAAI,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,IAAI,CAAC,UAAU,CAAC,KAAK,CAAC,EAAE,CAAC;gBACpD,MAAM,YAAY,GAAG,OAAO,CAAC,WAAW,EAAE,IAAI,CAAC,CAAC;gBAChD,MAAM,IAAI,GAAG,QAAQ,CAAC,YAAY,CAAC,CAAC;gBACpC,OAAO,EAAE,IAAI,EAAE,GAAG,EAAE,YAAY,EAAE,CAAC;YACrC,CAAC;YACD,yCAAyC;YACzC,MAAM,IAAI,GAAG,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC;gBAC/B,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,IAAI,IAAI;gBAC/B,CAAC,CAAC,IAAI,CAAC;YACT,OAAO,EAAE,IAAI,EAAE,GAAG,EAAE,IAAI,EAAE,CAAC;QAC7B,CAAC;QACD,IAAI,OAAO,IAAI,KAAK,QAAQ,IAAI,IAAI,KAAK,IAAI,IAAI,MAAM,IAAI,IAAI,EAAE,CAAC;YAChE,OAAO,IAA+B,CAAC;QACzC,CAAC;QACD,OAAO,EAAE,IAAI,EAAE,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC;IAChC,CAAC,CAAC,CAAC;AACL,CAAC"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Resource Scanner — discover bundled resources in a role directory.
|
|
3
|
+
*
|
|
4
|
+
* Recursively walks the role directory and returns ResourceFile entries for
|
|
5
|
+
* all files except ROLE.md itself. Only paths are stored — file content is
|
|
6
|
+
* never loaded into memory (per PRD §5.1).
|
|
7
|
+
*/
|
|
8
|
+
import type { ResourceFile } from "../types/role.js";
|
|
9
|
+
/**
|
|
10
|
+
* Recursively scan a role directory for bundled resources.
|
|
11
|
+
*
|
|
12
|
+
* @param roleDir - Absolute path to the role directory (contains ROLE.md)
|
|
13
|
+
* @returns Array of ResourceFile entries with relative and absolute paths
|
|
14
|
+
*/
|
|
15
|
+
export declare function scanBundledResources(roleDir: string): Promise<ResourceFile[]>;
|
|
16
|
+
//# sourceMappingURL=resource-scanner.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resource-scanner.d.ts","sourceRoot":"","sources":["../../src/role/resource-scanner.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAIH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAErD;;;;;GAKG;AACH,wBAAsB,oBAAoB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,EAAE,CAAC,CAInF"}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Resource Scanner — discover bundled resources in a role directory.
|
|
3
|
+
*
|
|
4
|
+
* Recursively walks the role directory and returns ResourceFile entries for
|
|
5
|
+
* all files except ROLE.md itself. Only paths are stored — file content is
|
|
6
|
+
* never loaded into memory (per PRD §5.1).
|
|
7
|
+
*/
|
|
8
|
+
import { readdir, stat } from "node:fs/promises";
|
|
9
|
+
import { join, relative } from "node:path";
|
|
10
|
+
/**
|
|
11
|
+
* Recursively scan a role directory for bundled resources.
|
|
12
|
+
*
|
|
13
|
+
* @param roleDir - Absolute path to the role directory (contains ROLE.md)
|
|
14
|
+
* @returns Array of ResourceFile entries with relative and absolute paths
|
|
15
|
+
*/
|
|
16
|
+
export async function scanBundledResources(roleDir) {
|
|
17
|
+
const resources = [];
|
|
18
|
+
await walkDirectory(roleDir, roleDir, resources);
|
|
19
|
+
return resources;
|
|
20
|
+
}
|
|
21
|
+
async function walkDirectory(baseDir, currentDir, results) {
|
|
22
|
+
const entries = await readdir(currentDir, { withFileTypes: true });
|
|
23
|
+
for (const entry of entries) {
|
|
24
|
+
const absolutePath = join(currentDir, entry.name);
|
|
25
|
+
const relativePath = relative(baseDir, absolutePath);
|
|
26
|
+
if (entry.isDirectory()) {
|
|
27
|
+
await walkDirectory(baseDir, absolutePath, results);
|
|
28
|
+
}
|
|
29
|
+
else if (entry.isFile()) {
|
|
30
|
+
// Skip ROLE.md itself
|
|
31
|
+
if (entry.name === "ROLE.md" && currentDir === baseDir) {
|
|
32
|
+
continue;
|
|
33
|
+
}
|
|
34
|
+
const fileStat = await stat(absolutePath);
|
|
35
|
+
results.push({
|
|
36
|
+
relativePath,
|
|
37
|
+
absolutePath,
|
|
38
|
+
permissions: fileStat.mode,
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
//# sourceMappingURL=resource-scanner.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resource-scanner.js","sourceRoot":"","sources":["../../src/role/resource-scanner.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAC;AACjD,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAC;AAG3C;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,oBAAoB,CAAC,OAAe;IACxD,MAAM,SAAS,GAAmB,EAAE,CAAC;IACrC,MAAM,aAAa,CAAC,OAAO,EAAE,OAAO,EAAE,SAAS,CAAC,CAAC;IACjD,OAAO,SAAS,CAAC;AACnB,CAAC;AAED,KAAK,UAAU,aAAa,CAC1B,OAAe,EACf,UAAkB,EAClB,OAAuB;IAEvB,MAAM,OAAO,GAAG,MAAM,OAAO,CAAC,UAAU,EAAE,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC,CAAC;IAEnE,KAAK,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC;QAC5B,MAAM,YAAY,GAAG,IAAI,CAAC,UAAU,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC;QAClD,MAAM,YAAY,GAAG,QAAQ,CAAC,OAAO,EAAE,YAAY,CAAC,CAAC;QAErD,IAAI,KAAK,CAAC,WAAW,EAAE,EAAE,CAAC;YACxB,MAAM,aAAa,CAAC,OAAO,EAAE,YAAY,EAAE,OAAO,CAAC,CAAC;QACtD,CAAC;aAAM,IAAI,KAAK,CAAC,MAAM,EAAE,EAAE,CAAC;YAC1B,sBAAsB;YACtB,IAAI,KAAK,CAAC,IAAI,KAAK,SAAS,IAAI,UAAU,KAAK,OAAO,EAAE,CAAC;gBACvD,SAAS;YACX,CAAC;YAED,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,YAAY,CAAC,CAAC;YAC1C,OAAO,CAAC,IAAI,CAAC;gBACX,YAAY;gBACZ,YAAY;gBACZ,WAAW,EAAE,QAAQ,CAAC,IAAI;aAC3B,CAAC,CAAC;QACL,CAAC;IACH,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export { appChapterFieldSchema, type AppChapterField } from "./app.js";
|
|
2
|
+
export { skillChapterFieldSchema, type SkillChapterField } from "./skill.js";
|
|
3
|
+
export { taskChapterFieldSchema, type TaskChapterField } from "./task.js";
|
|
4
|
+
export { roleChapterFieldSchema, type RoleChapterField } from "./role.js";
|
|
5
|
+
export { parseChapterField, type ChapterField } from "./chapter-field.js";
|
|
6
|
+
export { toolPermissionsSchema, roleMetadataSchema, taskRefSchema, skillRefSchema, appConfigSchema, mountConfigSchema, containerRequirementsSchema, governanceConfigSchema, resourceFileSchema, roleSourceSchema, roleSchema, } from "./role-types.js";
|
|
7
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/schemas/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,qBAAqB,EAAE,KAAK,eAAe,EAAE,MAAM,UAAU,CAAC;AACvE,OAAO,EAAE,uBAAuB,EAAE,KAAK,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAC7E,OAAO,EAAE,sBAAsB,EAAE,KAAK,gBAAgB,EAAE,MAAM,WAAW,CAAC;AAC1E,OAAO,EAAE,sBAAsB,EAAE,KAAK,gBAAgB,EAAE,MAAM,WAAW,CAAC;AAC1E,OAAO,EAAE,iBAAiB,EAAE,KAAK,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAG1E,OAAO,EACL,qBAAqB,EACrB,kBAAkB,EAClB,aAAa,EACb,cAAc,EACd,eAAe,EACf,iBAAiB,EACjB,2BAA2B,EAC3B,sBAAsB,EACtB,kBAAkB,EAClB,gBAAgB,EAChB,UAAU,GACX,MAAM,iBAAiB,CAAC"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export { appChapterFieldSchema } from "./app.js";
|
|
2
|
+
export { skillChapterFieldSchema } from "./skill.js";
|
|
3
|
+
export { taskChapterFieldSchema } from "./task.js";
|
|
4
|
+
export { roleChapterFieldSchema } from "./role.js";
|
|
5
|
+
export { parseChapterField } from "./chapter-field.js";
|
|
6
|
+
// ROLE_TYPES schemas
|
|
7
|
+
export { toolPermissionsSchema, roleMetadataSchema, taskRefSchema, skillRefSchema, appConfigSchema, mountConfigSchema, containerRequirementsSchema, governanceConfigSchema, resourceFileSchema, roleSourceSchema, roleSchema, } from "./role-types.js";
|
|
8
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/schemas/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,qBAAqB,EAAwB,MAAM,UAAU,CAAC;AACvE,OAAO,EAAE,uBAAuB,EAA0B,MAAM,YAAY,CAAC;AAC7E,OAAO,EAAE,sBAAsB,EAAyB,MAAM,WAAW,CAAC;AAC1E,OAAO,EAAE,sBAAsB,EAAyB,MAAM,WAAW,CAAC;AAC1E,OAAO,EAAE,iBAAiB,EAAqB,MAAM,oBAAoB,CAAC;AAE1E,qBAAqB;AACrB,OAAO,EACL,qBAAqB,EACrB,kBAAkB,EAClB,aAAa,EACb,cAAc,EACd,eAAe,EACf,iBAAiB,EACjB,2BAA2B,EAC3B,sBAAsB,EACtB,kBAAkB,EAClB,gBAAgB,EAChB,UAAU,GACX,MAAM,iBAAiB,CAAC"}
|