@agent-facets/core 0.1.2 → 0.2.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/CHANGELOG.md +20 -0
- package/package.json +6 -3
- package/src/__tests__/build-pipeline.test.ts +98 -13
- package/src/__tests__/content-hash.test.ts +9 -9
- package/src/__tests__/edit.test.ts +190 -0
- package/src/__tests__/facet-loader.test.ts +61 -10
- package/src/__tests__/facet-manifest.test.ts +9 -21
- package/src/build/content-hash.ts +1 -1
- package/src/build/pipeline.ts +55 -22
- package/src/build/validate-content.ts +50 -0
- package/src/edit/manifest-writer.ts +12 -0
- package/src/edit/reconcile.ts +77 -0
- package/src/edit/scanner.ts +57 -0
- package/src/front-matter.ts +58 -0
- package/src/index.ts +12 -7
- package/src/loaders/facet.ts +11 -13
- package/src/loaders/validate.ts +4 -2
- package/src/schemas/facet-manifest.ts +21 -47
|
@@ -2,7 +2,7 @@ import { type } from 'arktype'
|
|
|
2
2
|
|
|
3
3
|
// --- Sub-schemas ---
|
|
4
4
|
|
|
5
|
-
/** Skill descriptor — description is required, prompt resolved from skills/<name
|
|
5
|
+
/** Skill descriptor — description is required, prompt resolved from skills/<name>/SKILL.md */
|
|
6
6
|
const SkillDescriptor = type({
|
|
7
7
|
description: 'string',
|
|
8
8
|
'platforms?': type.Record('string', 'unknown'),
|
|
@@ -37,9 +37,11 @@ const ServerReference = type('string').or({ image: 'string' })
|
|
|
37
37
|
// --- Main schema ---
|
|
38
38
|
|
|
39
39
|
/**
|
|
40
|
-
* The
|
|
41
|
-
*
|
|
42
|
-
*
|
|
40
|
+
* The facet manifest schema — validates structure and business constraints.
|
|
41
|
+
*
|
|
42
|
+
* Structural validation covers field types and shapes. Narrow constraints enforce:
|
|
43
|
+
* 1. At least one text asset (skills, agents, commands, or facets) must be present
|
|
44
|
+
* 2. Selective facets entries must include at least one asset type selection
|
|
43
45
|
*/
|
|
44
46
|
export const FacetManifestSchema = type({
|
|
45
47
|
name: 'string',
|
|
@@ -51,63 +53,35 @@ export const FacetManifestSchema = type({
|
|
|
51
53
|
'commands?': type.Record('string', CommandDescriptor),
|
|
52
54
|
'facets?': FacetsEntry.array(),
|
|
53
55
|
'servers?': type.Record('string', ServerReference),
|
|
54
|
-
})
|
|
55
|
-
|
|
56
|
-
/** Inferred TypeScript type for a validated facet manifest */
|
|
57
|
-
export type FacetManifest = typeof FacetManifestSchema.infer
|
|
58
|
-
|
|
59
|
-
// --- Custom validation ---
|
|
60
|
-
|
|
61
|
-
export interface FacetManifestError {
|
|
62
|
-
path: string
|
|
63
|
-
message: string
|
|
64
|
-
expected: string
|
|
65
|
-
actual: string
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
/**
|
|
69
|
-
* Checks business-rule constraints that ArkType's structural validation cannot express:
|
|
70
|
-
* 1. At least one text asset must be present (skills, agents, commands, or facets)
|
|
71
|
-
* 2. Selective facets entries must include at least one asset type
|
|
72
|
-
*/
|
|
73
|
-
export function checkFacetManifestConstraints(manifest: FacetManifest): FacetManifestError[] {
|
|
74
|
-
const errors: FacetManifestError[] = []
|
|
75
|
-
|
|
56
|
+
}).narrow((data, ctx) => {
|
|
76
57
|
// Constraint 1: at least one text asset
|
|
77
|
-
const hasSkills =
|
|
78
|
-
const hasAgents =
|
|
79
|
-
const hasCommands =
|
|
80
|
-
const hasFacets =
|
|
58
|
+
const hasSkills = data.skills && Object.keys(data.skills).length > 0
|
|
59
|
+
const hasAgents = data.agents && Object.keys(data.agents).length > 0
|
|
60
|
+
const hasCommands = data.commands && Object.keys(data.commands).length > 0
|
|
61
|
+
const hasFacets = data.facets && data.facets.length > 0
|
|
81
62
|
|
|
82
63
|
if (!hasSkills && !hasAgents && !hasCommands && !hasFacets) {
|
|
83
|
-
|
|
84
|
-
path: '',
|
|
85
|
-
message: 'Manifest must include at least one text asset (skills, agents, commands, or facets)',
|
|
86
|
-
expected: 'at least one of: skills, agents, commands, facets',
|
|
87
|
-
actual: 'none present',
|
|
88
|
-
})
|
|
64
|
+
ctx.mustBe('Manifest must include at least one text asset (skills, agents, commands, or facets)')
|
|
89
65
|
}
|
|
90
66
|
|
|
91
67
|
// Constraint 2: selective facets entries must select at least one asset type
|
|
92
|
-
if (
|
|
93
|
-
for (let i = 0; i <
|
|
94
|
-
const entry =
|
|
68
|
+
if (data.facets) {
|
|
69
|
+
for (let i = 0; i < data.facets.length; i++) {
|
|
70
|
+
const entry = data.facets[i]
|
|
95
71
|
if (typeof entry === 'object') {
|
|
96
72
|
const hasSelectedSkills = entry.skills && entry.skills.length > 0
|
|
97
73
|
const hasSelectedAgents = entry.agents && entry.agents.length > 0
|
|
98
74
|
const hasSelectedCommands = entry.commands && entry.commands.length > 0
|
|
99
75
|
|
|
100
76
|
if (!hasSelectedSkills && !hasSelectedAgents && !hasSelectedCommands) {
|
|
101
|
-
|
|
102
|
-
path: `facets[${i}]`,
|
|
103
|
-
message: 'Selective facets entry must include at least one asset type (skills, agents, or commands)',
|
|
104
|
-
expected: 'at least one of: skills, agents, commands',
|
|
105
|
-
actual: 'none selected',
|
|
106
|
-
})
|
|
77
|
+
ctx.mustBe('Selective facets entry must include at least one asset type (skills, agents, or commands)')
|
|
107
78
|
}
|
|
108
79
|
}
|
|
109
80
|
}
|
|
110
81
|
}
|
|
111
82
|
|
|
112
|
-
return
|
|
113
|
-
}
|
|
83
|
+
return true
|
|
84
|
+
})
|
|
85
|
+
|
|
86
|
+
/** Inferred TypeScript type for a validated facet manifest */
|
|
87
|
+
export type FacetManifest = typeof FacetManifestSchema.infer
|