@graphorin/skills 0.5.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 +7 -0
- package/LICENSE +21 -0
- package/README.md +169 -0
- package/anthropic-spec-snapshot.json +114 -0
- package/dist/activation/index.d.ts +30 -0
- package/dist/activation/index.d.ts.map +1 -0
- package/dist/activation/index.js +71 -0
- package/dist/activation/index.js.map +1 -0
- package/dist/errors/index.d.ts +110 -0
- package/dist/errors/index.d.ts.map +1 -0
- package/dist/errors/index.js +126 -0
- package/dist/errors/index.js.map +1 -0
- package/dist/frontmatter/index.d.ts +120 -0
- package/dist/frontmatter/index.d.ts.map +1 -0
- package/dist/frontmatter/index.js +451 -0
- package/dist/frontmatter/index.js.map +1 -0
- package/dist/index.d.ts +52 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +51 -0
- package/dist/index.js.map +1 -0
- package/dist/loader/index.d.ts +55 -0
- package/dist/loader/index.d.ts.map +1 -0
- package/dist/loader/index.js +463 -0
- package/dist/loader/index.js.map +1 -0
- package/dist/migration/index.d.ts +62 -0
- package/dist/migration/index.d.ts.map +1 -0
- package/dist/migration/index.js +131 -0
- package/dist/migration/index.js.map +1 -0
- package/dist/registry/bridge.d.ts +47 -0
- package/dist/registry/bridge.d.ts.map +1 -0
- package/dist/registry/bridge.js +91 -0
- package/dist/registry/bridge.js.map +1 -0
- package/dist/registry/index.d.ts +140 -0
- package/dist/registry/index.d.ts.map +1 -0
- package/dist/registry/index.js +193 -0
- package/dist/registry/index.js.map +1 -0
- package/dist/spec/index.d.ts +92 -0
- package/dist/spec/index.d.ts.map +1 -0
- package/dist/spec/index.js +105 -0
- package/dist/spec/index.js.map +1 -0
- package/dist/types/index.d.ts +305 -0
- package/dist/types/index.d.ts.map +1 -0
- package/package.json +104 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","names":["lines: string[]","cues: string[]","matches: Skill[]","out: InlineSkillTool[]","request: Mutable<ActivationRequest>","out: ActivatedSkill[]","resources: ReadonlyArray<SkillResource>","stampedTools: ReadonlyArray<ResolvedTool>","out: RegisteredToolDeclaration[]"],"sources":["../../src/registry/index.ts"],"sourcesContent":["/**\n * `SkillRegistry` — registry over loaded skills.\n *\n * The registry is the surface the agent runtime (Phase 12) and the\n * standalone server (Phase 14) consume. It exposes:\n *\n * - `getMetadata()` — every skill's Tier-1 metadata, used by the\n * ContextEngine to assemble the system prompt's skill metadata\n * block (Phase 10d).\n * - `activate(triggers)` / `getActivationRequest(triggers)` —\n * match a list of trigger strings (slash commands and / or model-\n * emitted skill names) and return the corresponding\n * {@link ActivatedSkill} records.\n * - `getSkill(name)` — direct lookup.\n * - `tools()` — flat list of declared tool entries; the runtime\n * resolves the actual `Tool[]` through the `@graphorin/tools`\n * registry.\n *\n * @packageDocumentation\n */\n\nimport type { ResolvedTool } from '@graphorin/core';\nimport { parseSlashCommand } from '../activation/index.js';\nimport { SkillNameCollisionError, SlashCommandParseError } from '../errors/index.js';\n\nexport type { StampedSkillTool } from './bridge.js';\nexport { stampSkillTool, stampSkillToolFromMetadata } from './bridge.js';\n\nimport type {\n ActivatedSkill,\n InlineSkillTool,\n Skill,\n SkillMetadata,\n SkillResource,\n SkillToolDeclaration,\n} from '../types/index.js';\n\n/**\n * Stamping seam injected by the agent runtime (Phase 12). It turns a skill's\n * pre-built `Tool` into a fully resolved `ResolvedTool` (trust class + sandbox\n * tier + source). The skills package keeps no hard dependency on\n * `@graphorin/tools`; when no stamper is configured, `activate()` surfaces no\n * tools (the runtime resolves them itself).\n */\nexport type SkillToolStamper = (tool: InlineSkillTool, metadata: SkillMetadata) => ResolvedTool;\n\n/** Options accepted by {@link createSkillRegistry}. */\nexport interface SkillRegistryOptions {\n /**\n * Default activation behaviour. When `'metadata-only'` (default),\n * `activate(...)` returns the parsed activation request without\n * invoking `Skill.body()`; callers (the agent runtime) then invoke\n * the body resolver themselves so the runtime can attach a span.\n * When `'eager'`, the registry resolves the body before returning,\n * suitable for tests.\n */\n readonly activationStrategy?: 'metadata-only' | 'eager';\n /**\n * Optional stamping function (RP-11). When supplied, `activate()` runs each\n * skill's pre-built `Tool[]` through it and surfaces the results on\n * {@link ActivatedSkill.tools}. Without it, `activate()` surfaces no tools —\n * the agent runtime resolves and stamps them itself.\n */\n readonly stampTool?: SkillToolStamper;\n}\n\n/** Public registry surface. */\nexport interface SkillRegistry {\n register(skill: Skill): void;\n /**\n * Upsert a skill by name (RP-11). Unlike {@link SkillRegistry.register},\n * `replace` overwrites an existing registration instead of throwing on a\n * name collision — the upgrade path for hot-reloading a re-loaded skill.\n */\n replace(skill: Skill): void;\n unregister(name: string): boolean;\n getSkill(name: string): Skill | undefined;\n has(name: string): boolean;\n list(): ReadonlyArray<Skill>;\n getMetadata(): ReadonlyArray<SkillMetadata>;\n /**\n * Skills surfaced into the system prompt for auto-activation.\n * Skills with `disable-model-invocation: true` are excluded.\n */\n getAutoActivationMetadata(): ReadonlyArray<SkillMetadata>;\n /**\n * Render the auto-activation metadata as a string suitable for the\n * system prompt. The format is bytes-stable and consumed verbatim\n * by the ContextEngine layered template (Phase 10d). Skills with\n * `disable-model-invocation: true` are excluded.\n */\n getMetadataBlock(): string;\n /**\n * Resolve a single trigger (model-emitted skill name OR the raw\n * `/skill:<name>` slash-command body) into an {@link ActivationRequest}.\n * Returns `null` when no skill matches and the trigger looked like a\n * slash command — callers that want a strict mode should call\n * {@link parseActivationTrigger} themselves.\n */\n resolveTrigger(trigger: string): ActivationRequest | null;\n activate(\n triggers: ReadonlyArray<string>,\n signal?: AbortSignal,\n ): Promise<ReadonlyArray<ActivatedSkill>>;\n /**\n * Best-effort match: returns every skill whose name OR description\n * contains all of the supplied trigger tokens (case-insensitive).\n * The agent runtime uses this when the model emits a trigger phrase\n * that does not directly map to a skill name.\n */\n search(triggers: ReadonlyArray<string>): ReadonlyArray<Skill>;\n /**\n * Flat, deduplicated list of every pre-built tool shipped by the\n * registered skills. The first registration wins on a `tool.name`\n * collision; later collisions surface a one-time WARN through the\n * console so operators can resolve the conflict (Phase 12 will\n * route these through the audit emitter).\n */\n tools(): ReadonlyArray<InlineSkillTool>;\n toolDeclarations(): ReadonlyArray<RegisteredToolDeclaration>;\n size(): number;\n clear(): void;\n}\n\n/** Activation request produced by {@link SkillRegistry.resolveTrigger}. */\nexport interface ActivationRequest {\n readonly skill: Skill;\n readonly activationKind: ActivatedSkill['activationKind'];\n readonly args?: string;\n}\n\n/**\n * Tool-declaration record exposed by {@link SkillRegistry.toolDeclarations}.\n * Adds the owning skill's name and trust level so downstream\n * registrations into `@graphorin/tools` can stamp the source.\n *\n * @stable\n */\nexport interface RegisteredToolDeclaration extends SkillToolDeclaration {\n readonly skillName: string;\n readonly trustLevel: SkillMetadata['graphorinTrustLevel'];\n}\n\n/**\n * Build a fresh, empty registry. Multiple registries can co-exist\n * within a single process; the framework defaults to a single shared\n * instance per agent instance.\n *\n * @stable\n */\nexport function createSkillRegistry(options: SkillRegistryOptions = {}): SkillRegistry {\n const skillsByName = new Map<string, Skill>();\n const strategy = options.activationStrategy ?? 'metadata-only';\n\n function register(skill: Skill): void {\n if (skillsByName.has(skill.metadata.name)) {\n throw new SkillNameCollisionError(skill.metadata.name);\n }\n skillsByName.set(skill.metadata.name, skill);\n }\n\n function replace(skill: Skill): void {\n skillsByName.set(skill.metadata.name, skill);\n }\n\n function unregister(name: string): boolean {\n return skillsByName.delete(name);\n }\n\n function getSkill(name: string): Skill | undefined {\n return skillsByName.get(name);\n }\n\n function has(name: string): boolean {\n return skillsByName.has(name);\n }\n\n function list(): ReadonlyArray<Skill> {\n return Object.freeze([...skillsByName.values()]);\n }\n\n function getMetadata(): ReadonlyArray<SkillMetadata> {\n return Object.freeze([...skillsByName.values()].map((skill) => skill.metadata));\n }\n\n function getAutoActivationMetadata(): ReadonlyArray<SkillMetadata> {\n return Object.freeze(\n [...skillsByName.values()]\n .map((skill) => skill.metadata)\n .filter((metadata) => !metadata.disableModelInvocation),\n );\n }\n\n function getMetadataBlock(): string {\n const lines: string[] = [];\n const auto = getAutoActivationMetadata();\n if (auto.length === 0) return '';\n lines.push('# Available skills');\n lines.push('');\n for (const meta of auto) {\n lines.push(`## ${meta.name}`);\n lines.push('');\n const description = meta.description.replace(/\\s+/gu, ' ').trim();\n if (description.length > 0) lines.push(description);\n const cues: string[] = [];\n if (meta.allowedTools !== undefined && meta.allowedTools.length > 0) {\n cues.push(`Allowed tools: ${[...meta.allowedTools].join(', ')}`);\n }\n if (meta.graphorinSensitivity !== undefined) {\n cues.push(`Sensitivity: ${meta.graphorinSensitivity}`);\n }\n if (cues.length > 0) {\n lines.push('');\n for (const cue of cues) lines.push(`- ${cue}`);\n }\n lines.push('');\n }\n return lines.join('\\n').replace(/\\n+$/u, '\\n');\n }\n\n function search(triggers: ReadonlyArray<string>): ReadonlyArray<Skill> {\n const tokens = [...triggers]\n .flatMap((trigger) => trigger.toLowerCase().split(/\\s+/u))\n .filter((tok) => tok.length > 0);\n if (tokens.length === 0) return Object.freeze([]);\n const matches: Skill[] = [];\n const seen = new Set<string>();\n for (const skill of skillsByName.values()) {\n const haystack = `${skill.metadata.name}\\n${skill.metadata.description}`.toLowerCase();\n const isMatch = tokens.every((tok) => haystack.includes(tok));\n if (isMatch && !seen.has(skill.metadata.name)) {\n seen.add(skill.metadata.name);\n matches.push(skill);\n }\n }\n return Object.freeze(matches);\n }\n\n function tools(): ReadonlyArray<InlineSkillTool> {\n const seen = new Set<string>();\n const out: InlineSkillTool[] = [];\n const collisions = new Set<string>();\n for (const skill of skillsByName.values()) {\n for (const tool of skill.tools()) {\n if (seen.has(tool.name)) {\n if (!collisions.has(tool.name)) {\n collisions.add(tool.name);\n // eslint-disable-next-line no-console\n console.warn(\n `[graphorin/skills] Duplicate tool name '${tool.name}' across skills; first registration wins.`,\n );\n }\n continue;\n }\n seen.add(tool.name);\n out.push(tool);\n }\n }\n return Object.freeze(out);\n }\n\n function resolveTrigger(trigger: string): ActivationRequest | null {\n const parsed = parseActivationTrigger(trigger);\n const skill = skillsByName.get(parsed.name);\n if (skill === undefined) return null;\n if (parsed.activationKind === 'auto' && skill.metadata.disableModelInvocation) {\n // Auto-activation refused — the skill opted out.\n return null;\n }\n const request: Mutable<ActivationRequest> = {\n skill,\n activationKind: parsed.activationKind,\n };\n if (parsed.args !== undefined && parsed.args.length > 0) request.args = parsed.args;\n return Object.freeze(request);\n }\n\n async function activate(\n triggers: ReadonlyArray<string>,\n signal?: AbortSignal,\n ): Promise<ReadonlyArray<ActivatedSkill>> {\n const out: ActivatedSkill[] = [];\n const seen = new Set<string>();\n for (const trigger of triggers) {\n const request = resolveTrigger(trigger);\n if (request === null) continue;\n if (seen.has(request.skill.metadata.name)) continue;\n seen.add(request.skill.metadata.name);\n const body = strategy === 'eager' ? await request.skill.body(signal) : '';\n const resources: ReadonlyArray<SkillResource> =\n strategy === 'eager' ? await request.skill.resources(signal) : Object.freeze([]);\n // Pre-built tools (inline source) are surfaced via `Skill.tools()`.\n // When the caller wired a `stampTool` function (the agent runtime does),\n // each tool is stamped into a `ResolvedTool` and surfaced here; without\n // it the registry exposes no tools (the runtime resolves them itself).\n const stampedTools: ReadonlyArray<ResolvedTool> =\n options.stampTool !== undefined\n ? Object.freeze(\n request.skill\n .tools()\n .map((tool) =>\n (options.stampTool as SkillToolStamper)(tool, request.skill.metadata),\n ),\n )\n : Object.freeze([]);\n out.push(\n Object.freeze({\n skill: request.skill,\n body,\n resources,\n tools: stampedTools,\n activationKind: request.activationKind,\n activatedAt: Date.now(),\n }),\n );\n }\n return Object.freeze(out);\n }\n\n function toolDeclarations(): ReadonlyArray<RegisteredToolDeclaration> {\n const out: RegisteredToolDeclaration[] = [];\n for (const skill of skillsByName.values()) {\n for (const decl of skill.toolDeclarations()) {\n out.push(\n Object.freeze({\n ...decl,\n skillName: skill.metadata.name,\n trustLevel: skill.metadata.graphorinTrustLevel,\n }),\n );\n }\n }\n return Object.freeze(out);\n }\n\n function size(): number {\n return skillsByName.size;\n }\n\n function clear(): void {\n skillsByName.clear();\n }\n\n return Object.freeze({\n register,\n replace,\n unregister,\n getSkill,\n has,\n list,\n getMetadata,\n getAutoActivationMetadata,\n getMetadataBlock,\n resolveTrigger,\n activate,\n search,\n tools,\n toolDeclarations,\n size,\n clear,\n } satisfies SkillRegistry);\n}\n\n/**\n * Parsed activation trigger. The registry uses this to discriminate\n * slash-command activations (which override\n * `disable-model-invocation: true`) from model-emitted auto\n * activations (which honour it).\n *\n * @stable\n */\nexport interface ParsedActivationTrigger {\n readonly name: string;\n readonly activationKind: ActivatedSkill['activationKind'];\n readonly args?: string;\n}\n\n/**\n * Parse a single activation trigger. Slash-command bodies\n * (`/skill:<name>`) are routed through the slash parser; bare names\n * are treated as auto-activation requests emitted by the model.\n *\n * Throws {@link SlashCommandParseError} when the body looks like a\n * slash command but does not match the grammar (so the caller can\n * surface the error to the user).\n *\n * @stable\n */\nexport function parseActivationTrigger(raw: string): ParsedActivationTrigger {\n const trimmed = raw.trim();\n if (trimmed.startsWith('/skill:') || /^\\s*\\/skill:/u.test(raw)) {\n const parsed = parseSlashCommand(raw);\n return Object.freeze({\n name: parsed.name,\n activationKind: 'slash-command' as const,\n ...(parsed.args.length > 0 ? { args: parsed.args } : {}),\n });\n }\n if (trimmed.length === 0) {\n throw new SlashCommandParseError(raw, 'activation trigger must be non-empty.');\n }\n if (!/^[A-Za-z0-9][A-Za-z0-9_.-]{0,127}$/u.test(trimmed)) {\n throw new SlashCommandParseError(\n raw,\n 'auto-activation trigger must match /^[a-zA-Z0-9][a-zA-Z0-9_.-]{0,127}$/.',\n );\n }\n return Object.freeze({\n name: trimmed,\n activationKind: 'auto' as const,\n });\n}\n\ntype Mutable<T> = { -readonly [K in keyof T]: T[K] };\n"],"mappings":"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"}
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
//#region src/spec/index.d.ts
|
|
2
|
+
/**
|
|
3
|
+
* Bundled snapshot loader for the `SKILL.md` packaging-format
|
|
4
|
+
* specification.
|
|
5
|
+
*
|
|
6
|
+
* The framework ships an offline copy of the upstream specification
|
|
7
|
+
* so the loader can decide which frontmatter fields are recognised,
|
|
8
|
+
* which `graphorin-*` extensions deprecate (or co-exist with) an
|
|
9
|
+
* upstream field, and whether a skill author's
|
|
10
|
+
* `graphorin-anthropic-spec` hint refers to a snapshot newer or older
|
|
11
|
+
* than the bundled one. The snapshot is checked-in to the repository
|
|
12
|
+
* and refreshed via the `pnpm run check-anthropic-spec` CI cron.
|
|
13
|
+
*
|
|
14
|
+
* The loader does not fetch the upstream specification; the only
|
|
15
|
+
* network call lives inside the CI helper script. The snapshot lookup
|
|
16
|
+
* is deterministic and side-effect free at runtime.
|
|
17
|
+
*
|
|
18
|
+
* @packageDocumentation
|
|
19
|
+
*/
|
|
20
|
+
/** Stability classification of a known upstream field. */
|
|
21
|
+
type FieldStability = 'stable' | 'standardized' | 'experimental';
|
|
22
|
+
/** Migration policy applied to a `graphorin-*` field that maps to an upstream field. */
|
|
23
|
+
type GraphorinFieldPolicy = 'deprecate-graphorin-prefix' | 'co-exist' | 'graphorin-only';
|
|
24
|
+
/** Single entry of the upstream-known fields map. */
|
|
25
|
+
interface KnownFieldEntry {
|
|
26
|
+
readonly since: string;
|
|
27
|
+
readonly required: boolean;
|
|
28
|
+
readonly type: string;
|
|
29
|
+
readonly stability: FieldStability;
|
|
30
|
+
}
|
|
31
|
+
/** Single entry of the `graphorin-*` mapping map. */
|
|
32
|
+
interface GraphorinMappingEntry {
|
|
33
|
+
readonly anthropicEquivalent: string | null;
|
|
34
|
+
readonly policy: GraphorinFieldPolicy;
|
|
35
|
+
readonly since?: string;
|
|
36
|
+
readonly rationale?: string;
|
|
37
|
+
readonly deprecateAt?: string;
|
|
38
|
+
readonly removeAt?: string;
|
|
39
|
+
}
|
|
40
|
+
/** Top-level shape of the bundled snapshot. */
|
|
41
|
+
interface SpecSnapshot {
|
|
42
|
+
readonly snapshotDate: string;
|
|
43
|
+
readonly specSource: string;
|
|
44
|
+
readonly specCommit: string | null;
|
|
45
|
+
readonly rationale?: string;
|
|
46
|
+
readonly knownFields: Readonly<Record<string, KnownFieldEntry>>;
|
|
47
|
+
readonly graphorinMapping: Readonly<Record<string, GraphorinMappingEntry>>;
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Override the bundled snapshot. Used by tests that exercise the
|
|
51
|
+
* "newer / older spec snapshot" branches of the validator.
|
|
52
|
+
*
|
|
53
|
+
* @experimental
|
|
54
|
+
*/
|
|
55
|
+
declare function _setSpecSnapshotForTesting(snapshot: SpecSnapshot | null): void;
|
|
56
|
+
/**
|
|
57
|
+
* Return the currently active snapshot. Loads the bundled JSON file
|
|
58
|
+
* on first call, then caches the parsed object.
|
|
59
|
+
*
|
|
60
|
+
* @stable
|
|
61
|
+
*/
|
|
62
|
+
declare function getSpecSnapshot(): SpecSnapshot;
|
|
63
|
+
/**
|
|
64
|
+
* Resolve a known-field entry by name. Returns `undefined` if the
|
|
65
|
+
* field is not part of the upstream specification.
|
|
66
|
+
*
|
|
67
|
+
* @stable
|
|
68
|
+
*/
|
|
69
|
+
declare function getKnownField(field: string): KnownFieldEntry | undefined;
|
|
70
|
+
/**
|
|
71
|
+
* Resolve the mapping entry for a `graphorin-*` field. Returns
|
|
72
|
+
* `undefined` if the field is not known to the snapshot.
|
|
73
|
+
*
|
|
74
|
+
* @stable
|
|
75
|
+
*/
|
|
76
|
+
declare function getGraphorinMapping(field: string): GraphorinMappingEntry | undefined;
|
|
77
|
+
/**
|
|
78
|
+
* Compare an author's `graphorin-anthropic-spec` value against the
|
|
79
|
+
* bundled snapshot date. Returns:
|
|
80
|
+
*
|
|
81
|
+
* - `'same'` — the author targeted the same snapshot.
|
|
82
|
+
* - `'older'` — the author targeted an older snapshot.
|
|
83
|
+
* - `'newer'` — the author targeted a newer snapshot.
|
|
84
|
+
* - `'unparseable'` — the author's value could not be interpreted as
|
|
85
|
+
* an ISO-8601 date.
|
|
86
|
+
*
|
|
87
|
+
* @stable
|
|
88
|
+
*/
|
|
89
|
+
declare function compareAuthorSpecHint(authorValue: string): 'same' | 'older' | 'newer' | 'unparseable';
|
|
90
|
+
//#endregion
|
|
91
|
+
export { FieldStability, GraphorinFieldPolicy, GraphorinMappingEntry, KnownFieldEntry, SpecSnapshot, _setSpecSnapshotForTesting, compareAuthorSpecHint, getGraphorinMapping, getKnownField, getSpecSnapshot };
|
|
92
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","names":[],"sources":["../../src/spec/index.ts"],"sourcesContent":[],"mappings":";;AAwBA;AAGA;AAGA;AAQA;AAUA;;;;;;;;AAkBA;AAUA;AAkCA;AAUA;AAgBA;;KAhHY,cAAA;;KAGA,oBAAA;;UAGK,eAAA;;;;sBAIK;;;UAIL,qBAAA;;mBAEE;;;;;;;UAQF,YAAA;;;;;wBAKO,SAAS,eAAe;6BACnB,SAAS,eAAe;;;;;;;;iBAYrC,0BAAA,WAAqC;;;;;;;iBAUrC,eAAA,CAAA,GAAmB;;;;;;;iBAkCnB,aAAA,iBAA8B;;;;;;;iBAU9B,mBAAA,iBAAoC;;;;;;;;;;;;;iBAgBpC,qBAAA"}
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
import { readFileSync } from "node:fs";
|
|
2
|
+
import { dirname, join } from "node:path";
|
|
3
|
+
import { fileURLToPath } from "node:url";
|
|
4
|
+
|
|
5
|
+
//#region src/spec/index.ts
|
|
6
|
+
/**
|
|
7
|
+
* Bundled snapshot loader for the `SKILL.md` packaging-format
|
|
8
|
+
* specification.
|
|
9
|
+
*
|
|
10
|
+
* The framework ships an offline copy of the upstream specification
|
|
11
|
+
* so the loader can decide which frontmatter fields are recognised,
|
|
12
|
+
* which `graphorin-*` extensions deprecate (or co-exist with) an
|
|
13
|
+
* upstream field, and whether a skill author's
|
|
14
|
+
* `graphorin-anthropic-spec` hint refers to a snapshot newer or older
|
|
15
|
+
* than the bundled one. The snapshot is checked-in to the repository
|
|
16
|
+
* and refreshed via the `pnpm run check-anthropic-spec` CI cron.
|
|
17
|
+
*
|
|
18
|
+
* The loader does not fetch the upstream specification; the only
|
|
19
|
+
* network call lives inside the CI helper script. The snapshot lookup
|
|
20
|
+
* is deterministic and side-effect free at runtime.
|
|
21
|
+
*
|
|
22
|
+
* @packageDocumentation
|
|
23
|
+
*/
|
|
24
|
+
let cached = null;
|
|
25
|
+
let overrideSnapshot = null;
|
|
26
|
+
/**
|
|
27
|
+
* Override the bundled snapshot. Used by tests that exercise the
|
|
28
|
+
* "newer / older spec snapshot" branches of the validator.
|
|
29
|
+
*
|
|
30
|
+
* @experimental
|
|
31
|
+
*/
|
|
32
|
+
function _setSpecSnapshotForTesting(snapshot) {
|
|
33
|
+
overrideSnapshot = snapshot;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Return the currently active snapshot. Loads the bundled JSON file
|
|
37
|
+
* on first call, then caches the parsed object.
|
|
38
|
+
*
|
|
39
|
+
* @stable
|
|
40
|
+
*/
|
|
41
|
+
function getSpecSnapshot() {
|
|
42
|
+
if (overrideSnapshot !== null) return overrideSnapshot;
|
|
43
|
+
if (cached !== null) return cached;
|
|
44
|
+
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
45
|
+
const candidates = [join(__dirname, "..", "..", "anthropic-spec-snapshot.json"), join(__dirname, "..", "..", "anthropic-spec-snapshot.json")];
|
|
46
|
+
let lastError;
|
|
47
|
+
for (const candidate of candidates) try {
|
|
48
|
+
const raw = readFileSync(candidate, "utf8");
|
|
49
|
+
const parsed = JSON.parse(raw);
|
|
50
|
+
cached = parsed;
|
|
51
|
+
return parsed;
|
|
52
|
+
} catch (err) {
|
|
53
|
+
lastError = err;
|
|
54
|
+
}
|
|
55
|
+
throw new Error(`Failed to load bundled spec snapshot. Tried: ${candidates.join(", ")}. Cause: ${lastError.message}`);
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Resolve a known-field entry by name. Returns `undefined` if the
|
|
59
|
+
* field is not part of the upstream specification.
|
|
60
|
+
*
|
|
61
|
+
* @stable
|
|
62
|
+
*/
|
|
63
|
+
function getKnownField(field) {
|
|
64
|
+
return getSpecSnapshot().knownFields[field];
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Resolve the mapping entry for a `graphorin-*` field. Returns
|
|
68
|
+
* `undefined` if the field is not known to the snapshot.
|
|
69
|
+
*
|
|
70
|
+
* @stable
|
|
71
|
+
*/
|
|
72
|
+
function getGraphorinMapping(field) {
|
|
73
|
+
return getSpecSnapshot().graphorinMapping[field];
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Compare an author's `graphorin-anthropic-spec` value against the
|
|
77
|
+
* bundled snapshot date. Returns:
|
|
78
|
+
*
|
|
79
|
+
* - `'same'` — the author targeted the same snapshot.
|
|
80
|
+
* - `'older'` — the author targeted an older snapshot.
|
|
81
|
+
* - `'newer'` — the author targeted a newer snapshot.
|
|
82
|
+
* - `'unparseable'` — the author's value could not be interpreted as
|
|
83
|
+
* an ISO-8601 date.
|
|
84
|
+
*
|
|
85
|
+
* @stable
|
|
86
|
+
*/
|
|
87
|
+
function compareAuthorSpecHint(authorValue) {
|
|
88
|
+
const snapshot = getSpecSnapshot();
|
|
89
|
+
const author = parseDate(authorValue);
|
|
90
|
+
const local = parseDate(snapshot.snapshotDate);
|
|
91
|
+
if (author === null || local === null) return "unparseable";
|
|
92
|
+
if (author.getTime() === local.getTime()) return "same";
|
|
93
|
+
return author.getTime() > local.getTime() ? "newer" : "older";
|
|
94
|
+
}
|
|
95
|
+
function parseDate(value) {
|
|
96
|
+
const trimmed = value.trim();
|
|
97
|
+
if (!/^\d{4}-\d{2}-\d{2}/u.test(trimmed)) return null;
|
|
98
|
+
const date = new Date(trimmed);
|
|
99
|
+
if (Number.isNaN(date.getTime())) return null;
|
|
100
|
+
return date;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
//#endregion
|
|
104
|
+
export { _setSpecSnapshotForTesting, compareAuthorSpecHint, getGraphorinMapping, getKnownField, getSpecSnapshot };
|
|
105
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","names":["cached: SpecSnapshot | null","overrideSnapshot: SpecSnapshot | null","lastError: unknown"],"sources":["../../src/spec/index.ts"],"sourcesContent":["/**\n * Bundled snapshot loader for the `SKILL.md` packaging-format\n * specification.\n *\n * The framework ships an offline copy of the upstream specification\n * so the loader can decide which frontmatter fields are recognised,\n * which `graphorin-*` extensions deprecate (or co-exist with) an\n * upstream field, and whether a skill author's\n * `graphorin-anthropic-spec` hint refers to a snapshot newer or older\n * than the bundled one. The snapshot is checked-in to the repository\n * and refreshed via the `pnpm run check-anthropic-spec` CI cron.\n *\n * The loader does not fetch the upstream specification; the only\n * network call lives inside the CI helper script. The snapshot lookup\n * is deterministic and side-effect free at runtime.\n *\n * @packageDocumentation\n */\n\nimport { readFileSync } from 'node:fs';\nimport { dirname, join } from 'node:path';\nimport { fileURLToPath } from 'node:url';\n\n/** Stability classification of a known upstream field. */\nexport type FieldStability = 'stable' | 'standardized' | 'experimental';\n\n/** Migration policy applied to a `graphorin-*` field that maps to an upstream field. */\nexport type GraphorinFieldPolicy = 'deprecate-graphorin-prefix' | 'co-exist' | 'graphorin-only';\n\n/** Single entry of the upstream-known fields map. */\nexport interface KnownFieldEntry {\n readonly since: string;\n readonly required: boolean;\n readonly type: string;\n readonly stability: FieldStability;\n}\n\n/** Single entry of the `graphorin-*` mapping map. */\nexport interface GraphorinMappingEntry {\n readonly anthropicEquivalent: string | null;\n readonly policy: GraphorinFieldPolicy;\n readonly since?: string;\n readonly rationale?: string;\n readonly deprecateAt?: string;\n readonly removeAt?: string;\n}\n\n/** Top-level shape of the bundled snapshot. */\nexport interface SpecSnapshot {\n readonly snapshotDate: string;\n readonly specSource: string;\n readonly specCommit: string | null;\n readonly rationale?: string;\n readonly knownFields: Readonly<Record<string, KnownFieldEntry>>;\n readonly graphorinMapping: Readonly<Record<string, GraphorinMappingEntry>>;\n}\n\nlet cached: SpecSnapshot | null = null;\nlet overrideSnapshot: SpecSnapshot | null = null;\n\n/**\n * Override the bundled snapshot. Used by tests that exercise the\n * \"newer / older spec snapshot\" branches of the validator.\n *\n * @experimental\n */\nexport function _setSpecSnapshotForTesting(snapshot: SpecSnapshot | null): void {\n overrideSnapshot = snapshot;\n}\n\n/**\n * Return the currently active snapshot. Loads the bundled JSON file\n * on first call, then caches the parsed object.\n *\n * @stable\n */\nexport function getSpecSnapshot(): SpecSnapshot {\n if (overrideSnapshot !== null) return overrideSnapshot;\n if (cached !== null) return cached;\n const __filename = fileURLToPath(import.meta.url);\n const __dirname = dirname(__filename);\n const candidates = [\n // Source: packages/skills/src/spec/index.ts → ../../anthropic-spec-snapshot.json\n join(__dirname, '..', '..', 'anthropic-spec-snapshot.json'),\n // Built ESM: packages/skills/dist/spec/index.js → ../../anthropic-spec-snapshot.json\n join(__dirname, '..', '..', 'anthropic-spec-snapshot.json'),\n ];\n let lastError: unknown;\n for (const candidate of candidates) {\n try {\n const raw = readFileSync(candidate, 'utf8');\n const parsed = JSON.parse(raw) as SpecSnapshot;\n cached = parsed;\n return parsed;\n } catch (err) {\n lastError = err;\n }\n }\n throw new Error(\n `Failed to load bundled spec snapshot. Tried: ${candidates.join(', ')}. ` +\n `Cause: ${(lastError as Error).message}`,\n );\n}\n\n/**\n * Resolve a known-field entry by name. Returns `undefined` if the\n * field is not part of the upstream specification.\n *\n * @stable\n */\nexport function getKnownField(field: string): KnownFieldEntry | undefined {\n return getSpecSnapshot().knownFields[field];\n}\n\n/**\n * Resolve the mapping entry for a `graphorin-*` field. Returns\n * `undefined` if the field is not known to the snapshot.\n *\n * @stable\n */\nexport function getGraphorinMapping(field: string): GraphorinMappingEntry | undefined {\n return getSpecSnapshot().graphorinMapping[field];\n}\n\n/**\n * Compare an author's `graphorin-anthropic-spec` value against the\n * bundled snapshot date. Returns:\n *\n * - `'same'` — the author targeted the same snapshot.\n * - `'older'` — the author targeted an older snapshot.\n * - `'newer'` — the author targeted a newer snapshot.\n * - `'unparseable'` — the author's value could not be interpreted as\n * an ISO-8601 date.\n *\n * @stable\n */\nexport function compareAuthorSpecHint(\n authorValue: string,\n): 'same' | 'older' | 'newer' | 'unparseable' {\n const snapshot = getSpecSnapshot();\n const author = parseDate(authorValue);\n const local = parseDate(snapshot.snapshotDate);\n if (author === null || local === null) return 'unparseable';\n if (author.getTime() === local.getTime()) return 'same';\n return author.getTime() > local.getTime() ? 'newer' : 'older';\n}\n\nfunction parseDate(value: string): Date | null {\n const trimmed = value.trim();\n if (!/^\\d{4}-\\d{2}-\\d{2}/u.test(trimmed)) return null;\n const date = new Date(trimmed);\n if (Number.isNaN(date.getTime())) return null;\n return date;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;AAyDA,IAAIA,SAA8B;AAClC,IAAIC,mBAAwC;;;;;;;AAQ5C,SAAgB,2BAA2B,UAAqC;AAC9E,oBAAmB;;;;;;;;AASrB,SAAgB,kBAAgC;AAC9C,KAAI,qBAAqB,KAAM,QAAO;AACtC,KAAI,WAAW,KAAM,QAAO;CAE5B,MAAM,YAAY,QADC,cAAc,OAAO,KAAK,IAAI,CACZ;CACrC,MAAM,aAAa,CAEjB,KAAK,WAAW,MAAM,MAAM,+BAA+B,EAE3D,KAAK,WAAW,MAAM,MAAM,+BAA+B,CAC5D;CACD,IAAIC;AACJ,MAAK,MAAM,aAAa,WACtB,KAAI;EACF,MAAM,MAAM,aAAa,WAAW,OAAO;EAC3C,MAAM,SAAS,KAAK,MAAM,IAAI;AAC9B,WAAS;AACT,SAAO;UACA,KAAK;AACZ,cAAY;;AAGhB,OAAM,IAAI,MACR,gDAAgD,WAAW,KAAK,KAAK,CAAC,WACzD,UAAoB,UAClC;;;;;;;;AASH,SAAgB,cAAc,OAA4C;AACxE,QAAO,iBAAiB,CAAC,YAAY;;;;;;;;AASvC,SAAgB,oBAAoB,OAAkD;AACpF,QAAO,iBAAiB,CAAC,iBAAiB;;;;;;;;;;;;;;AAe5C,SAAgB,sBACd,aAC4C;CAC5C,MAAM,WAAW,iBAAiB;CAClC,MAAM,SAAS,UAAU,YAAY;CACrC,MAAM,QAAQ,UAAU,SAAS,aAAa;AAC9C,KAAI,WAAW,QAAQ,UAAU,KAAM,QAAO;AAC9C,KAAI,OAAO,SAAS,KAAK,MAAM,SAAS,CAAE,QAAO;AACjD,QAAO,OAAO,SAAS,GAAG,MAAM,SAAS,GAAG,UAAU;;AAGxD,SAAS,UAAU,OAA4B;CAC7C,MAAM,UAAU,MAAM,MAAM;AAC5B,KAAI,CAAC,sBAAsB,KAAK,QAAQ,CAAE,QAAO;CACjD,MAAM,OAAO,IAAI,KAAK,QAAQ;AAC9B,KAAI,OAAO,MAAM,KAAK,SAAS,CAAC,CAAE,QAAO;AACzC,QAAO"}
|
|
@@ -0,0 +1,305 @@
|
|
|
1
|
+
import { ResolvedSkillTrustPolicy, SkillSignatureVerificationResult, SkillSource as SupplyChainSkillSource, SkillTrustLevel } from "@graphorin/security/supply-chain";
|
|
2
|
+
import { ResolvedTool, Tool } from "@graphorin/core";
|
|
3
|
+
|
|
4
|
+
//#region src/types/index.d.ts
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Trust level recognised by the skills loader. Extends the
|
|
8
|
+
* supply-chain trust ladder with a third `'unknown'` value the
|
|
9
|
+
* loader uses for skills that have no explicit declaration. The
|
|
10
|
+
* sandbox tier resolver treats `'unknown'` like `'untrusted'`
|
|
11
|
+
* (mandatory `worker-threads + no-net + no-fs`); the supply-chain
|
|
12
|
+
* installer treats it as untrusted EXCEPT that the signature
|
|
13
|
+
* requirement is downgraded from mandatory to optional — signature
|
|
14
|
+
* is a trust upgrade, not a gate (Phase 08 § Risks & mitigations).
|
|
15
|
+
*
|
|
16
|
+
* @stable
|
|
17
|
+
*/
|
|
18
|
+
type SkillsTrustLevel = SkillTrustLevel | 'unknown';
|
|
19
|
+
/**
|
|
20
|
+
* Conflict-resolution policy used by the frontmatter validator when an
|
|
21
|
+
* Anthropic-base field and the equivalent `graphorin-*` field are both
|
|
22
|
+
* declared.
|
|
23
|
+
*
|
|
24
|
+
* @stable
|
|
25
|
+
*/
|
|
26
|
+
type FrontmatterValidatorPolicy = 'warn' | 'error' | 'silent';
|
|
27
|
+
/**
|
|
28
|
+
* Policy applied to frontmatter fields that are present but recognised
|
|
29
|
+
* neither by the bundled spec snapshot nor by the `graphorin-*`
|
|
30
|
+
* extension catalogue.
|
|
31
|
+
*
|
|
32
|
+
* @stable
|
|
33
|
+
*/
|
|
34
|
+
type UnknownFieldPolicy = 'preserve' | 'reject' | 'warn';
|
|
35
|
+
/**
|
|
36
|
+
* Trust level applied to a loaded skill. Mirrors the supply-chain
|
|
37
|
+
* trust ladder + the loader's `'unknown'` extension so callers do
|
|
38
|
+
* not have to bridge two enums.
|
|
39
|
+
*
|
|
40
|
+
* @stable
|
|
41
|
+
*/
|
|
42
|
+
type SkillTrustLevelValue = SkillsTrustLevel;
|
|
43
|
+
/**
|
|
44
|
+
* Source descriptor for a {@link loadSkills} request.
|
|
45
|
+
*
|
|
46
|
+
* - `'folder'` — load from a directory on disk.
|
|
47
|
+
* - `'npm-package'` — install via the supply-chain installer + load.
|
|
48
|
+
* - `'git-repo'` — shallow-clone via the supply-chain installer +
|
|
49
|
+
* load.
|
|
50
|
+
* - `'inline'` — the caller supplies a parsed skill structure;
|
|
51
|
+
* useful for tests and embedded fixtures.
|
|
52
|
+
*
|
|
53
|
+
* @stable
|
|
54
|
+
*/
|
|
55
|
+
type SkillSource = {
|
|
56
|
+
readonly kind: 'folder';
|
|
57
|
+
readonly path: string;
|
|
58
|
+
/**
|
|
59
|
+
* Operator-supplied trust level. When present it overrides the
|
|
60
|
+
* skill's self-declared `graphorin-trust-level`. Without it, a
|
|
61
|
+
* folder's self-declared `trusted` / `trusted-with-scripts` is
|
|
62
|
+
* capped at `'unknown'` — a downloaded directory cannot promote
|
|
63
|
+
* itself; trust is granted by the integrator, never the artifact.
|
|
64
|
+
*/
|
|
65
|
+
readonly trustLevel?: SkillTrustLevel;
|
|
66
|
+
} | {
|
|
67
|
+
readonly kind: 'npm-package';
|
|
68
|
+
readonly packageName: string;
|
|
69
|
+
readonly version?: string;
|
|
70
|
+
readonly trustLevel?: SkillTrustLevel;
|
|
71
|
+
} | {
|
|
72
|
+
readonly kind: 'git-repo';
|
|
73
|
+
readonly url: string;
|
|
74
|
+
readonly ref?: string;
|
|
75
|
+
readonly trustLevel?: SkillTrustLevel;
|
|
76
|
+
} | {
|
|
77
|
+
readonly kind: 'inline';
|
|
78
|
+
readonly skill: InlineSkill;
|
|
79
|
+
};
|
|
80
|
+
/**
|
|
81
|
+
* Pre-built tool record accepted by the inline source. The loader
|
|
82
|
+
* does not parse the tool — it forwards the record to the agent
|
|
83
|
+
* runtime which feeds it through `stampSkillTool(...)` before
|
|
84
|
+
* registering with `@graphorin/tools`.
|
|
85
|
+
*
|
|
86
|
+
* @stable
|
|
87
|
+
*/
|
|
88
|
+
type InlineSkillTool = Tool;
|
|
89
|
+
/**
|
|
90
|
+
* Pre-built skill payload accepted by `{ kind: 'inline' }`. Bypasses
|
|
91
|
+
* the file-system loader; useful for tests and bundled defaults.
|
|
92
|
+
*
|
|
93
|
+
* @stable
|
|
94
|
+
*/
|
|
95
|
+
interface InlineSkill {
|
|
96
|
+
readonly skillMd: string;
|
|
97
|
+
readonly basePath?: string;
|
|
98
|
+
readonly resources?: ReadonlyArray<{
|
|
99
|
+
readonly path: string;
|
|
100
|
+
readonly content: string;
|
|
101
|
+
}>;
|
|
102
|
+
/**
|
|
103
|
+
* Pre-built `Tool[]` payload. When supplied, the loader exposes
|
|
104
|
+
* these via {@link Skill.tools} so {@link SkillRegistry.tools}
|
|
105
|
+
* returns them deduplicated by `tool.name`.
|
|
106
|
+
*
|
|
107
|
+
* Folder / npm / git sources do not carry tool implementations —
|
|
108
|
+
* the agent runtime (Phase 12) materialises them from the skill's
|
|
109
|
+
* `tools/` directory. The inline source is the only path through
|
|
110
|
+
* which tests + bundled defaults can ship pre-built tools.
|
|
111
|
+
*/
|
|
112
|
+
readonly tools?: ReadonlyArray<InlineSkillTool>;
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* Resolution outcome of a single field on a `SKILL.md` frontmatter.
|
|
116
|
+
*
|
|
117
|
+
* @stable
|
|
118
|
+
*/
|
|
119
|
+
interface FieldResolution<T = unknown> {
|
|
120
|
+
readonly value: T | undefined;
|
|
121
|
+
readonly source: 'anthropic-base' | 'metadata-graphorin' | 'graphorin-prefix' | 'fallback';
|
|
122
|
+
readonly conflicting: boolean;
|
|
123
|
+
readonly conflictingSources: ReadonlyArray<string>;
|
|
124
|
+
}
|
|
125
|
+
/**
|
|
126
|
+
* Diagnostic record produced by the frontmatter validator. Carries a
|
|
127
|
+
* structured `kind` so the loader can surface the diagnostic on a
|
|
128
|
+
* trace span / audit emitter without re-parsing the human message.
|
|
129
|
+
*
|
|
130
|
+
* @stable
|
|
131
|
+
*/
|
|
132
|
+
interface FrontmatterDiagnostic {
|
|
133
|
+
readonly kind: 'conflict' | 'experimental-field' | 'unknown-field' | 'spec-newer-than-loader' | 'spec-older-than-loader' | 'unsupported-frontmatter' | 'invalid-field-type' | 'missing-required-field' | 'untrusted-handoff-filter-required' | 'invalid-runtime-compat';
|
|
134
|
+
readonly field: string;
|
|
135
|
+
readonly severity: 'info' | 'warn' | 'error';
|
|
136
|
+
readonly message: string;
|
|
137
|
+
readonly hint?: string;
|
|
138
|
+
}
|
|
139
|
+
/**
|
|
140
|
+
* Validated skill metadata. Always available on the registry without
|
|
141
|
+
* loading the body — this is the always-present **Tier 1** payload
|
|
142
|
+
* that the system prompt advertises.
|
|
143
|
+
*
|
|
144
|
+
* @stable
|
|
145
|
+
*/
|
|
146
|
+
interface SkillMetadata {
|
|
147
|
+
readonly name: string;
|
|
148
|
+
readonly description: string;
|
|
149
|
+
readonly license?: string;
|
|
150
|
+
readonly compatibility?: string;
|
|
151
|
+
readonly metadata?: Readonly<Record<string, unknown>>;
|
|
152
|
+
readonly allowedTools?: ReadonlyArray<string>;
|
|
153
|
+
readonly disableModelInvocation: boolean;
|
|
154
|
+
readonly graphorinTrustLevel: SkillsTrustLevel;
|
|
155
|
+
readonly graphorinRuntimeCompat?: string;
|
|
156
|
+
readonly graphorinSensitivity?: string;
|
|
157
|
+
readonly graphorinSensitivityDefaults?: Readonly<Record<string, string>>;
|
|
158
|
+
readonly graphorinSandbox?: Readonly<Record<string, unknown>>;
|
|
159
|
+
readonly graphorinHandoffInputFilter?: HandoffInputFilterDeclaration;
|
|
160
|
+
readonly graphorinSignaturePresent: boolean;
|
|
161
|
+
readonly graphorinAnthropicSpec?: string;
|
|
162
|
+
/** Author-declared graphorin runtime / extension version. */
|
|
163
|
+
readonly graphorinVersion?: string;
|
|
164
|
+
/** Raw frontmatter (read-only) for power users — every loader user can re-derive bespoke fields. */
|
|
165
|
+
readonly raw: Readonly<Record<string, unknown>>;
|
|
166
|
+
}
|
|
167
|
+
/**
|
|
168
|
+
* `graphorin-handoff-input-filter` declaration recognised by the
|
|
169
|
+
* loader. The runtime resolves the declaration into the actual filter
|
|
170
|
+
* implementation in Phase 12; the loader only validates the shape.
|
|
171
|
+
*
|
|
172
|
+
* @stable
|
|
173
|
+
*/
|
|
174
|
+
type HandoffInputFilterDeclaration = {
|
|
175
|
+
readonly kind: 'lastUser';
|
|
176
|
+
} | {
|
|
177
|
+
readonly kind: 'lastN';
|
|
178
|
+
readonly n: number;
|
|
179
|
+
} | {
|
|
180
|
+
readonly kind: 'summary';
|
|
181
|
+
} | {
|
|
182
|
+
readonly kind: 'full';
|
|
183
|
+
} | {
|
|
184
|
+
readonly kind: 'compose';
|
|
185
|
+
readonly steps: ReadonlyArray<HandoffInputFilterStep>;
|
|
186
|
+
};
|
|
187
|
+
/**
|
|
188
|
+
* Composable step recognised inside `graphorin-handoff-input-filter:
|
|
189
|
+
* { compose: [...] }`. The runtime resolves named steps into actual
|
|
190
|
+
* filter implementations in Phase 12.
|
|
191
|
+
*
|
|
192
|
+
* @stable
|
|
193
|
+
*/
|
|
194
|
+
type HandoffInputFilterStep = {
|
|
195
|
+
readonly kind: 'lastUser';
|
|
196
|
+
} | {
|
|
197
|
+
readonly kind: 'lastN';
|
|
198
|
+
readonly n: number;
|
|
199
|
+
} | {
|
|
200
|
+
readonly kind: 'summary';
|
|
201
|
+
} | {
|
|
202
|
+
readonly kind: 'stripSensitiveOutputs';
|
|
203
|
+
readonly keepTier?: string;
|
|
204
|
+
} | {
|
|
205
|
+
readonly kind: 'stripReasoning';
|
|
206
|
+
};
|
|
207
|
+
/**
|
|
208
|
+
* Tool declaration found inside `graphorin-tools:`. The loader only
|
|
209
|
+
* captures the declarations; the actual `Tool[]` is produced by the
|
|
210
|
+
* skill author's `tools/*.ts` modules and bridged into the
|
|
211
|
+
* `@graphorin/tools` registry by the agent runtime in Phase 12.
|
|
212
|
+
*
|
|
213
|
+
* @stable
|
|
214
|
+
*/
|
|
215
|
+
interface SkillToolDeclaration {
|
|
216
|
+
readonly name: string;
|
|
217
|
+
readonly module?: string;
|
|
218
|
+
readonly description?: string;
|
|
219
|
+
readonly tags?: ReadonlyArray<string>;
|
|
220
|
+
}
|
|
221
|
+
/**
|
|
222
|
+
* Lazy resource accessor returned by {@link Skill.resources}. The
|
|
223
|
+
* loader does not read the file off disk until `.read()` is invoked.
|
|
224
|
+
*
|
|
225
|
+
* @stable
|
|
226
|
+
*/
|
|
227
|
+
interface SkillResource {
|
|
228
|
+
readonly path: string;
|
|
229
|
+
readonly relativePath: string;
|
|
230
|
+
readonly mediaType?: string;
|
|
231
|
+
read(signal?: AbortSignal): Promise<Uint8Array>;
|
|
232
|
+
readText(signal?: AbortSignal): Promise<string>;
|
|
233
|
+
}
|
|
234
|
+
/**
|
|
235
|
+
* Loaded skill record returned by {@link SkillRegistry.getSkill} and
|
|
236
|
+
* {@link loadSkills}. Three-tier semantics:
|
|
237
|
+
*
|
|
238
|
+
* - {@link Skill.metadata} — always available (parsed at load time).
|
|
239
|
+
* - {@link Skill.body} — lazy; resolved on first call. Cached for
|
|
240
|
+
* subsequent calls.
|
|
241
|
+
* - {@link Skill.resources} — lazy listing; resource bytes are only
|
|
242
|
+
* read when {@link SkillResource.read} is invoked.
|
|
243
|
+
* - {@link Skill.tools} — derived from the `graphorin-tools`
|
|
244
|
+
* declarations; the actual `Tool[]` is materialised by the agent
|
|
245
|
+
* runtime through the `@graphorin/tools` registry.
|
|
246
|
+
*
|
|
247
|
+
* @stable
|
|
248
|
+
*/
|
|
249
|
+
interface Skill {
|
|
250
|
+
readonly metadata: SkillMetadata;
|
|
251
|
+
readonly source: SkillSource;
|
|
252
|
+
readonly basePath?: string;
|
|
253
|
+
readonly trustPolicy: ResolvedSkillTrustPolicy;
|
|
254
|
+
readonly signature?: SkillSignatureVerificationResult;
|
|
255
|
+
body(signal?: AbortSignal): Promise<string>;
|
|
256
|
+
resources(signal?: AbortSignal): Promise<ReadonlyArray<SkillResource>>;
|
|
257
|
+
/**
|
|
258
|
+
* Pre-built tools shipped with the skill. The inline source is the
|
|
259
|
+
* only path through which the loader carries actual `Tool[]`
|
|
260
|
+
* records; folder / npm / git sources return `[]` here and the
|
|
261
|
+
* agent runtime (Phase 12) materialises tools from the
|
|
262
|
+
* `graphorin-tools` declarations + the skill's `tools/` directory.
|
|
263
|
+
*/
|
|
264
|
+
tools(): ReadonlyArray<InlineSkillTool>;
|
|
265
|
+
toolDeclarations(): ReadonlyArray<SkillToolDeclaration>;
|
|
266
|
+
diagnostics(): ReadonlyArray<FrontmatterDiagnostic>;
|
|
267
|
+
}
|
|
268
|
+
/**
|
|
269
|
+
* Activated skill — what the agent runtime sees after the model (or a
|
|
270
|
+
* slash command) elects a skill. Carries the loaded body + declared
|
|
271
|
+
* tools so the runtime can inject them into the conversation.
|
|
272
|
+
*
|
|
273
|
+
* @stable
|
|
274
|
+
*/
|
|
275
|
+
interface ActivatedSkill {
|
|
276
|
+
readonly skill: Skill;
|
|
277
|
+
readonly body: string;
|
|
278
|
+
readonly resources: ReadonlyArray<SkillResource>;
|
|
279
|
+
/**
|
|
280
|
+
* Tools made available to the model while the skill is active.
|
|
281
|
+
* The agent runtime (Phase 12) is the canonical producer — it
|
|
282
|
+
* resolves the skill's `tools/` directory or the inline-supplied
|
|
283
|
+
* `Tool[]` and feeds each entry through `stampSkillTool(...)` so
|
|
284
|
+
* the resulting `ResolvedTool` carries the right trust class +
|
|
285
|
+
* sandbox tier.
|
|
286
|
+
*/
|
|
287
|
+
readonly tools: ReadonlyArray<ResolvedTool>;
|
|
288
|
+
readonly activationKind: 'auto' | 'slash-command' | 'explicit';
|
|
289
|
+
readonly activatedAt: number;
|
|
290
|
+
}
|
|
291
|
+
/**
|
|
292
|
+
* Result of {@link parseSlashCommand}. The loader parses
|
|
293
|
+
* `/skill:<name>` and `/skill:<name> <free-form-args>` into a
|
|
294
|
+
* structured payload the agent runtime consumes.
|
|
295
|
+
*
|
|
296
|
+
* @stable
|
|
297
|
+
*/
|
|
298
|
+
interface SlashCommandActivation {
|
|
299
|
+
readonly name: string;
|
|
300
|
+
readonly args: string;
|
|
301
|
+
readonly raw: string;
|
|
302
|
+
}
|
|
303
|
+
//#endregion
|
|
304
|
+
export { ActivatedSkill, FieldResolution, FrontmatterDiagnostic, FrontmatterValidatorPolicy, HandoffInputFilterDeclaration, HandoffInputFilterStep, InlineSkill, InlineSkillTool, type ResolvedSkillTrustPolicy, Skill, SkillMetadata, SkillResource, type SkillSignatureVerificationResult, SkillSource, SkillToolDeclaration, type SkillTrustLevel, SkillTrustLevelValue, SkillsTrustLevel, SlashCommandActivation, type SupplyChainSkillSource, UnknownFieldPolicy };
|
|
305
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","names":[],"sources":["../../src/types/index.ts"],"sourcesContent":[],"mappings":";;;;;;;;AA0GA;AAQA;;;;;AAsBA;AAcA;AAyBA;AAK+B,KAtJnB,gBAAA,GAAmB,eAsJA,GAAA,SAAA;;;;;;;;AAQU,KArJ7B,0BAAA,GAqJ6B,MAAA,GAAA,OAAA,GAAA,QAAA;;;;AAgBzC;AAiBA;AAkBA;AAaA;AAIgB,KAhNJ,kBAAA,GAgNI,UAAA,GAAA,QAAA,GAAA,MAAA;;;;;;AAmBhB;;AAEmB,KA5NP,oBAAA,GAAuB,gBA4NhB;;;;;;;;;;;;;AAeY,KA7NnB,WAAA,GA6NmB;EAAd,SAAA,IAAA,EAAA,QAAA;EAAa,SAAA,IAAA,EAAA,MAAA;EAUb;;;;;;;EAwBA,SAAA,UAAA,CAAA,EApPW,eAoPW;;;;;wBA9OX;;;;;wBAMA;;;kBAEmB;;;;;;;;;;KAUnC,eAAA,GAAkB;;;;;;;UAQb,WAAA;;;uBAGM;;;;;;;;;;;;;;mBAWJ,cAAc;;;;;;;UAQhB;kBACC;;;+BAGa;;;;;;;;;UAUd,qBAAA;;;;;;;;;;;;;;UAyBA,aAAA;;;;;sBAKK,SAAS;0BACL;;gCAEM;;;0CAGU,SAAS;8BACrB,SAAS;yCACE;;;;;;gBAMzB,SAAS;;;;;;;;;KAUb,6BAAA;;;;;;;;;;;kBAOU,cAAc;;;;;;;;;KAUxB,sBAAA;;;;;;;;;;;;;;;;;;;;;UAkBK,oBAAA;;;;kBAIC;;;;;;;;UASD,aAAA;;;;gBAID,cAAc,QAAQ;oBAClB,cAAc;;;;;;;;;;;;;;;;;UAkBjB,KAAA;qBACI;mBACF;;wBAEK;uBACD;gBACP,cAAc;qBACT,cAAc,QAAQ,cAAc;;;;;;;;WAQ9C,cAAc;sBACH,cAAc;iBACnB,cAAc;;;;;;;;;UAUd,cAAA;kBACC;;sBAEI,cAAc;;;;;;;;;kBASlB,cAAc;;;;;;;;;;;UAYf,sBAAA"}
|