@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.
Files changed (43) hide show
  1. package/CHANGELOG.md +7 -0
  2. package/LICENSE +21 -0
  3. package/README.md +169 -0
  4. package/anthropic-spec-snapshot.json +114 -0
  5. package/dist/activation/index.d.ts +30 -0
  6. package/dist/activation/index.d.ts.map +1 -0
  7. package/dist/activation/index.js +71 -0
  8. package/dist/activation/index.js.map +1 -0
  9. package/dist/errors/index.d.ts +110 -0
  10. package/dist/errors/index.d.ts.map +1 -0
  11. package/dist/errors/index.js +126 -0
  12. package/dist/errors/index.js.map +1 -0
  13. package/dist/frontmatter/index.d.ts +120 -0
  14. package/dist/frontmatter/index.d.ts.map +1 -0
  15. package/dist/frontmatter/index.js +451 -0
  16. package/dist/frontmatter/index.js.map +1 -0
  17. package/dist/index.d.ts +52 -0
  18. package/dist/index.d.ts.map +1 -0
  19. package/dist/index.js +51 -0
  20. package/dist/index.js.map +1 -0
  21. package/dist/loader/index.d.ts +55 -0
  22. package/dist/loader/index.d.ts.map +1 -0
  23. package/dist/loader/index.js +463 -0
  24. package/dist/loader/index.js.map +1 -0
  25. package/dist/migration/index.d.ts +62 -0
  26. package/dist/migration/index.d.ts.map +1 -0
  27. package/dist/migration/index.js +131 -0
  28. package/dist/migration/index.js.map +1 -0
  29. package/dist/registry/bridge.d.ts +47 -0
  30. package/dist/registry/bridge.d.ts.map +1 -0
  31. package/dist/registry/bridge.js +91 -0
  32. package/dist/registry/bridge.js.map +1 -0
  33. package/dist/registry/index.d.ts +140 -0
  34. package/dist/registry/index.d.ts.map +1 -0
  35. package/dist/registry/index.js +193 -0
  36. package/dist/registry/index.js.map +1 -0
  37. package/dist/spec/index.d.ts +92 -0
  38. package/dist/spec/index.d.ts.map +1 -0
  39. package/dist/spec/index.js +105 -0
  40. package/dist/spec/index.js.map +1 -0
  41. package/dist/types/index.d.ts +305 -0
  42. package/dist/types/index.d.ts.map +1 -0
  43. package/package.json +104 -0
package/CHANGELOG.md ADDED
@@ -0,0 +1,7 @@
1
+ # @graphorin/skills
2
+
3
+ ## 0.1.0
4
+
5
+ Initial release. See the workspace root `CHANGELOG.md` for the full
6
+ release notes; the per-package changelog is generated by Changesets
7
+ and tracks subsequent updates.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Oleksiy Stepurenko
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,169 @@
1
+ # @graphorin/skills
2
+
3
+ > Skills surface for the Graphorin framework.
4
+
5
+ `@graphorin/skills` ships the loader, registry, validator, and
6
+ migration library that let a Graphorin agent consume skills written
7
+ to the `SKILL.md` packaging format with three-tier progressive
8
+ disclosure plus the Graphorin-specific extensions namespaced under
9
+ the `graphorin-*` prefix.
10
+
11
+ ## Highlights
12
+
13
+ - **Compatibility-first loader.** A skill written to the public
14
+ `SKILL.md` packaging format loads in Graphorin without
15
+ modification. Author-time fields under the `graphorin-*` prefix and
16
+ the spec-recommended `metadata.graphorin.*` bucket are honoured
17
+ through a deterministic field-resolution algorithm (Anthropic-base
18
+ > `metadata.graphorin.*` > `graphorin-*` legacy > caller fallback).
19
+ - **Three-tier progressive disclosure.** Metadata (Tier 1) is parsed
20
+ at load time. The skill body (Tier 2) is read on first
21
+ `Skill.body()` call. Resources (Tier 3) are listed lazily and the
22
+ bytes are only read when `SkillResource.read()` is invoked.
23
+ - **Conflict policy.** Direct collisions (Anthropic-base set + the
24
+ matching `graphorin-*` set) honour the operator-resolved
25
+ `conflictPolicy` (`'warn' | 'error' | 'silent'`); the default is
26
+ `'warn'`. The validator returns a typed `FrontmatterDiagnostic[]`
27
+ so callers can route the report to logs, audit, or CI.
28
+ - **Spec-snapshot tracking.** A bundled
29
+ `anthropic-spec-snapshot.json` records the upstream fields the
30
+ framework recognises and the migration policy for every
31
+ `graphorin-*` extension. The `pnpm run check-anthropic-spec` CI
32
+ helper diffs the snapshot against the published specification so
33
+ maintainers can promote new fields with a clear changelog entry.
34
+ - **Supply-chain aware.** Loading from `npm-package` and `git-repo`
35
+ sources delegates to the supply-chain helpers in
36
+ `@graphorin/security` so untrusted skills install with
37
+ `--ignore-scripts` enforced and a verifiable ed25519 signature is
38
+ required before the loader trusts the bytes. Local `folder`
39
+ installations remain trusted-by-default but inherit the same
40
+ validation pipeline.
41
+ - **Slash-command activation.** `/skill:<name>` parses into a
42
+ structured activation request the agent runtime consumes alongside
43
+ the model-emitted auto-activation requests; skills that opt out via
44
+ `disable-model-invocation: true` are excluded from auto-activation
45
+ but remain reachable through the slash command.
46
+ - **Migration library.** `migrateFrontmatter()` is idempotent and
47
+ dry-run by default. Re-running the migrator on an already-migrated
48
+ manifest returns `changed: false`.
49
+
50
+ ## Stable sub-paths
51
+
52
+ ```ts
53
+ // Loader (folder / npm-package / git-repo / inline sources).
54
+ import { loadSkills, loadSkillFromSource } from '@graphorin/skills/loader';
55
+
56
+ // Registry (auto-activation metadata + slash-command resolver +
57
+ // trust-level-aware tool-declaration listing).
58
+ import { createSkillRegistry } from '@graphorin/skills/registry';
59
+
60
+ // Frontmatter validator + field-resolution algorithm.
61
+ import { validateFrontmatter, resolveSkillField } from '@graphorin/skills/frontmatter';
62
+
63
+ // Idempotent migrate-frontmatter helper used by the CLI.
64
+ import { migrateFrontmatter } from '@graphorin/skills/migration';
65
+
66
+ // Activation utilities (`/skill:<name>` parser).
67
+ import { parseSlashCommand, isSlashCommand } from '@graphorin/skills/activation';
68
+
69
+ // Spec-snapshot helpers.
70
+ import { getSpecSnapshot, getKnownField, compareAuthorSpecHint } from '@graphorin/skills/spec';
71
+
72
+ // Typed errors.
73
+ import { SkillFrontmatterConflictError, InputFilterRequiredError } from '@graphorin/skills/errors';
74
+ ```
75
+
76
+ ## Hello-world
77
+
78
+ ```ts
79
+ import { loadSkillFromSource, createSkillRegistry } from '@graphorin/skills';
80
+
81
+ const skill = await loadSkillFromSource(
82
+ { kind: 'folder', path: './skills/finance-helper' },
83
+ { conflictPolicy: 'warn', runtimeVersion: '0.5.0' },
84
+ );
85
+
86
+ const registry = createSkillRegistry();
87
+ registry.register(skill);
88
+
89
+ const metadataBlock = registry.getAutoActivationMetadata();
90
+ // → metadata fed into the system prompt by the agent runtime (Phase 12).
91
+
92
+ const activation = registry.resolveTrigger('/skill:finance-helper run-quarterly-report');
93
+ if (activation !== null) {
94
+ const body = await activation.skill.body();
95
+ // → Tier-2 body resolved lazily on first call; cached afterwards.
96
+ }
97
+ ```
98
+
99
+ ## Frontmatter cheat sheet
100
+
101
+ ```yaml
102
+ ---
103
+ # === Public SKILL.md packaging format (no prefix) ===
104
+ name: finance-helper
105
+ description: |
106
+ Surface monthly P&L reports. Use when the user asks about cash
107
+ flow, runway, or quarterly business reports.
108
+ license: MIT
109
+ disable-model-invocation: false
110
+
111
+ # === Graphorin extensions (namespaced) ===
112
+ graphorin-runtime-compat: ^0.5.0
113
+ graphorin-trust-level: trusted
114
+ graphorin-sensitivity: internal
115
+ graphorin-handoff-input-filter: lastUser
116
+ graphorin-tools:
117
+ - name: pull_quarterly_report
118
+ description: Read the latest quarterly close.
119
+ tags: ['finance', 'reporting']
120
+ graphorin-signature:
121
+ algorithm: ed25519-sha256
122
+ publisher: example.com
123
+ publishedAt: 2026-04-19T12:00:00Z
124
+ signature: <base64url>
125
+ publicKeyRef:
126
+ kind: well-known
127
+ url: https://example.com/.well-known/graphorin-skill-pubkey.pem
128
+ ---
129
+
130
+ # Finance Helper
131
+
132
+ The body of the SKILL.md is loaded lazily on activation.
133
+ ```
134
+
135
+ ## Trust levels
136
+
137
+ | Source | Default `graphorin-trust-level` | `--ignore-scripts` | Signature |
138
+ |----------------|------------------------------------------|----------------------------|-----------------------------|
139
+ | `folder` | `trusted` (override `trusted-with-scripts`) | default ON; opt-in override | optional |
140
+ | `npm-package` | `untrusted` (override via `trustLevel`) | mandatory (no override) | mandatory |
141
+ | `git-repo` | `untrusted` | mandatory | mandatory |
142
+ | `inline` | `trusted` (test fixture) | n/a | n/a |
143
+
144
+ The supply-chain layer enforces `--ignore-scripts` and signature
145
+ verification through `@graphorin/security/supply-chain`. The skills
146
+ loader does not duplicate that logic — it delegates and surfaces the
147
+ resulting `ResolvedSkillTrustPolicy` alongside the loaded skill.
148
+
149
+ ## Dependencies
150
+
151
+ - `yaml@^2.8.0` — required runtime dependency. Used for frontmatter
152
+ parsing and migrator output.
153
+ - `@graphorin/core` — typed contracts (`ResolvedTool`, …) consumed by
154
+ the registry's tool-declaration surface.
155
+ - `@graphorin/security` — supply-chain installer, ed25519 signature
156
+ verifier, trust-policy resolver. Skills loaded from `npm-package`
157
+ and `git-repo` sources go through this package.
158
+ - `@graphorin/tools` — peer surface the agent runtime uses to
159
+ register skill-bundled tools after activation. The skills loader
160
+ does not import the runtime registry directly; it returns a typed
161
+ `RegisteredToolDeclaration[]` the runtime consumes.
162
+
163
+ ## License
164
+
165
+ MIT. Copyright © 2026 Oleksiy Stepurenko.
166
+
167
+ ---
168
+
169
+ **Project Graphorin** · v0.5.0 · MIT License · © 2026 Oleksiy Stepurenko · <https://github.com/o-stepper/graphorin>
@@ -0,0 +1,114 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "$id": "https://raw.githubusercontent.com/o-stepper/graphorin/main/packages/skills/anthropic-spec-snapshot.json",
4
+ "snapshotDate": "2026-04-19",
5
+ "specSource": "https://agentskills.io/specification",
6
+ "specCommit": null,
7
+ "rationale": "Bundled snapshot of the publicly published `SKILL.md` file-format specification used to determine which frontmatter fields are recognised by the upstream loader. Updated through the `pnpm run check-anthropic-spec` CI cron whenever the published specification changes.",
8
+ "knownFields": {
9
+ "name": {
10
+ "since": "2025-01-01",
11
+ "required": true,
12
+ "type": "string",
13
+ "stability": "stable"
14
+ },
15
+ "description": {
16
+ "since": "2025-01-01",
17
+ "required": true,
18
+ "type": "string",
19
+ "stability": "stable"
20
+ },
21
+ "license": {
22
+ "since": "2025-06-01",
23
+ "required": false,
24
+ "type": "string",
25
+ "stability": "standardized"
26
+ },
27
+ "compatibility": {
28
+ "since": "2025-06-01",
29
+ "required": false,
30
+ "type": "string",
31
+ "stability": "standardized"
32
+ },
33
+ "metadata": {
34
+ "since": "2025-09-01",
35
+ "required": false,
36
+ "type": "object",
37
+ "stability": "standardized"
38
+ },
39
+ "allowed-tools": {
40
+ "since": "2025-12-01",
41
+ "required": false,
42
+ "type": "string-or-array",
43
+ "stability": "experimental"
44
+ },
45
+ "disable-model-invocation": {
46
+ "since": "2025-09-01",
47
+ "required": false,
48
+ "type": "boolean",
49
+ "stability": "stable"
50
+ }
51
+ },
52
+ "graphorinMapping": {
53
+ "graphorin-allowed-tools": {
54
+ "anthropicEquivalent": "allowed-tools",
55
+ "since": "agentskills-2025-12",
56
+ "policy": "deprecate-graphorin-prefix",
57
+ "deprecateAt": "graphorin@0.5",
58
+ "removeAt": "graphorin@1.0"
59
+ },
60
+ "graphorin-version": {
61
+ "anthropicEquivalent": "metadata.version",
62
+ "policy": "co-exist",
63
+ "rationale": "graphorin-version means runtime-compat semver range; metadata.version means skill version"
64
+ },
65
+ "graphorin-runtime-compat": {
66
+ "anthropicEquivalent": null,
67
+ "policy": "graphorin-only",
68
+ "rationale": "Successor naming for graphorin-version (clearer intent); both honoured during transition."
69
+ },
70
+ "graphorin-trust-level": {
71
+ "anthropicEquivalent": null,
72
+ "policy": "graphorin-only"
73
+ },
74
+ "graphorin-allowed-tools-overrides": {
75
+ "anthropicEquivalent": null,
76
+ "policy": "graphorin-only"
77
+ },
78
+ "graphorin-sandbox": {
79
+ "anthropicEquivalent": null,
80
+ "policy": "graphorin-only"
81
+ },
82
+ "graphorin-sensitivity": {
83
+ "anthropicEquivalent": null,
84
+ "policy": "graphorin-only"
85
+ },
86
+ "graphorin-sensitivity-defaults": {
87
+ "anthropicEquivalent": null,
88
+ "policy": "graphorin-only"
89
+ },
90
+ "graphorin-handoff-input-filter": {
91
+ "anthropicEquivalent": null,
92
+ "policy": "graphorin-only"
93
+ },
94
+ "graphorin-disable-model-invocation": {
95
+ "anthropicEquivalent": "disable-model-invocation",
96
+ "policy": "deprecate-graphorin-prefix",
97
+ "deprecateAt": "graphorin@0.5",
98
+ "removeAt": "graphorin@1.0"
99
+ },
100
+ "graphorin-signature": {
101
+ "anthropicEquivalent": null,
102
+ "policy": "graphorin-only"
103
+ },
104
+ "graphorin-tools": {
105
+ "anthropicEquivalent": null,
106
+ "policy": "graphorin-only"
107
+ },
108
+ "graphorin-anthropic-spec": {
109
+ "anthropicEquivalent": null,
110
+ "policy": "graphorin-only",
111
+ "rationale": "Author-declared snapshot date the skill was tested against."
112
+ }
113
+ }
114
+ }
@@ -0,0 +1,30 @@
1
+ import { SlashCommandActivation } from "../types/index.js";
2
+
3
+ //#region src/activation/index.d.ts
4
+
5
+ /**
6
+ * Parse a single message body for a `/skill:<name>` invocation. The
7
+ * grammar accepts:
8
+ *
9
+ * ```
10
+ * /skill:<name>
11
+ * /skill:<name> <free-form-args>
12
+ * ```
13
+ *
14
+ * `<name>` must match `^[a-zA-Z0-9][a-zA-Z0-9_.-]{0,127}$` (kebab-case
15
+ * conventional). Whitespace before the leading `/` is tolerated; any
16
+ * other prefix triggers a {@link SlashCommandParseError}.
17
+ *
18
+ * @stable
19
+ */
20
+ declare function parseSlashCommand(raw: string): SlashCommandActivation;
21
+ /**
22
+ * Convenience predicate. Returns `true` when {@link parseSlashCommand}
23
+ * would succeed against the supplied body.
24
+ *
25
+ * @stable
26
+ */
27
+ declare function isSlashCommand(raw: string): boolean;
28
+ //#endregion
29
+ export { isSlashCommand, parseSlashCommand };
30
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","names":[],"sources":["../../src/activation/index.ts"],"sourcesContent":[],"mappings":";;;;;;;;;;;;;;;;;;;iBAsCgB,iBAAA,eAAgC;;;;;;;iBA8BhC,cAAA"}
@@ -0,0 +1,71 @@
1
+ import { SlashCommandParseError } from "../errors/index.js";
2
+
3
+ //#region src/activation/index.ts
4
+ /**
5
+ * Activation surface for `@graphorin/skills`.
6
+ *
7
+ * Two activation paths are supported per DEC-206:
8
+ *
9
+ * 1. **Auto** — every step the agent runtime injects the metadata of
10
+ * every registered skill into the system prompt; the model elects
11
+ * a skill by invoking the synthetic `activate_skill(name)` tool.
12
+ * Skills with `disable-model-invocation: true` are excluded from
13
+ * the metadata advertisement so the model never sees them.
14
+ * 2. **Slash command** — the user types `/skill:<name>` (optionally
15
+ * followed by free-form arguments) and the agent runtime activates
16
+ * the matched skill regardless of `disable-model-invocation`.
17
+ *
18
+ * The runtime owns the actual activation; this module only parses the
19
+ * inputs into a structured payload.
20
+ *
21
+ * @packageDocumentation
22
+ */
23
+ /**
24
+ * Parse a single message body for a `/skill:<name>` invocation. The
25
+ * grammar accepts:
26
+ *
27
+ * ```
28
+ * /skill:<name>
29
+ * /skill:<name> <free-form-args>
30
+ * ```
31
+ *
32
+ * `<name>` must match `^[a-zA-Z0-9][a-zA-Z0-9_.-]{0,127}$` (kebab-case
33
+ * conventional). Whitespace before the leading `/` is tolerated; any
34
+ * other prefix triggers a {@link SlashCommandParseError}.
35
+ *
36
+ * @stable
37
+ */
38
+ function parseSlashCommand(raw) {
39
+ if (typeof raw !== "string" || raw.length === 0) throw new SlashCommandParseError(raw ?? "", "message body must be a non-empty string.");
40
+ const trimmed = raw.replace(/^\s+/u, "");
41
+ if (!trimmed.startsWith("/skill:")) throw new SlashCommandParseError(raw, "message must begin with '/skill:'.");
42
+ const remainder = trimmed.slice(7);
43
+ if (remainder.length === 0) throw new SlashCommandParseError(raw, "missing skill name after '/skill:'.");
44
+ const match = /^([A-Za-z0-9][A-Za-z0-9_.-]{0,127})(?:\s+([\s\S]*))?$/u.exec(remainder);
45
+ if (match === null) throw new SlashCommandParseError(raw, "skill name must match /^[a-zA-Z0-9][a-zA-Z0-9_.-]{0,127}$/.");
46
+ const name = match[1] ?? "";
47
+ const args = (match[2] ?? "").trim();
48
+ return Object.freeze({
49
+ name,
50
+ args,
51
+ raw
52
+ });
53
+ }
54
+ /**
55
+ * Convenience predicate. Returns `true` when {@link parseSlashCommand}
56
+ * would succeed against the supplied body.
57
+ *
58
+ * @stable
59
+ */
60
+ function isSlashCommand(raw) {
61
+ try {
62
+ parseSlashCommand(raw);
63
+ return true;
64
+ } catch {
65
+ return false;
66
+ }
67
+ }
68
+
69
+ //#endregion
70
+ export { isSlashCommand, parseSlashCommand };
71
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","names":[],"sources":["../../src/activation/index.ts"],"sourcesContent":["/**\n * Activation surface for `@graphorin/skills`.\n *\n * Two activation paths are supported per DEC-206:\n *\n * 1. **Auto** — every step the agent runtime injects the metadata of\n * every registered skill into the system prompt; the model elects\n * a skill by invoking the synthetic `activate_skill(name)` tool.\n * Skills with `disable-model-invocation: true` are excluded from\n * the metadata advertisement so the model never sees them.\n * 2. **Slash command** — the user types `/skill:<name>` (optionally\n * followed by free-form arguments) and the agent runtime activates\n * the matched skill regardless of `disable-model-invocation`.\n *\n * The runtime owns the actual activation; this module only parses the\n * inputs into a structured payload.\n *\n * @packageDocumentation\n */\n\nimport { SlashCommandParseError } from '../errors/index.js';\nimport type { SlashCommandActivation } from '../types/index.js';\n\n/**\n * Parse a single message body for a `/skill:<name>` invocation. The\n * grammar accepts:\n *\n * ```\n * /skill:<name>\n * /skill:<name> <free-form-args>\n * ```\n *\n * `<name>` must match `^[a-zA-Z0-9][a-zA-Z0-9_.-]{0,127}$` (kebab-case\n * conventional). Whitespace before the leading `/` is tolerated; any\n * other prefix triggers a {@link SlashCommandParseError}.\n *\n * @stable\n */\nexport function parseSlashCommand(raw: string): SlashCommandActivation {\n if (typeof raw !== 'string' || raw.length === 0) {\n throw new SlashCommandParseError(raw ?? '', 'message body must be a non-empty string.');\n }\n const trimmed = raw.replace(/^\\s+/u, '');\n if (!trimmed.startsWith('/skill:')) {\n throw new SlashCommandParseError(raw, \"message must begin with '/skill:'.\");\n }\n const remainder = trimmed.slice('/skill:'.length);\n if (remainder.length === 0) {\n throw new SlashCommandParseError(raw, \"missing skill name after '/skill:'.\");\n }\n const match = /^([A-Za-z0-9][A-Za-z0-9_.-]{0,127})(?:\\s+([\\s\\S]*))?$/u.exec(remainder);\n if (match === null) {\n throw new SlashCommandParseError(\n raw,\n 'skill name must match /^[a-zA-Z0-9][a-zA-Z0-9_.-]{0,127}$/.',\n );\n }\n const name = match[1] ?? '';\n const args = (match[2] ?? '').trim();\n return Object.freeze({ name, args, raw });\n}\n\n/**\n * Convenience predicate. Returns `true` when {@link parseSlashCommand}\n * would succeed against the supplied body.\n *\n * @stable\n */\nexport function isSlashCommand(raw: string): boolean {\n try {\n parseSlashCommand(raw);\n return true;\n } catch {\n return false;\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAsCA,SAAgB,kBAAkB,KAAqC;AACrE,KAAI,OAAO,QAAQ,YAAY,IAAI,WAAW,EAC5C,OAAM,IAAI,uBAAuB,OAAO,IAAI,2CAA2C;CAEzF,MAAM,UAAU,IAAI,QAAQ,SAAS,GAAG;AACxC,KAAI,CAAC,QAAQ,WAAW,UAAU,CAChC,OAAM,IAAI,uBAAuB,KAAK,qCAAqC;CAE7E,MAAM,YAAY,QAAQ,MAAM,EAAiB;AACjD,KAAI,UAAU,WAAW,EACvB,OAAM,IAAI,uBAAuB,KAAK,sCAAsC;CAE9E,MAAM,QAAQ,yDAAyD,KAAK,UAAU;AACtF,KAAI,UAAU,KACZ,OAAM,IAAI,uBACR,KACA,8DACD;CAEH,MAAM,OAAO,MAAM,MAAM;CACzB,MAAM,QAAQ,MAAM,MAAM,IAAI,MAAM;AACpC,QAAO,OAAO,OAAO;EAAE;EAAM;EAAM;EAAK,CAAC;;;;;;;;AAS3C,SAAgB,eAAe,KAAsB;AACnD,KAAI;AACF,oBAAkB,IAAI;AACtB,SAAO;SACD;AACN,SAAO"}
@@ -0,0 +1,110 @@
1
+ //#region src/errors/index.d.ts
2
+ /**
3
+ * Typed error hierarchy for `@graphorin/skills`.
4
+ *
5
+ * Every error carries a stable lowercase `kind` discriminator so the
6
+ * agent runtime, the CLI, and the audit emitter can branch without
7
+ * resorting to `instanceof` chains, plus an optional `hint` field with
8
+ * an actionable remediation step (a CLI command or a documentation
9
+ * link).
10
+ *
11
+ * @packageDocumentation
12
+ */
13
+ /** Base class for every error thrown by `@graphorin/skills`. */
14
+ declare abstract class GraphorinSkillsError extends Error {
15
+ abstract readonly kind: string;
16
+ readonly hint?: string;
17
+ readonly cause?: unknown;
18
+ constructor(message: string, options?: {
19
+ hint?: string;
20
+ cause?: unknown;
21
+ });
22
+ }
23
+ /**
24
+ * The frontmatter validator detected an Anthropic-base / `graphorin-*`
25
+ * collision and the operator-resolved policy is `'error'`.
26
+ */
27
+ declare class SkillFrontmatterConflictError extends GraphorinSkillsError {
28
+ readonly kind: "frontmatter:conflict";
29
+ readonly skillName: string;
30
+ readonly field: string;
31
+ readonly conflictingFields: ReadonlyArray<string>;
32
+ constructor(skillName: string, field: string, conflictingFields: ReadonlyArray<string>, options?: {
33
+ hint?: string;
34
+ });
35
+ }
36
+ /** A skill manifest could not be parsed (missing frontmatter / invalid YAML). */
37
+ declare class SkillManifestParseError extends GraphorinSkillsError {
38
+ readonly kind: "manifest:parse";
39
+ }
40
+ /**
41
+ * The runtime-compat declaration on a skill does not satisfy the
42
+ * loader's installed runtime version.
43
+ */
44
+ declare class SkillRuntimeCompatError extends GraphorinSkillsError {
45
+ readonly kind: "runtime-compat:mismatch";
46
+ readonly skillName: string;
47
+ readonly declared: string;
48
+ readonly installed: string;
49
+ constructor(skillName: string, declared: string, installed: string, options?: {
50
+ hint?: string;
51
+ });
52
+ }
53
+ /** A required Anthropic-base field is missing from the frontmatter. */
54
+ declare class SkillRequiredFieldMissingError extends GraphorinSkillsError {
55
+ readonly kind: "frontmatter:missing-required";
56
+ readonly field: string;
57
+ constructor(field: string, options?: {
58
+ hint?: string;
59
+ });
60
+ }
61
+ /**
62
+ * `Agent.toTool()` / `handoff(...)` would be invoked inside an
63
+ * untrusted skill, but the skill did not declare
64
+ * `graphorin-handoff-input-filter`. Throwing the error at activation
65
+ * time prevents the runtime from materialising a sub-agent without an
66
+ * explicit filter.
67
+ */
68
+ declare class InputFilterRequiredError extends GraphorinSkillsError {
69
+ readonly kind: "handoff:input-filter-required";
70
+ readonly skillName: string;
71
+ constructor(skillName: string, options?: {
72
+ hint?: string;
73
+ cause?: unknown;
74
+ });
75
+ }
76
+ /** A skill source could not be loaded from disk. */
77
+ declare class SkillLoadError extends GraphorinSkillsError {
78
+ readonly kind: "load:failed";
79
+ readonly source: string;
80
+ constructor(source: string, message: string, options?: {
81
+ hint?: string;
82
+ cause?: unknown;
83
+ });
84
+ }
85
+ /** A skill name in a registry registration collided with another already-loaded skill. */
86
+ declare class SkillNameCollisionError extends GraphorinSkillsError {
87
+ readonly kind: "registry:name-collision";
88
+ readonly skillName: string;
89
+ constructor(skillName: string, options?: {
90
+ hint?: string;
91
+ cause?: unknown;
92
+ });
93
+ }
94
+ /**
95
+ * The slash-command parser received a string that did not match the
96
+ * `/skill:<name>` grammar.
97
+ */
98
+ declare class SlashCommandParseError extends GraphorinSkillsError {
99
+ readonly kind: "slash:parse";
100
+ readonly raw: string;
101
+ constructor(raw: string, message: string, options?: {
102
+ hint?: string;
103
+ cause?: unknown;
104
+ });
105
+ }
106
+ /** Convenience union — every `kind` discriminator the package may emit. */
107
+ type GraphorinSkillsErrorKind = 'frontmatter:conflict' | 'manifest:parse' | 'runtime-compat:mismatch' | 'frontmatter:missing-required' | 'handoff:input-filter-required' | 'load:failed' | 'registry:name-collision' | 'slash:parse';
108
+ //#endregion
109
+ export { GraphorinSkillsError, GraphorinSkillsErrorKind, InputFilterRequiredError, SkillFrontmatterConflictError, SkillLoadError, SkillManifestParseError, SkillNameCollisionError, SkillRequiredFieldMissingError, SkillRuntimeCompatError, SlashCommandParseError };
110
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","names":[],"sources":["../../src/errors/index.ts"],"sourcesContent":[],"mappings":";;AAaA;AAgBA;;;;;AAwBA;AAQA;AAiBA;AAgBA;AAkBA;AAUa,uBA7GS,oBAAA,SAA6B,KAAA,CA6Gc;EAkBpD,kBAAA,IAAA,EAAA,MAAuB;EAaxB,SAAA,IAAA,CAAA,EAAA,MAAA;;;;;;;;;;;cA5HC,6BAAA,SAAsC,oBAAA;;;;8BAIrB;mEAIP;;;;;cAgBV,uBAAA,SAAgC,oBAAA;;;;;;;cAQhC,uBAAA,SAAgC,oBAAA;;;;;;;;;;cAiBhC,8BAAA,SAAuC,oBAAA;;;;;;;;;;;;;;cAgBvC,wBAAA,SAAiC,oBAAA;;;;;;;;;cAkBjC,cAAA,SAAuB,oBAAA;;;;;;;;;cAUvB,uBAAA,SAAgC,oBAAA;;;;;;;;;;;;cAkBhC,sBAAA,SAA+B,oBAAA;;;;;;;;;KAahC,wBAAA"}
@@ -0,0 +1,126 @@
1
+ //#region src/errors/index.ts
2
+ /**
3
+ * Typed error hierarchy for `@graphorin/skills`.
4
+ *
5
+ * Every error carries a stable lowercase `kind` discriminator so the
6
+ * agent runtime, the CLI, and the audit emitter can branch without
7
+ * resorting to `instanceof` chains, plus an optional `hint` field with
8
+ * an actionable remediation step (a CLI command or a documentation
9
+ * link).
10
+ *
11
+ * @packageDocumentation
12
+ */
13
+ /** Base class for every error thrown by `@graphorin/skills`. */
14
+ var GraphorinSkillsError = class extends Error {
15
+ hint;
16
+ cause;
17
+ constructor(message, options) {
18
+ super(message);
19
+ this.name = new.target.name;
20
+ if (options?.hint !== void 0) this.hint = options.hint;
21
+ if (options?.cause !== void 0) this.cause = options.cause;
22
+ }
23
+ };
24
+ /**
25
+ * The frontmatter validator detected an Anthropic-base / `graphorin-*`
26
+ * collision and the operator-resolved policy is `'error'`.
27
+ */
28
+ var SkillFrontmatterConflictError = class extends GraphorinSkillsError {
29
+ kind = "frontmatter:conflict";
30
+ skillName;
31
+ field;
32
+ conflictingFields;
33
+ constructor(skillName, field, conflictingFields, options) {
34
+ super(`Skill '${skillName}' frontmatter conflict on '${field}' (also set: ${conflictingFields.filter((f) => f !== field).join(", ")}). Validator policy: 'error'.`, options);
35
+ this.skillName = skillName;
36
+ this.field = field;
37
+ this.conflictingFields = conflictingFields;
38
+ }
39
+ };
40
+ /** A skill manifest could not be parsed (missing frontmatter / invalid YAML). */
41
+ var SkillManifestParseError = class extends GraphorinSkillsError {
42
+ kind = "manifest:parse";
43
+ };
44
+ /**
45
+ * The runtime-compat declaration on a skill does not satisfy the
46
+ * loader's installed runtime version.
47
+ */
48
+ var SkillRuntimeCompatError = class extends GraphorinSkillsError {
49
+ kind = "runtime-compat:mismatch";
50
+ skillName;
51
+ declared;
52
+ installed;
53
+ constructor(skillName, declared, installed, options) {
54
+ super(`Skill '${skillName}' declares runtime-compat '${declared}' which does not match installed Graphorin '${installed}'.`, options);
55
+ this.skillName = skillName;
56
+ this.declared = declared;
57
+ this.installed = installed;
58
+ }
59
+ };
60
+ /** A required Anthropic-base field is missing from the frontmatter. */
61
+ var SkillRequiredFieldMissingError = class extends GraphorinSkillsError {
62
+ kind = "frontmatter:missing-required";
63
+ field;
64
+ constructor(field, options) {
65
+ super(`Skill frontmatter is missing required field '${field}'.`, options);
66
+ this.field = field;
67
+ }
68
+ };
69
+ /**
70
+ * `Agent.toTool()` / `handoff(...)` would be invoked inside an
71
+ * untrusted skill, but the skill did not declare
72
+ * `graphorin-handoff-input-filter`. Throwing the error at activation
73
+ * time prevents the runtime from materialising a sub-agent without an
74
+ * explicit filter.
75
+ */
76
+ var InputFilterRequiredError = class extends GraphorinSkillsError {
77
+ kind = "handoff:input-filter-required";
78
+ skillName;
79
+ constructor(skillName, options) {
80
+ super(`Untrusted skill '${skillName}' uses Agent.toTool()/handoff() but did not declare 'graphorin-handoff-input-filter'.`, {
81
+ hint: options?.hint ?? "Add 'graphorin-handoff-input-filter: lastUser' (or another supported value) to the SKILL.md frontmatter.",
82
+ ...options?.cause === void 0 ? {} : { cause: options.cause }
83
+ });
84
+ this.skillName = skillName;
85
+ }
86
+ };
87
+ /** A skill source could not be loaded from disk. */
88
+ var SkillLoadError = class extends GraphorinSkillsError {
89
+ kind = "load:failed";
90
+ source;
91
+ constructor(source, message, options) {
92
+ super(`Skill load failed (source='${source}'): ${message}`, options);
93
+ this.source = source;
94
+ }
95
+ };
96
+ /** A skill name in a registry registration collided with another already-loaded skill. */
97
+ var SkillNameCollisionError = class extends GraphorinSkillsError {
98
+ kind = "registry:name-collision";
99
+ skillName;
100
+ constructor(skillName, options) {
101
+ super(`Skill '${skillName}' is already registered.`, {
102
+ hint: options?.hint ?? "Either rename one of the colliding skills or call `registry.unregister(name)` before re-registering.",
103
+ ...options?.cause === void 0 ? {} : { cause: options.cause }
104
+ });
105
+ this.skillName = skillName;
106
+ }
107
+ };
108
+ /**
109
+ * The slash-command parser received a string that did not match the
110
+ * `/skill:<name>` grammar.
111
+ */
112
+ var SlashCommandParseError = class extends GraphorinSkillsError {
113
+ kind = "slash:parse";
114
+ raw;
115
+ constructor(raw, message, options) {
116
+ super(`Slash command '${raw}': ${message}`, {
117
+ hint: options?.hint ?? "Use `/skill:<name>` to activate a registered skill.",
118
+ ...options?.cause === void 0 ? {} : { cause: options.cause }
119
+ });
120
+ this.raw = raw;
121
+ }
122
+ };
123
+
124
+ //#endregion
125
+ export { GraphorinSkillsError, InputFilterRequiredError, SkillFrontmatterConflictError, SkillLoadError, SkillManifestParseError, SkillNameCollisionError, SkillRequiredFieldMissingError, SkillRuntimeCompatError, SlashCommandParseError };
126
+ //# sourceMappingURL=index.js.map