-
Notifications
You must be signed in to change notification settings - Fork 7.8k
Expand file tree
/
Copy path__init__.py
More file actions
120 lines (98 loc) · 4.18 KB
/
__init__.py
File metadata and controls
120 lines (98 loc) · 4.18 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
"""Claude Code integration."""
from __future__ import annotations
from pathlib import Path
from typing import Any
import yaml
from .skill_postprocess import (
ARGUMENT_HINTS,
apply_claude_skill_postprocess,
inject_argument_hint,
inject_frontmatter_flag,
inject_hook_command_note,
set_frontmatter_key,
)
from ..base import SkillsIntegration
from ..manifest import IntegrationManifest
class ClaudeIntegration(SkillsIntegration):
"""Integration for Claude Code skills."""
key = "claude"
config = {
"name": "Claude Code",
"folder": ".claude/",
"commands_subdir": "skills",
"install_url": "https://docs.anthropic.com/en/docs/claude-code/setup",
"requires_cli": True,
}
registrar_config = {
"dir": ".claude/skills",
"format": "markdown",
"args": "$ARGUMENTS",
"extension": "/SKILL.md",
}
context_file = "CLAUDE.md"
@staticmethod
def inject_argument_hint(content: str, hint: str) -> str:
"""Delegate to shared Claude skill transform implementation."""
return inject_argument_hint(content, hint)
@staticmethod
def _inject_frontmatter_flag(content: str, key: str, value: str = "true") -> str:
"""Delegate to shared Claude skill transform implementation."""
return inject_frontmatter_flag(content, key, value)
@staticmethod
def _inject_hook_command_note(content: str) -> str:
"""Delegate to shared Claude skill transform implementation."""
return inject_hook_command_note(content)
def _render_skill(self, template_name: str, frontmatter: dict[str, Any], body: str) -> str:
"""Render a processed command template as a Claude skill."""
skill_name = f"speckit-{template_name.replace('.', '-')}"
description = frontmatter.get(
"description",
f"Spec-kit workflow command: {template_name}",
)
skill_frontmatter = self._build_skill_fm(
skill_name, description, f"templates/commands/{template_name}.md"
)
frontmatter_text = yaml.safe_dump(skill_frontmatter, sort_keys=False).strip()
return f"---\n{frontmatter_text}\n---\n\n{body.strip()}\n"
def _build_skill_fm(self, name: str, description: str, source: str) -> dict:
from specify_cli.agents import CommandRegistrar
return CommandRegistrar.build_skill_frontmatter(
self.key, name, description, source
)
def post_process_skill_content(self, content: str) -> str:
"""Inject Claude-specific frontmatter flags and hook notes (no argument-hint).
Used by preset/extension skill generators; matches flags applied during
``setup()`` except for fenced question rendering and argument-hint lines.
"""
updated = inject_frontmatter_flag(content, "user-invocable")
updated = set_frontmatter_key(updated, "disable-model-invocation", "false")
updated = inject_hook_command_note(updated)
return updated
@classmethod
def render_skill_postprocess(cls, content: str, skill_path: Path) -> str:
"""Run Claude-specific skill post-processing pipeline."""
return apply_claude_skill_postprocess(content, skill_path)
def setup(
self,
project_root: Path,
manifest: IntegrationManifest,
parsed_options: dict[str, Any] | None = None,
**opts: Any,
) -> list[Path]:
"""Install Claude skills, then run the skill post-process extension chain."""
created = super().setup(project_root, manifest, parsed_options, **opts)
skills_dir = self.skills_dest(project_root).resolve()
for path in created:
try:
path.resolve().relative_to(skills_dir)
except ValueError:
continue
if path.name != "SKILL.md":
continue
content_bytes = path.read_bytes()
content = content_bytes.decode("utf-8")
updated = self.render_skill_postprocess(content, path)
if updated != content:
path.write_bytes(updated.encode("utf-8"))
self.record_file_in_manifest(path, project_root, manifest)
return created