@skill-graph/cli 0.5.6
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 +247 -0
- package/LICENSE +200 -0
- package/NOTICE +62 -0
- package/README.md +398 -0
- package/SKILL_GRAPH.md +443 -0
- package/bin/skill-graph.js +374 -0
- package/docs/ADOPTION.md +117 -0
- package/docs/CONFORMANCE.md +66 -0
- package/docs/PRIMER.md +384 -0
- package/docs/QUICKSTART-30MIN.md +333 -0
- package/docs/ROUTING-METRICS.md +120 -0
- package/docs/SKILL-MD-FORMAT-COMPATIBILITY.md +127 -0
- package/docs/SKILL_AUDIT_CHECKLIST.md +199 -0
- package/docs/SKILL_AUDIT_LOOP.md +195 -0
- package/docs/SKILL_METADATA_PROTOCOL.md +609 -0
- package/docs/_archived/marketplace-publication-priority-2026-05-18.md +239 -0
- package/docs/adr/0001-predicate-set.md +69 -0
- package/docs/adr/0002-json-ld-context.md +82 -0
- package/docs/adr/0003-ontoclean-rigidity-tags.md +65 -0
- package/docs/adr/0004-persistent-identifiers.md +74 -0
- package/docs/adr/0005-freshness-consolidation.md +70 -0
- package/docs/adr/0006-revise-predicate-rename.md +105 -0
- package/docs/adr/0007-audit-loop-cadence.md +99 -0
- package/docs/adr/0008-skill-surface-split-and-curation-policy.md +93 -0
- package/docs/category-consumers.md +168 -0
- package/docs/concept-map.md +194 -0
- package/docs/diagrams/drift-states.mmd +21 -0
- package/docs/diagrams/manifest-pipeline.mmd +25 -0
- package/docs/diagrams/routing-harness.mmd +41 -0
- package/docs/diagrams/starter-graph.mmd +53 -0
- package/docs/field-decision-guide.md +315 -0
- package/docs/field-rationale.md +211 -0
- package/docs/field-reference.generated.md +624 -0
- package/docs/field-reference.md +1426 -0
- package/docs/glossary.md +190 -0
- package/docs/head-noun-glossary.md +63 -0
- package/docs/images/audit-phases.png +0 -0
- package/docs/images/drift-states.png +0 -0
- package/docs/images/graded-mode.png +0 -0
- package/docs/images/manifest-pipeline.png +0 -0
- package/docs/images/routing-harness.png +0 -0
- package/docs/images/skill-anatomy.png +0 -0
- package/docs/images/starter-graph.png +0 -0
- package/docs/images/system-model.png +0 -0
- package/docs/integrations/github-actions.md +155 -0
- package/docs/manifest-field-mapping.md +443 -0
- package/docs/marketplace-publication-queue.generated.md +240 -0
- package/docs/marketplace-release-agent-prompt.md +82 -0
- package/docs/marketplace-skill-candidate-list.md +272 -0
- package/docs/marketplace-syndication.md +222 -0
- package/docs/migration-sample-review.md +155 -0
- package/docs/migrations/v4-to-v5.md +168 -0
- package/docs/migrations/v5-to-v6.md +221 -0
- package/docs/name-exceptions.yaml +37 -0
- package/docs/plans/marketplace-p1-public-migration-plan.md +41 -0
- package/docs/plans/multi-root-workspace.md +148 -0
- package/docs/plans/scripts-roadmap.md +107 -0
- package/docs/plans/v4-schema-bump.md +160 -0
- package/docs/plans/wave-2-extraction.md +122 -0
- package/docs/positioning-vs-marketplaces.md +175 -0
- package/docs/proposals/skill-audit-loop-positioning.md +160 -0
- package/docs/quality-doctrine.md +138 -0
- package/docs/recommended-skills.md +150 -0
- package/docs/research/skill-comprehension-eval-research.md +1830 -0
- package/docs/research/skill-retrieval-evidence.md +66 -0
- package/docs/skill-metadata-protocol.md +471 -0
- package/docs/skills-sh-maintainer-cleanup-request.md +80 -0
- package/examples/audits/a11y/findings.md +52 -0
- package/examples/audits/a11y/scorecard.md +21 -0
- package/examples/audits/a11y/verdict.md +44 -0
- package/examples/audits/debugging/findings.md +59 -0
- package/examples/audits/debugging/scorecard.md +22 -0
- package/examples/audits/debugging/verdict.md +33 -0
- package/examples/audits/documentation/findings.md +59 -0
- package/examples/audits/documentation/scorecard.md +22 -0
- package/examples/audits/documentation/verdict.md +33 -0
- package/examples/evals/a11y.json +140 -0
- package/examples/evals/api-design.json +52 -0
- package/examples/evals/code-review.json +52 -0
- package/examples/evals/data-modeling.json +52 -0
- package/examples/evals/database-migration.json +52 -0
- package/examples/evals/debugging.json +118 -0
- package/examples/evals/dependency-architecture.json +52 -0
- package/examples/evals/design-system-architecture.json +52 -0
- package/examples/evals/error-tracking.json +52 -0
- package/examples/evals/event-contract-design.json +52 -0
- package/examples/evals/form-ux-architecture.json +52 -0
- package/examples/evals/framework-fit-analysis.json +52 -0
- package/examples/evals/graph-audit.json +139 -0
- package/examples/evals/information-architecture.json +52 -0
- package/examples/evals/interaction-feedback.json +52 -0
- package/examples/evals/interaction-patterns.json +52 -0
- package/examples/evals/layout-composition.json +52 -0
- package/examples/evals/lint-overlay.json +117 -0
- package/examples/evals/microcopy.json +52 -0
- package/examples/evals/observability-modeling.json +52 -0
- package/examples/evals/pattern-recognition.json +96 -0
- package/examples/evals/performance-engineering.json +52 -0
- package/examples/evals/refactor.json +128 -0
- package/examples/evals/semiotics.json +52 -0
- package/examples/evals/skill-infrastructure.json +96 -0
- package/examples/evals/skill-router.json +140 -0
- package/examples/evals/skill-router.routing.json +113 -0
- package/examples/evals/system-interface-contracts.json +52 -0
- package/examples/evals/task-analysis.json +52 -0
- package/examples/evals/testing-strategy.json +118 -0
- package/examples/evals/type-safety.json +249 -0
- package/examples/evals/visual-design-foundations.json +52 -0
- package/examples/evals/webhook-integration.json +52 -0
- package/examples/exports/a11y.skill-md.md +80 -0
- package/examples/exports/debugging.skill-md.md +80 -0
- package/examples/exports/refactor.skill-md.md +78 -0
- package/examples/exports/testing-strategy.skill-md.md +81 -0
- package/examples/projects/markdown-static-site/README.md +115 -0
- package/examples/projects/markdown-static-site/skills/content-source-router/SKILL.md +131 -0
- package/examples/projects/markdown-static-site/skills/image-optimization-pipeline-config/SKILL.md +132 -0
- package/examples/projects/markdown-static-site/skills/link-rot-detection/SKILL.md +103 -0
- package/examples/projects/markdown-static-site/skills/markdown-post-frontmatter-validation/SKILL.md +133 -0
- package/examples/projects/markdown-static-site/skills/migrate-posts-to-v2-frontmatter/SKILL.md +140 -0
- package/examples/projects/saas-stripe-postgres/README.md +208 -0
- package/examples/projects/saas-stripe-postgres/db/migrations/0004_canonicalize_orders.sql +37 -0
- package/examples/projects/saas-stripe-postgres/db/schema.sql +112 -0
- package/examples/projects/saas-stripe-postgres/skills/migrate-orders-to-canonical-schema/SKILL.md +149 -0
- package/examples/projects/saas-stripe-postgres/skills/nextjs-server-action-validation/SKILL.md +154 -0
- package/examples/projects/saas-stripe-postgres/skills/payment-provider-router/SKILL.md +153 -0
- package/examples/projects/saas-stripe-postgres/skills/postgres-rls-pattern/SKILL.md +163 -0
- package/examples/projects/saas-stripe-postgres/skills/stripe-webhook-signature-verification/SKILL.md +137 -0
- package/examples/protocol/skill-metadata-template.md +301 -0
- package/examples/protocol/skills.manifest.sample.json +13245 -0
- package/examples/skill-metadata-template.md +317 -0
- package/examples/skills.manifest.sample.json +13519 -0
- package/examples/tests/v3-1-skos-fixture/SKILL.md +93 -0
- package/marketplace/README.md +17 -0
- package/marketplace/skills/a11y/SKILL.md +66 -0
- package/marketplace/skills/acid-fundamentals/SKILL.md +106 -0
- package/marketplace/skills/agent-engineering/SKILL.md +386 -0
- package/marketplace/skills/agent-eval-design/SKILL.md +55 -0
- package/marketplace/skills/ai-native-development/SKILL.md +294 -0
- package/marketplace/skills/api-design/SKILL.md +60 -0
- package/marketplace/skills/architecture-decision-records/SKILL.md +55 -0
- package/marketplace/skills/background-jobs/SKILL.md +265 -0
- package/marketplace/skills/bounded-context-mapping/SKILL.md +55 -0
- package/marketplace/skills/cap-theorem-tradeoffs/SKILL.md +127 -0
- package/marketplace/skills/client-server-boundary/SKILL.md +187 -0
- package/marketplace/skills/code-review/SKILL.md +120 -0
- package/marketplace/skills/color-system-design/SKILL.md +43 -0
- package/marketplace/skills/component-architecture/SKILL.md +126 -0
- package/marketplace/skills/compression/SKILL.md +112 -0
- package/marketplace/skills/conceptual-modeling/SKILL.md +181 -0
- package/marketplace/skills/connection-pooling/SKILL.md +105 -0
- package/marketplace/skills/constraint-awareness/SKILL.md +287 -0
- package/marketplace/skills/content-monitor/SKILL.md +209 -0
- package/marketplace/skills/context-engineering/SKILL.md +320 -0
- package/marketplace/skills/context-graph/SKILL.md +174 -0
- package/marketplace/skills/context-management/SKILL.md +174 -0
- package/marketplace/skills/context-window/SKILL.md +239 -0
- package/marketplace/skills/contract-testing/SKILL.md +120 -0
- package/marketplace/skills/cron-scheduling/SKILL.md +223 -0
- package/marketplace/skills/dark-mode-implementation/SKILL.md +47 -0
- package/marketplace/skills/data-modeling/SKILL.md +59 -0
- package/marketplace/skills/data-modeling-fundamentals/SKILL.md +117 -0
- package/marketplace/skills/database-migration/SKILL.md +429 -0
- package/marketplace/skills/debugging/SKILL.md +67 -0
- package/marketplace/skills/dependency-architecture/SKILL.md +58 -0
- package/marketplace/skills/design-module-composition/SKILL.md +43 -0
- package/marketplace/skills/design-system-architecture/SKILL.md +61 -0
- package/marketplace/skills/design-thinking/SKILL.md +44 -0
- package/marketplace/skills/diagnosis/SKILL.md +296 -0
- package/marketplace/skills/diff-analysis/SKILL.md +188 -0
- package/marketplace/skills/e2e-test-design/SKILL.md +113 -0
- package/marketplace/skills/entity-relationship-modeling/SKILL.md +218 -0
- package/marketplace/skills/epistemic-grounding/SKILL.md +112 -0
- package/marketplace/skills/error-boundary/SKILL.md +235 -0
- package/marketplace/skills/error-tracking/SKILL.md +261 -0
- package/marketplace/skills/eval-driven-development/SKILL.md +147 -0
- package/marketplace/skills/evaluation/SKILL.md +113 -0
- package/marketplace/skills/event-contract-design/SKILL.md +60 -0
- package/marketplace/skills/event-storming/SKILL.md +56 -0
- package/marketplace/skills/form-ux-architecture/SKILL.md +60 -0
- package/marketplace/skills/framework-fit-analysis/SKILL.md +59 -0
- package/marketplace/skills/frontend-architecture/SKILL.md +43 -0
- package/marketplace/skills/generative-ui/SKILL.md +118 -0
- package/marketplace/skills/graph-audit/SKILL.md +81 -0
- package/marketplace/skills/guardrails/SKILL.md +118 -0
- package/marketplace/skills/hooks-patterns/SKILL.md +185 -0
- package/marketplace/skills/http-semantics/SKILL.md +136 -0
- package/marketplace/skills/ideation/SKILL.md +41 -0
- package/marketplace/skills/indexing-strategy/SKILL.md +108 -0
- package/marketplace/skills/information-architecture/SKILL.md +59 -0
- package/marketplace/skills/integration-test-design/SKILL.md +111 -0
- package/marketplace/skills/intent-recognition/SKILL.md +136 -0
- package/marketplace/skills/interaction-feedback/SKILL.md +59 -0
- package/marketplace/skills/interaction-patterns/SKILL.md +59 -0
- package/marketplace/skills/journey-mapping/SKILL.md +41 -0
- package/marketplace/skills/keywords/SKILL.md +213 -0
- package/marketplace/skills/knowledge-modeling/SKILL.md +232 -0
- package/marketplace/skills/layout-composition/SKILL.md +59 -0
- package/marketplace/skills/linguistics/SKILL.md +429 -0
- package/marketplace/skills/lint-overlay/SKILL.md +76 -0
- package/marketplace/skills/mental-models/SKILL.md +126 -0
- package/marketplace/skills/merge-queue/SKILL.md +94 -0
- package/marketplace/skills/methodology/SKILL.md +317 -0
- package/marketplace/skills/microcopy/SKILL.md +232 -0
- package/marketplace/skills/middleware-patterns/SKILL.md +363 -0
- package/marketplace/skills/mobile-responsive-ux/SKILL.md +287 -0
- package/marketplace/skills/mutation-testing/SKILL.md +112 -0
- package/marketplace/skills/naming-conventions/SKILL.md +112 -0
- package/marketplace/skills/observability-modeling/SKILL.md +59 -0
- package/marketplace/skills/ontology-modeling/SKILL.md +67 -0
- package/marketplace/skills/owasp-security/SKILL.md +153 -0
- package/marketplace/skills/pattern-recognition/SKILL.md +472 -0
- package/marketplace/skills/performance-budgets/SKILL.md +185 -0
- package/marketplace/skills/performance-engineering/SKILL.md +58 -0
- package/marketplace/skills/performance-testing/SKILL.md +125 -0
- package/marketplace/skills/printify/SKILL.md +42 -0
- package/marketplace/skills/prioritization/SKILL.md +118 -0
- package/marketplace/skills/problem-framing/SKILL.md +41 -0
- package/marketplace/skills/problem-locating-solving/SKILL.md +203 -0
- package/marketplace/skills/project-knowledge-extraction/SKILL.md +54 -0
- package/marketplace/skills/prompt-craft/SKILL.md +134 -0
- package/marketplace/skills/prompt-injection-defense/SKILL.md +132 -0
- package/marketplace/skills/property-based-testing/SKILL.md +100 -0
- package/marketplace/skills/prototyping/SKILL.md +43 -0
- package/marketplace/skills/query-optimization/SKILL.md +144 -0
- package/marketplace/skills/real-time-updates/SKILL.md +324 -0
- package/marketplace/skills/ref-patterns/SKILL.md +284 -0
- package/marketplace/skills/refactor/SKILL.md +65 -0
- package/marketplace/skills/rendering-models/SKILL.md +142 -0
- package/marketplace/skills/replication-patterns/SKILL.md +110 -0
- package/marketplace/skills/research-synthesis/SKILL.md +41 -0
- package/marketplace/skills/route-handler-design/SKILL.md +347 -0
- package/marketplace/skills/schema-evolution/SKILL.md +140 -0
- package/marketplace/skills/security-fundamentals/SKILL.md +139 -0
- package/marketplace/skills/semantic-center/SKILL.md +194 -0
- package/marketplace/skills/semantic-relations/SKILL.md +250 -0
- package/marketplace/skills/semantics/SKILL.md +366 -0
- package/marketplace/skills/semiotics/SKILL.md +230 -0
- package/marketplace/skills/seo-strategy/SKILL.md +260 -0
- package/marketplace/skills/server-actions-design/SKILL.md +243 -0
- package/marketplace/skills/server-components-design/SKILL.md +190 -0
- package/marketplace/skills/sharding-strategy/SKILL.md +123 -0
- package/marketplace/skills/shopify/SKILL.md +42 -0
- package/marketplace/skills/skill-infrastructure/SKILL.md +320 -0
- package/marketplace/skills/skill-router/SKILL.md +71 -0
- package/marketplace/skills/skill-scaffold/SKILL.md +105 -0
- package/marketplace/skills/snapshot-testing/SKILL.md +120 -0
- package/marketplace/skills/spec-driven-development/SKILL.md +148 -0
- package/marketplace/skills/state-machine-modeling/SKILL.md +56 -0
- package/marketplace/skills/state-management/SKILL.md +134 -0
- package/marketplace/skills/streaming-architecture/SKILL.md +194 -0
- package/marketplace/skills/summarization/SKILL.md +156 -0
- package/marketplace/skills/suspense-patterns/SKILL.md +265 -0
- package/marketplace/skills/system-interface-contracts/SKILL.md +59 -0
- package/marketplace/skills/task-analysis/SKILL.md +201 -0
- package/marketplace/skills/taxonomy-design/SKILL.md +66 -0
- package/marketplace/skills/test-coverage-strategy/SKILL.md +108 -0
- package/marketplace/skills/test-doubles-design/SKILL.md +98 -0
- package/marketplace/skills/test-driven-development/SKILL.md +96 -0
- package/marketplace/skills/testing-strategy/SKILL.md +67 -0
- package/marketplace/skills/theme-system-design/SKILL.md +43 -0
- package/marketplace/skills/tool-call-flow/SKILL.md +229 -0
- package/marketplace/skills/tool-call-strategy/SKILL.md +292 -0
- package/marketplace/skills/transaction-isolation/SKILL.md +98 -0
- package/marketplace/skills/type-safety/SKILL.md +177 -0
- package/marketplace/skills/typography-system/SKILL.md +43 -0
- package/marketplace/skills/usability-testing/SKILL.md +43 -0
- package/marketplace/skills/user-research/SKILL.md +43 -0
- package/marketplace/skills/vercel-composition-patterns/SKILL.md +157 -0
- package/marketplace/skills/version-control/SKILL.md +233 -0
- package/marketplace/skills/visual-design-foundations/SKILL.md +59 -0
- package/marketplace/skills/visual-hierarchy/SKILL.md +43 -0
- package/marketplace/skills/webhook-integration/SKILL.md +331 -0
- package/marketplace/skills/writing-humanizer/SKILL.md +380 -0
- package/package.json +67 -0
- package/schemas/manifest.schema.json +811 -0
- package/schemas/manifest.v2.schema.json +164 -0
- package/schemas/manifest.v3.schema.json +758 -0
- package/schemas/manifest.v4.schema.json +755 -0
- package/schemas/manifest.v5.schema.json +755 -0
- package/schemas/manifest.v6.schema.json +811 -0
- package/schemas/skill.context.jsonld +279 -0
- package/schemas/skill.schema.json +919 -0
- package/schemas/skill.v2.schema.json +201 -0
- package/schemas/skill.v3.schema.json +827 -0
- package/schemas/skill.v4.schema.json +822 -0
- package/schemas/skill.v5.schema.json +830 -0
- package/schemas/skill.v6.schema.json +946 -0
- package/schemas/vocabulary/keywords.json +180 -0
- package/schemas/vocabulary/workspace_tags.json +23 -0
- package/scripts/__tests__/migrate-skill-v2-to-v3.test.js +161 -0
- package/scripts/__tests__/migrate-skill-v3-to-v4.test.js +158 -0
- package/scripts/__tests__/test-export-parser-drift.js +149 -0
- package/scripts/__tests__/test-marketplace-export.js +114 -0
- package/scripts/__tests__/test-router-paths.js +82 -0
- package/scripts/__tests__/test-stability-promotion.js +244 -0
- package/scripts/__tests__/test-v3-1-alias-contract.js +109 -0
- package/scripts/__tests__/test-v3-1-skos-runtime.js +116 -0
- package/scripts/backfill-schema-version.js +198 -0
- package/scripts/build-field-reference.js +160 -0
- package/scripts/build-retrieval-baseline.js +511 -0
- package/scripts/check-markdown-links.js +211 -0
- package/scripts/check-protocol-consistency.js +979 -0
- package/scripts/export-marketplace-skills.js +610 -0
- package/scripts/export-skill.js +374 -0
- package/scripts/generate-manifest.js +787 -0
- package/scripts/lib/alias-contract.js +83 -0
- package/scripts/lib/audit-prompt-builder.js +771 -0
- package/scripts/lib/mock-grader.js +134 -0
- package/scripts/lib/parse-frontmatter.js +429 -0
- package/scripts/lib/roots.js +119 -0
- package/scripts/lint/check-archetype-sections.js +185 -0
- package/scripts/lint/check-category-enum.js +83 -0
- package/scripts/lint/check-routing-eval.js +146 -0
- package/scripts/lint/check-routing-quality.js +211 -0
- package/scripts/lint/check-stability-promotion.js +220 -0
- package/scripts/lint/format-code-frame.js +206 -0
- package/scripts/marketplace-install.js +125 -0
- package/scripts/migrate-category-to-enum.js +169 -0
- package/scripts/migrate-skill-v2-to-v3.js +424 -0
- package/scripts/migrate-skill-v3-to-v4.js +200 -0
- package/scripts/migrate-skill-v5-to-v6.js +304 -0
- package/scripts/restructure-by-category.js +85 -0
- package/scripts/seed-publication-classification.js +282 -0
- package/scripts/skill-audit.js +893 -0
- package/scripts/skill-graph-drift.js +483 -0
- package/scripts/skill-graph-route.js +766 -0
- package/scripts/skill-graph-routing-eval.js +393 -0
- package/scripts/skill-lint.js +1317 -0
- package/scripts/skill-overlap.js +213 -0
- package/scripts/verify-skill-md-export.js +201 -0
|
@@ -0,0 +1,220 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Stability promotion gate for SKILL.md files (lint check 14).
|
|
4
|
+
*
|
|
5
|
+
* **S1 — stability: stable requires promotion criteria (WARN)**
|
|
6
|
+
* A skill that declares `stability: stable` is claiming its content is
|
|
7
|
+
* settled and suitable for production dependence. This check enforces that
|
|
8
|
+
* the claim is backed by evidence across five independently-checked criteria.
|
|
9
|
+
*
|
|
10
|
+
* All failures are WARN level — never ERROR. Setting `stability: stable`
|
|
11
|
+
* does not break builds; it triggers an audit trail so authors know which
|
|
12
|
+
* criteria remain unmet. This design choice is intentional: 141 skills are
|
|
13
|
+
* currently `experimental`. If violations were errors, a single `stable`
|
|
14
|
+
* claim on an unready skill would block the entire lint run for that skill.
|
|
15
|
+
* Warnings surface the gap without creating a false blocker.
|
|
16
|
+
*
|
|
17
|
+
* The five promotion criteria (all checked independently — no short-circuit):
|
|
18
|
+
*
|
|
19
|
+
* 1. `eval_state` ≠ `unverified` — evals have been run at least once.
|
|
20
|
+
* `passing` or `monitored` both satisfy this criterion.
|
|
21
|
+
*
|
|
22
|
+
* 2. `eval_score` ≥ 4.0 (80% of the 0.0–5.0 audit scale) — the most
|
|
23
|
+
* recent graded audit score meets the quality bar. Absent `eval_score`
|
|
24
|
+
* fails this criterion because an unscored skill has no evidence of
|
|
25
|
+
* quality.
|
|
26
|
+
*
|
|
27
|
+
* 3. `routing_eval: present` — routing coverage is explicitly evaluated.
|
|
28
|
+
* A stable skill must prove it activates correctly, not just claim it
|
|
29
|
+
* does.
|
|
30
|
+
*
|
|
31
|
+
* 4. `drift_check.last_verified` within the last 90 days — the skill has
|
|
32
|
+
* been actively maintained. A last_verified date older than 90 days
|
|
33
|
+
* indicates the content may have drifted from its truth sources.
|
|
34
|
+
*
|
|
35
|
+
* 5. `grounding.truth_sources` populated (for `scope: codebase` and
|
|
36
|
+
* `scope: reference` skills) OR `scope: portable` (general skills with
|
|
37
|
+
* no codebase tie-in are exempt from this criterion). A stable
|
|
38
|
+
* codebase/reference skill must declare what it is grounded in.
|
|
39
|
+
*
|
|
40
|
+
* @module lint/check-stability-promotion
|
|
41
|
+
*/
|
|
42
|
+
|
|
43
|
+
'use strict';
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Minimum eval score to qualify for stable promotion.
|
|
47
|
+
* Maps to 80% of the 0.0–5.0 audit scale used by scripts/skill-audit.js.
|
|
48
|
+
*/
|
|
49
|
+
const STABLE_EVAL_SCORE_THRESHOLD = 4.0;
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Maximum age in days for drift_check.last_verified before a stable skill
|
|
53
|
+
* is considered potentially drifted.
|
|
54
|
+
*/
|
|
55
|
+
const STABLE_DRIFT_MAX_DAYS = 90;
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Scope values that require grounding.truth_sources to be populated.
|
|
59
|
+
* portable-scope skills are exempt (criterion 5 does not apply).
|
|
60
|
+
*/
|
|
61
|
+
const GROUNDING_REQUIRED_SCOPES = ['codebase', 'reference'];
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Run the stability-promotion check on one SKILL.md file.
|
|
65
|
+
*
|
|
66
|
+
* Only fires when `stability === "stable"`. When the skill is experimental
|
|
67
|
+
* or deprecated, or when `stability` is absent, this function returns early
|
|
68
|
+
* with empty arrays.
|
|
69
|
+
*
|
|
70
|
+
* All findings are WARN level. The caller is responsible for routing them
|
|
71
|
+
* into the warning track rather than the error track.
|
|
72
|
+
*
|
|
73
|
+
* @param {object} opts
|
|
74
|
+
* @param {string} opts.filePath - Path to the file (used in messages only).
|
|
75
|
+
* @param {string} opts.sourceText - Full file content.
|
|
76
|
+
* @param {object} opts.fm - Parsed frontmatter object.
|
|
77
|
+
* @param {Date} [opts.today] - Reference date for age checks (injectable
|
|
78
|
+
* for tests; defaults to new Date()).
|
|
79
|
+
*
|
|
80
|
+
* @returns {{
|
|
81
|
+
* errors: Array<{message: string, line: number, column: number, help: string}>,
|
|
82
|
+
* warnings: Array<{message: string, line: number, column: number, help: string}>
|
|
83
|
+
* }}
|
|
84
|
+
*/
|
|
85
|
+
function checkStabilityPromotion(opts) {
|
|
86
|
+
const { sourceText, fm } = opts;
|
|
87
|
+
const today = opts.today || new Date();
|
|
88
|
+
const warnings = [];
|
|
89
|
+
|
|
90
|
+
if (!fm || fm.stability !== 'stable') return { errors: [], warnings };
|
|
91
|
+
|
|
92
|
+
// Locate the `stability` key in the frontmatter for code-frame anchoring.
|
|
93
|
+
const keyLine = locateKey(sourceText, 'stability') || { line: 1, column: 1 };
|
|
94
|
+
|
|
95
|
+
// ── Criterion 1: eval_state ≠ "unverified" ─────────────────────────────────
|
|
96
|
+
// eval_state must be "passing" or "monitored" to qualify.
|
|
97
|
+
const evalState = fm.eval_state || (fm.eval && fm.eval.content_state);
|
|
98
|
+
if (!evalState || evalState === 'unverified') {
|
|
99
|
+
warnings.push({
|
|
100
|
+
message: `stability: stable — criterion 1 unmet: eval_state is "${evalState || 'absent'}" (must be "passing" or "monitored")`,
|
|
101
|
+
line: keyLine.line,
|
|
102
|
+
column: keyLine.column,
|
|
103
|
+
help: 'Run the eval suite, verify results, and set eval_state to "passing" or "monitored". See docs/field-reference.md § eval_state.',
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
// ── Criterion 2: eval_score ≥ 4.0 ──────────────────────────────────────────
|
|
108
|
+
// The 0.0–5.0 audit score; absent or below threshold fails.
|
|
109
|
+
const evalScore = fm.eval_score;
|
|
110
|
+
if (typeof evalScore !== 'number') {
|
|
111
|
+
warnings.push({
|
|
112
|
+
message: `stability: stable — criterion 2 unmet: eval_score is absent (must be ≥ ${STABLE_EVAL_SCORE_THRESHOLD} on the 0.0–5.0 scale)`,
|
|
113
|
+
line: keyLine.line,
|
|
114
|
+
column: keyLine.column,
|
|
115
|
+
help: 'Run `node scripts/skill-audit.js` to produce a graded score and record it in eval_score. See docs/field-reference.md § eval_score.',
|
|
116
|
+
});
|
|
117
|
+
} else if (evalScore < STABLE_EVAL_SCORE_THRESHOLD) {
|
|
118
|
+
warnings.push({
|
|
119
|
+
message: `stability: stable — criterion 2 unmet: eval_score ${evalScore} < ${STABLE_EVAL_SCORE_THRESHOLD} (80% threshold on the 0.0–5.0 scale)`,
|
|
120
|
+
line: keyLine.line,
|
|
121
|
+
column: keyLine.column,
|
|
122
|
+
help: `Improve the skill until eval_score reaches ${STABLE_EVAL_SCORE_THRESHOLD}. Run \`node scripts/skill-audit.js\` to grade. See docs/field-reference.md § eval_score.`,
|
|
123
|
+
});
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
// ── Criterion 3: routing_eval: present ─────────────────────────────────────
|
|
127
|
+
const routingEval = fm.routing_eval || (fm.eval && fm.eval.routing_coverage);
|
|
128
|
+
if (routingEval !== 'present') {
|
|
129
|
+
warnings.push({
|
|
130
|
+
message: `stability: stable — criterion 3 unmet: routing_eval is "${routingEval || 'absent'}" (must be "present")`,
|
|
131
|
+
line: keyLine.line,
|
|
132
|
+
column: keyLine.column,
|
|
133
|
+
help: 'Populate examples[] and anti_examples[], then verify with `node scripts/skill-graph-routing-eval.js`. Set routing_eval to "present" once the harness passes. See docs/field-reference.md § routing_eval.',
|
|
134
|
+
});
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
// ── Criterion 4: drift_check.last_verified within 90 days ──────────────────
|
|
138
|
+
const lastVerified = fm.drift_check && fm.drift_check.last_verified;
|
|
139
|
+
if (!lastVerified) {
|
|
140
|
+
warnings.push({
|
|
141
|
+
message: `stability: stable — criterion 4 unmet: drift_check.last_verified is absent (must be within last ${STABLE_DRIFT_MAX_DAYS} days)`,
|
|
142
|
+
line: keyLine.line,
|
|
143
|
+
column: keyLine.column,
|
|
144
|
+
help: `Set a drift baseline and verify: \`node scripts/skill-graph-drift.js --record --apply <skill-path>\`. See docs/field-reference.md § drift_check.`,
|
|
145
|
+
});
|
|
146
|
+
} else {
|
|
147
|
+
const verifiedDate = new Date(lastVerified);
|
|
148
|
+
if (Number.isNaN(verifiedDate.getTime())) {
|
|
149
|
+
warnings.push({
|
|
150
|
+
message: `stability: stable — criterion 4 unmet: drift_check.last_verified "${lastVerified}" is not a valid ISO 8601 date`,
|
|
151
|
+
line: keyLine.line,
|
|
152
|
+
column: keyLine.column,
|
|
153
|
+
help: 'Use ISO 8601 format (YYYY-MM-DD). See docs/field-reference.md § drift_check.',
|
|
154
|
+
});
|
|
155
|
+
} else {
|
|
156
|
+
const daysOld = (today.getTime() - verifiedDate.getTime()) / (24 * 60 * 60 * 1000);
|
|
157
|
+
if (daysOld > STABLE_DRIFT_MAX_DAYS) {
|
|
158
|
+
warnings.push({
|
|
159
|
+
message: `stability: stable — criterion 4 unmet: drift_check.last_verified is ${Math.round(daysOld)} days ago (limit: ${STABLE_DRIFT_MAX_DAYS} days)`,
|
|
160
|
+
line: keyLine.line,
|
|
161
|
+
column: keyLine.column,
|
|
162
|
+
help: `Re-verify against truth sources and update drift_check.last_verified: \`node scripts/skill-graph-drift.js --record --apply <skill-path>\`.`,
|
|
163
|
+
});
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
// ── Criterion 5: grounding.truth_sources populated (codebase/reference) ────
|
|
169
|
+
// portable-scope skills are exempt — they have no codebase tie-in.
|
|
170
|
+
const scope = fm.scope;
|
|
171
|
+
if (GROUNDING_REQUIRED_SCOPES.includes(scope)) {
|
|
172
|
+
const truthSources =
|
|
173
|
+
fm.grounding && Array.isArray(fm.grounding.truth_sources)
|
|
174
|
+
? fm.grounding.truth_sources
|
|
175
|
+
: [];
|
|
176
|
+
if (truthSources.length === 0) {
|
|
177
|
+
warnings.push({
|
|
178
|
+
message: `stability: stable — criterion 5 unmet: grounding.truth_sources is absent or empty (required for scope: ${scope})`,
|
|
179
|
+
line: keyLine.line,
|
|
180
|
+
column: keyLine.column,
|
|
181
|
+
help: 'Declare at least one truth source in grounding.truth_sources. See docs/field-reference.md § grounding and docs/skill-metadata-protocol.md § Stability Promotion Criteria.',
|
|
182
|
+
});
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
// portable-scope skills are implicitly exempt (criterion 5 does not apply).
|
|
186
|
+
|
|
187
|
+
return { errors: [], warnings };
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
/**
|
|
191
|
+
* Locate a YAML key in the frontmatter block and return its { line, column }.
|
|
192
|
+
* Mirrors the pattern used in check-routing-eval.js.
|
|
193
|
+
*
|
|
194
|
+
* @param {string} sourceText - Full file content.
|
|
195
|
+
* @param {string} key - YAML key name to locate.
|
|
196
|
+
* @returns {{ line: number, column: number } | null}
|
|
197
|
+
*/
|
|
198
|
+
function locateKey(sourceText, key) {
|
|
199
|
+
const lines = sourceText.split('\n');
|
|
200
|
+
let dashCount = 0;
|
|
201
|
+
let inside = false;
|
|
202
|
+
for (let i = 0; i < lines.length; i++) {
|
|
203
|
+
if (lines[i].trim() === '---') {
|
|
204
|
+
dashCount++;
|
|
205
|
+
if (dashCount === 1) { inside = true; continue; }
|
|
206
|
+
if (dashCount === 2) break;
|
|
207
|
+
}
|
|
208
|
+
if (!inside) continue;
|
|
209
|
+
const m = lines[i].match(new RegExp(`^(\\s*)${key}\\s*:`));
|
|
210
|
+
if (m) return { line: i + 1, column: m[1].length + 1 };
|
|
211
|
+
}
|
|
212
|
+
return null;
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
module.exports = {
|
|
216
|
+
checkStabilityPromotion,
|
|
217
|
+
STABLE_EVAL_SCORE_THRESHOLD,
|
|
218
|
+
STABLE_DRIFT_MAX_DAYS,
|
|
219
|
+
GROUNDING_REQUIRED_SCOPES,
|
|
220
|
+
};
|
|
@@ -0,0 +1,206 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Code-frame formatter for skill-lint error messages.
|
|
4
|
+
*
|
|
5
|
+
* Renders a diagnostic in the style popularised by Babel and Rust:
|
|
6
|
+
*
|
|
7
|
+
* skills/a11y/SKILL.md:3:1
|
|
8
|
+
*
|
|
9
|
+
* 1 | ---
|
|
10
|
+
* 2 | schema_version: 2
|
|
11
|
+
* > 3 | nme: a11y
|
|
12
|
+
* | ^ unknown field: nme
|
|
13
|
+
* 4 | description: "..."
|
|
14
|
+
* 5 | version: 1.0.0
|
|
15
|
+
*
|
|
16
|
+
* help: Remove or rename 'nme' to a known field. See docs/field-reference.md.
|
|
17
|
+
*
|
|
18
|
+
* Zero external dependencies. Uses only Node.js built-ins.
|
|
19
|
+
*
|
|
20
|
+
* @module lint/format-code-frame
|
|
21
|
+
*/
|
|
22
|
+
|
|
23
|
+
'use strict';
|
|
24
|
+
|
|
25
|
+
// ANSI colour codes. Disabled when noColor === true.
|
|
26
|
+
const COLORS = {
|
|
27
|
+
red: '\x1b[31m',
|
|
28
|
+
yellow: '\x1b[33m',
|
|
29
|
+
cyan: '\x1b[36m',
|
|
30
|
+
bold: '\x1b[1m',
|
|
31
|
+
dim: '\x1b[2m',
|
|
32
|
+
reset: '\x1b[0m',
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Return a colour-escaped string, or the plain string if colour is disabled.
|
|
37
|
+
*
|
|
38
|
+
* @param {string} text
|
|
39
|
+
* @param {string} colorCode - Key from the COLORS map.
|
|
40
|
+
* @param {boolean} noColor - When true, no ANSI codes are emitted.
|
|
41
|
+
* @returns {string}
|
|
42
|
+
*/
|
|
43
|
+
function colorize(text, colorCode, noColor) {
|
|
44
|
+
if (noColor) return text;
|
|
45
|
+
return `${COLORS[colorCode] || ''}${text}${COLORS.reset}`;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Format a diagnostic message with a code frame.
|
|
50
|
+
*
|
|
51
|
+
* @param {object} opts
|
|
52
|
+
* @param {string} opts.filePath - Path to the file, relative to repo root.
|
|
53
|
+
* @param {number} opts.line - 1-based line number of the error.
|
|
54
|
+
* @param {number} [opts.column=1] - 1-based column number of the error.
|
|
55
|
+
* @param {string} opts.message - Short error description (no trailing period needed).
|
|
56
|
+
* @param {string} [opts.help] - Optional help/fix hint shown after the frame.
|
|
57
|
+
* @param {string} opts.sourceText - Full text of the file (used to extract the frame).
|
|
58
|
+
* @param {'error'|'warn'} [opts.severity='error'] - Controls caret colour.
|
|
59
|
+
* @param {boolean} [opts.noColor=false] - Suppress ANSI codes (CI / --no-color).
|
|
60
|
+
* @param {number} [opts.context=2] - Lines of context above and below the target line.
|
|
61
|
+
* @returns {string} Multi-line formatted diagnostic string.
|
|
62
|
+
*/
|
|
63
|
+
function formatCodeFrame(opts) {
|
|
64
|
+
const {
|
|
65
|
+
filePath,
|
|
66
|
+
line,
|
|
67
|
+
column = 1,
|
|
68
|
+
message,
|
|
69
|
+
help,
|
|
70
|
+
sourceText,
|
|
71
|
+
severity = 'error',
|
|
72
|
+
noColor = false,
|
|
73
|
+
context = 2,
|
|
74
|
+
} = opts;
|
|
75
|
+
|
|
76
|
+
const lines = sourceText.split('\n');
|
|
77
|
+
const targetIdx = line - 1; // 0-based
|
|
78
|
+
|
|
79
|
+
// Guard against out-of-range line numbers.
|
|
80
|
+
if (targetIdx < 0 || targetIdx >= lines.length) {
|
|
81
|
+
return formatSimple({ filePath, line, column, message, help, severity, noColor });
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
const firstLine = Math.max(0, targetIdx - context);
|
|
85
|
+
const lastLine = Math.min(lines.length - 1, targetIdx + context);
|
|
86
|
+
|
|
87
|
+
// Width of the line-number gutter (right-aligned).
|
|
88
|
+
const gutterWidth = String(lastLine + 1).length;
|
|
89
|
+
|
|
90
|
+
const caretColor = severity === 'warn' ? 'yellow' : 'red';
|
|
91
|
+
const labelColor = severity === 'warn' ? 'yellow' : 'red';
|
|
92
|
+
const label = severity === 'warn' ? 'warn' : 'error';
|
|
93
|
+
|
|
94
|
+
// Header: file:line:col
|
|
95
|
+
const header = colorize(
|
|
96
|
+
`${filePath}:${line}:${column}`,
|
|
97
|
+
'cyan',
|
|
98
|
+
noColor
|
|
99
|
+
);
|
|
100
|
+
|
|
101
|
+
// Severity prefix
|
|
102
|
+
const severityLabel = colorize(`[${label}]`, labelColor, noColor);
|
|
103
|
+
|
|
104
|
+
const frameLines = [];
|
|
105
|
+
|
|
106
|
+
for (let i = firstLine; i <= lastLine; i++) {
|
|
107
|
+
const lineNum = i + 1;
|
|
108
|
+
const gutter = String(lineNum).padStart(gutterWidth);
|
|
109
|
+
const isTarget = i === targetIdx;
|
|
110
|
+
const indicator = isTarget ? colorize('>', 'bold', noColor) : ' ';
|
|
111
|
+
const gutterStr = colorize(`${gutter} |`, 'dim', noColor);
|
|
112
|
+
|
|
113
|
+
if (isTarget) {
|
|
114
|
+
frameLines.push(`${indicator} ${gutterStr} ${lines[i]}`);
|
|
115
|
+
// Caret line
|
|
116
|
+
const caretPad = ' '.repeat(gutterWidth + 4 + (column - 1));
|
|
117
|
+
const caret = colorize('^', caretColor, noColor);
|
|
118
|
+
const caretMsg = colorize(message, caretColor, noColor);
|
|
119
|
+
frameLines.push(`${caretPad}${caret} ${caretMsg}`);
|
|
120
|
+
} else {
|
|
121
|
+
frameLines.push(` ${gutterStr} ${lines[i]}`);
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
const parts = [
|
|
126
|
+
'',
|
|
127
|
+
`${severityLabel} ${header}`,
|
|
128
|
+
'',
|
|
129
|
+
...frameLines,
|
|
130
|
+
'',
|
|
131
|
+
];
|
|
132
|
+
|
|
133
|
+
if (help) {
|
|
134
|
+
parts.push(colorize(` help: ${help}`, 'dim', noColor));
|
|
135
|
+
parts.push('');
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
return parts.join('\n');
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
/**
|
|
142
|
+
* Fallback when line number is out of range — plain file:line:col + message.
|
|
143
|
+
* @private
|
|
144
|
+
*/
|
|
145
|
+
function formatSimple({ filePath, line, column, message, help, severity, noColor }) {
|
|
146
|
+
const labelColor = severity === 'warn' ? 'yellow' : 'red';
|
|
147
|
+
const label = severity === 'warn' ? 'warn' : 'error';
|
|
148
|
+
const parts = [
|
|
149
|
+
`${colorize(`[${label}]`, labelColor, noColor)} ${colorize(`${filePath}:${line}:${column}`, 'cyan', noColor)} ${message}`,
|
|
150
|
+
];
|
|
151
|
+
if (help) parts.push(colorize(` help: ${help}`, 'dim', noColor));
|
|
152
|
+
return parts.join('\n');
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
/**
|
|
156
|
+
* Locate the line and column of the first occurrence of a YAML key in the
|
|
157
|
+
* frontmatter block of a SKILL.md file.
|
|
158
|
+
*
|
|
159
|
+
* Returns { line: 1-based, column: 1-based } or { line: 1, column: 1 } as a
|
|
160
|
+
* fallback if the key is not found.
|
|
161
|
+
*
|
|
162
|
+
* @param {string} sourceText - Full file text.
|
|
163
|
+
* @param {string} key - YAML key to find (exact match, at the start of a line after optional spaces).
|
|
164
|
+
* @returns {{ line: number, column: number }}
|
|
165
|
+
*/
|
|
166
|
+
function locateYamlKey(sourceText, key) {
|
|
167
|
+
const lines = sourceText.split('\n');
|
|
168
|
+
const pattern = new RegExp(`^(\\s*)${escapeRegex(key)}\\s*:`);
|
|
169
|
+
for (let i = 0; i < lines.length; i++) {
|
|
170
|
+
const m = pattern.exec(lines[i]);
|
|
171
|
+
if (m) {
|
|
172
|
+
return { line: i + 1, column: m[1].length + 1 };
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
return { line: 1, column: 1 };
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
/**
|
|
179
|
+
* Locate the line and column of the first occurrence of an H2 section header
|
|
180
|
+
* in the body of a SKILL.md file.
|
|
181
|
+
*
|
|
182
|
+
* @param {string} sourceText - Full file text.
|
|
183
|
+
* @param {string} heading - Heading text without '## ' prefix (e.g. 'Verification').
|
|
184
|
+
* @returns {{ line: number, column: number }}
|
|
185
|
+
*/
|
|
186
|
+
function locateH2Section(sourceText, heading) {
|
|
187
|
+
const lines = sourceText.split('\n');
|
|
188
|
+
const target = `## ${heading}`;
|
|
189
|
+
for (let i = 0; i < lines.length; i++) {
|
|
190
|
+
if (lines[i].trimEnd() === target) {
|
|
191
|
+
return { line: i + 1, column: 1 };
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
return { line: 1, column: 1 };
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
/**
|
|
198
|
+
* Escape special regex characters in a string.
|
|
199
|
+
* @param {string} s
|
|
200
|
+
* @returns {string}
|
|
201
|
+
*/
|
|
202
|
+
function escapeRegex(s) {
|
|
203
|
+
return s.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
module.exports = { formatCodeFrame, locateYamlKey, locateH2Section };
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* marketplace-install.js — Install a skill from the Skill Graph marketplace.
|
|
4
|
+
*
|
|
5
|
+
* Fetches a skill from a remote registry (GitHub or npm) and writes it into
|
|
6
|
+
* the local skill library. This is a minimal stub — the full implementation
|
|
7
|
+
* will follow in SH-6110.
|
|
8
|
+
*
|
|
9
|
+
* Usage:
|
|
10
|
+
* node scripts/marketplace-install.js <slug>
|
|
11
|
+
* node scripts/marketplace-install.js <slug> --source <registry-url>
|
|
12
|
+
* node scripts/marketplace-install.js --list
|
|
13
|
+
* node scripts/marketplace-install.js --help
|
|
14
|
+
*
|
|
15
|
+
* Flags:
|
|
16
|
+
* --source <url> Override the default registry URL.
|
|
17
|
+
* --list List skills available in the default registry.
|
|
18
|
+
* --dry-run Show what would be installed without writing anything.
|
|
19
|
+
* --force Overwrite if the skill already exists locally.
|
|
20
|
+
* --output <dir> Override the local output directory (default: skills/).
|
|
21
|
+
*/
|
|
22
|
+
|
|
23
|
+
'use strict';
|
|
24
|
+
|
|
25
|
+
const DEFAULT_REGISTRY = 'https://raw.githubusercontent.com/jacob-balslev/skills/main/skills';
|
|
26
|
+
|
|
27
|
+
function printHelp() {
|
|
28
|
+
process.stdout.write(`Usage: skill-graph add <slug> [options]
|
|
29
|
+
|
|
30
|
+
Install a skill from the marketplace into your local skill library.
|
|
31
|
+
|
|
32
|
+
Arguments:
|
|
33
|
+
<slug> Skill slug to install (e.g. "debugging", "code-review")
|
|
34
|
+
|
|
35
|
+
Options:
|
|
36
|
+
--source <url> Registry URL (default: ${DEFAULT_REGISTRY})
|
|
37
|
+
--dry-run Show what would be installed without writing files
|
|
38
|
+
--force Overwrite an existing local skill
|
|
39
|
+
--output <dir> Local directory to install into (default: skills/)
|
|
40
|
+
--list List skills available in the registry
|
|
41
|
+
--help Show this help
|
|
42
|
+
|
|
43
|
+
Examples:
|
|
44
|
+
skill-graph add debugging
|
|
45
|
+
skill-graph add code-review --dry-run
|
|
46
|
+
skill-graph add a11y --force --output ./my-skills
|
|
47
|
+
skill-graph add --list
|
|
48
|
+
`);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
async function listSkills(registryUrl) {
|
|
52
|
+
process.stdout.write(`Listing skills from: ${registryUrl}\n`);
|
|
53
|
+
process.stdout.write(`\nThis feature requires the full SH-6110 implementation.\n`);
|
|
54
|
+
process.stdout.write(`For now, browse available skills at:\n`);
|
|
55
|
+
process.stdout.write(` https://github.com/jacob-balslev/skills/tree/main/skills\n`);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
async function installSkill(slug, opts) {
|
|
59
|
+
if (!slug) {
|
|
60
|
+
process.stderr.write('Error: missing required argument <slug>\n\n');
|
|
61
|
+
printHelp();
|
|
62
|
+
process.exit(1);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
const registryUrl = opts.source || DEFAULT_REGISTRY;
|
|
66
|
+
const skillUrl = `${registryUrl}/${slug}/SKILL.md`;
|
|
67
|
+
|
|
68
|
+
process.stdout.write(`Installing skill: ${slug}\n`);
|
|
69
|
+
process.stdout.write(`Registry: ${registryUrl}\n`);
|
|
70
|
+
process.stdout.write(`Source: ${skillUrl}\n\n`);
|
|
71
|
+
|
|
72
|
+
if (opts['dry-run']) {
|
|
73
|
+
process.stdout.write(`[dry-run] Would fetch: ${skillUrl}\n`);
|
|
74
|
+
process.stdout.write(`[dry-run] Would write: ${opts.output || 'skills'}/${slug}/SKILL.md\n`);
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
// Full implementation follows in SH-6110 (install verification).
|
|
79
|
+
// For now, direct users to the canonical install method.
|
|
80
|
+
process.stderr.write(`Full marketplace install is not yet implemented.\n`);
|
|
81
|
+
process.stderr.write(`\nTo install skills manually:\n`);
|
|
82
|
+
process.stderr.write(` 1. Visit: ${skillUrl}\n`);
|
|
83
|
+
process.stderr.write(` 2. Copy the file to: ${opts.output || 'skills'}/${slug}/SKILL.md\n`);
|
|
84
|
+
process.stderr.write(`\nFull install support is tracked in SH-6110.\n`);
|
|
85
|
+
process.exit(1);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
function parseArgs(argv) {
|
|
89
|
+
const opts = {};
|
|
90
|
+
const positional = [];
|
|
91
|
+
for (let i = 0; i < argv.length; i++) {
|
|
92
|
+
const arg = argv[i];
|
|
93
|
+
if (arg === '--help' || arg === '-h') { opts.help = true; }
|
|
94
|
+
else if (arg === '--dry-run') { opts['dry-run'] = true; }
|
|
95
|
+
else if (arg === '--force') { opts.force = true; }
|
|
96
|
+
else if (arg === '--list') { opts.list = true; }
|
|
97
|
+
else if (arg === '--source' && argv[i + 1]) { opts.source = argv[++i]; }
|
|
98
|
+
else if (arg === '--output' && argv[i + 1]) { opts.output = argv[++i]; }
|
|
99
|
+
else if (!arg.startsWith('--')) { positional.push(arg); }
|
|
100
|
+
}
|
|
101
|
+
opts._positional = positional;
|
|
102
|
+
return opts;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
async function main() {
|
|
106
|
+
const args = parseArgs(process.argv.slice(2));
|
|
107
|
+
|
|
108
|
+
if (args.help) {
|
|
109
|
+
printHelp();
|
|
110
|
+
process.exit(0);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
if (args.list) {
|
|
114
|
+
await listSkills(args.source || DEFAULT_REGISTRY);
|
|
115
|
+
process.exit(0);
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
const slug = args._positional[0];
|
|
119
|
+
await installSkill(slug, args);
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
main().catch(err => {
|
|
123
|
+
process.stderr.write(`Error: ${err.message}\n`);
|
|
124
|
+
process.exit(1);
|
|
125
|
+
});
|