@a16njs/plugin-claude 0.0.1
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/README.md +127 -0
- package/dist/discover.d.ts +6 -0
- package/dist/discover.d.ts.map +1 -0
- package/dist/discover.js +251 -0
- package/dist/discover.js.map +1 -0
- package/dist/emit.d.ts +9 -0
- package/dist/emit.d.ts.map +1 -0
- package/dist/emit.js +292 -0
- package/dist/emit.js.map +1 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +20 -0
- package/dist/index.js.map +1 -0
- package/package.json +48 -0
package/README.md
ADDED
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
# @a16njs/plugin-claude
|
|
2
|
+
|
|
3
|
+
Claude Code plugin for a16n. Discovers and emits Claude configuration.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
This plugin is bundled with the `a16n` CLI. For programmatic use:
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
npm install @a16njs/plugin-claude
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## Supported Types
|
|
14
|
+
|
|
15
|
+
This plugin supports four customization types:
|
|
16
|
+
|
|
17
|
+
| Type | Claude Format | Description |
|
|
18
|
+
|------|---------------|-------------|
|
|
19
|
+
| **GlobalPrompt** | `CLAUDE.md` | Always-active instructions |
|
|
20
|
+
| **FileRule** | `.claude/settings.local.json` + `.a16n/rules/` | Glob-triggered via hooks |
|
|
21
|
+
| **AgentSkill** | `.claude/skills/*/SKILL.md` | Description-triggered skills |
|
|
22
|
+
| **AgentIgnore** | `.claude/settings.json` `permissions.deny` | Files to exclude |
|
|
23
|
+
|
|
24
|
+
## Supported Files
|
|
25
|
+
|
|
26
|
+
### Discovery
|
|
27
|
+
|
|
28
|
+
- `CLAUDE.md` - Root Claude configuration (GlobalPrompt)
|
|
29
|
+
- `*/CLAUDE.md` - Nested Claude configuration files (GlobalPrompt)
|
|
30
|
+
- `.claude/skills/*/SKILL.md` - Skills with description frontmatter (AgentSkill)
|
|
31
|
+
- `.claude/settings.json` - Permissions deny rules (AgentIgnore)
|
|
32
|
+
|
|
33
|
+
> **Note:** Skills with `hooks:` in their frontmatter are skipped (not convertible to Cursor).
|
|
34
|
+
> **Note:** Only `Read()` permission denials are discovered (other types like `Bash()` or `Edit()` are ignored).
|
|
35
|
+
|
|
36
|
+
### Emission
|
|
37
|
+
|
|
38
|
+
- **GlobalPrompt** → `CLAUDE.md` (merged with section headers)
|
|
39
|
+
- **FileRule** → `.a16n/rules/<name>.txt` + `.claude/settings.local.json` with hooks
|
|
40
|
+
- **AgentSkill** → `.claude/skills/<name>/SKILL.md` with description frontmatter
|
|
41
|
+
- **AgentIgnore** → `.claude/settings.json` with `permissions.deny` Read rules
|
|
42
|
+
|
|
43
|
+
## File Formats
|
|
44
|
+
|
|
45
|
+
### CLAUDE.md (GlobalPrompt)
|
|
46
|
+
|
|
47
|
+
```markdown
|
|
48
|
+
# Project Guidelines
|
|
49
|
+
|
|
50
|
+
Your instructions for Claude here.
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
### SKILL.md (AgentSkill)
|
|
54
|
+
|
|
55
|
+
```markdown
|
|
56
|
+
---
|
|
57
|
+
description: Testing best practices
|
|
58
|
+
---
|
|
59
|
+
|
|
60
|
+
Write unit tests first.
|
|
61
|
+
Aim for 80% code coverage.
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
### settings.local.json (FileRule via hooks)
|
|
65
|
+
|
|
66
|
+
FileRules are converted using `@a16njs/glob-hook` for runtime glob matching:
|
|
67
|
+
|
|
68
|
+
```json
|
|
69
|
+
{
|
|
70
|
+
"hooks": {
|
|
71
|
+
"PreToolUse": [{
|
|
72
|
+
"matcher": "Read|Write|Edit",
|
|
73
|
+
"hooks": [{
|
|
74
|
+
"type": "command",
|
|
75
|
+
"command": "npx @a16njs/glob-hook --globs \"**/*.tsx\" --context-file \".a16n/rules/react.txt\""
|
|
76
|
+
}]
|
|
77
|
+
}]
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
> **Note:** FileRule conversion emits an "Approximated" warning because hook-based matching may differ slightly from Cursor's native glob matching.
|
|
83
|
+
|
|
84
|
+
### settings.json (AgentIgnore via permissions.deny)
|
|
85
|
+
|
|
86
|
+
AgentIgnore patterns are converted to `permissions.deny` Read rules:
|
|
87
|
+
|
|
88
|
+
```json
|
|
89
|
+
{
|
|
90
|
+
"permissions": {
|
|
91
|
+
"deny": [
|
|
92
|
+
"Read(./dist/**)",
|
|
93
|
+
"Read(./.env)",
|
|
94
|
+
"Read(./**/*.log)",
|
|
95
|
+
"Read(./secrets/**)"
|
|
96
|
+
]
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
Pattern conversion rules:
|
|
102
|
+
- `dist/` → `Read(./dist/**)`
|
|
103
|
+
- `.env` → `Read(./.env)`
|
|
104
|
+
- `*.log` → `Read(./**/*.log)`
|
|
105
|
+
- `**/*.tmp` → `Read(./**/*.tmp)`
|
|
106
|
+
|
|
107
|
+
> **Note:** AgentIgnore conversion emits an "Approximated" warning because Claude's permission system may behave slightly differently than `.cursorignore`.
|
|
108
|
+
|
|
109
|
+
## Usage
|
|
110
|
+
|
|
111
|
+
```typescript
|
|
112
|
+
import claudePlugin from '@a16njs/plugin-claude';
|
|
113
|
+
import { A16nEngine } from '@a16njs/engine';
|
|
114
|
+
|
|
115
|
+
const engine = new A16nEngine([claudePlugin]);
|
|
116
|
+
|
|
117
|
+
// Discover Claude configuration
|
|
118
|
+
const result = await claudePlugin.discover('./my-project');
|
|
119
|
+
console.log(`Found ${result.items.length} items`);
|
|
120
|
+
|
|
121
|
+
// Emit to Claude format
|
|
122
|
+
await claudePlugin.emit(result.items, './my-project');
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
## License
|
|
126
|
+
|
|
127
|
+
MIT
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"discover.d.ts","sourceRoot":"","sources":["../src/discover.ts"],"names":[],"mappings":"AAEA,OAAO,EAIL,KAAK,eAAe,EAKrB,MAAM,gBAAgB,CAAC;AAyMxB;;GAEG;AACH,wBAAsB,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,eAAe,CAAC,CA8FrE"}
|
package/dist/discover.js
ADDED
|
@@ -0,0 +1,251 @@
|
|
|
1
|
+
import * as fs from 'fs/promises';
|
|
2
|
+
import * as path from 'path';
|
|
3
|
+
import { CustomizationType, WarningCode, createId, } from '@a16njs/models';
|
|
4
|
+
/**
|
|
5
|
+
* Convert a Claude Read() permission rule to a gitignore-style pattern.
|
|
6
|
+
* Returns null for non-Read rules.
|
|
7
|
+
*/
|
|
8
|
+
function convertReadRuleToPattern(rule) {
|
|
9
|
+
const match = rule.match(/^Read\(\.\/(.+)\)$/);
|
|
10
|
+
if (!match)
|
|
11
|
+
return null;
|
|
12
|
+
let pattern = match[1];
|
|
13
|
+
// Read(./dist/**) → dist/
|
|
14
|
+
if (pattern.endsWith('/**')) {
|
|
15
|
+
return pattern.slice(0, -2);
|
|
16
|
+
}
|
|
17
|
+
// Read(./**/*.log) → *.log
|
|
18
|
+
if (pattern.startsWith('**/')) {
|
|
19
|
+
return pattern.slice(3);
|
|
20
|
+
}
|
|
21
|
+
// Read(./.env) → .env
|
|
22
|
+
return pattern;
|
|
23
|
+
}
|
|
24
|
+
function parseSkillFrontmatter(content) {
|
|
25
|
+
const lines = content.split('\n');
|
|
26
|
+
let frontmatterStart = -1;
|
|
27
|
+
let frontmatterEnd = -1;
|
|
28
|
+
for (let i = 0; i < lines.length; i++) {
|
|
29
|
+
const line = lines[i]?.trim();
|
|
30
|
+
if (line === '---') {
|
|
31
|
+
if (frontmatterStart === -1) {
|
|
32
|
+
frontmatterStart = i;
|
|
33
|
+
}
|
|
34
|
+
else {
|
|
35
|
+
frontmatterEnd = i;
|
|
36
|
+
break;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
// No frontmatter found
|
|
41
|
+
if (frontmatterStart === -1 || frontmatterEnd === -1) {
|
|
42
|
+
return {
|
|
43
|
+
frontmatter: { hasHooks: false },
|
|
44
|
+
body: content.trim(),
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
const frontmatter = { hasHooks: false };
|
|
48
|
+
// Parse frontmatter lines
|
|
49
|
+
for (let i = frontmatterStart + 1; i < frontmatterEnd; i++) {
|
|
50
|
+
const line = lines[i];
|
|
51
|
+
if (!line)
|
|
52
|
+
continue;
|
|
53
|
+
// Check for hooks: key (indicates skill-scoped hooks)
|
|
54
|
+
if (line.match(/^hooks:\s*$/)) {
|
|
55
|
+
frontmatter.hasHooks = true;
|
|
56
|
+
continue;
|
|
57
|
+
}
|
|
58
|
+
// Parse description: "..."
|
|
59
|
+
const descriptionMatch = line.match(/^description:\s*["']?(.+?)["']?\s*$/);
|
|
60
|
+
if (descriptionMatch) {
|
|
61
|
+
frontmatter.description = descriptionMatch[1];
|
|
62
|
+
continue;
|
|
63
|
+
}
|
|
64
|
+
// Parse name: "..."
|
|
65
|
+
const nameMatch = line.match(/^name:\s*["']?(.+?)["']?\s*$/);
|
|
66
|
+
if (nameMatch) {
|
|
67
|
+
frontmatter.name = nameMatch[1];
|
|
68
|
+
continue;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
// Extract body (everything after second ---)
|
|
72
|
+
const bodyLines = lines.slice(frontmatterEnd + 1);
|
|
73
|
+
const body = bodyLines.join('\n').trim();
|
|
74
|
+
return { frontmatter, body };
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Find all SKILL.md files in .claude/skills/ subdirectories.
|
|
78
|
+
* Returns paths like ".claude/skills/testing/SKILL.md"
|
|
79
|
+
*/
|
|
80
|
+
async function findSkillFiles(root) {
|
|
81
|
+
const results = [];
|
|
82
|
+
const skillsDir = path.join(root, '.claude', 'skills');
|
|
83
|
+
try {
|
|
84
|
+
const entries = await fs.readdir(skillsDir, { withFileTypes: true });
|
|
85
|
+
for (const entry of entries) {
|
|
86
|
+
if (entry.isDirectory()) {
|
|
87
|
+
const skillFile = path.join(skillsDir, entry.name, 'SKILL.md');
|
|
88
|
+
try {
|
|
89
|
+
await fs.access(skillFile);
|
|
90
|
+
results.push(`.claude/skills/${entry.name}/SKILL.md`);
|
|
91
|
+
}
|
|
92
|
+
catch {
|
|
93
|
+
// No SKILL.md in this directory
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
catch {
|
|
99
|
+
// .claude/skills doesn't exist
|
|
100
|
+
}
|
|
101
|
+
return results;
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* Recursively find all CLAUDE.md files in a directory tree.
|
|
105
|
+
*/
|
|
106
|
+
async function findClaudeFiles(root, currentDir = '') {
|
|
107
|
+
const results = [];
|
|
108
|
+
const fullPath = currentDir ? path.join(root, currentDir) : root;
|
|
109
|
+
try {
|
|
110
|
+
const entries = await fs.readdir(fullPath, { withFileTypes: true });
|
|
111
|
+
for (const entry of entries) {
|
|
112
|
+
// Skip node_modules and hidden directories
|
|
113
|
+
if (entry.name.startsWith('.') || entry.name === 'node_modules') {
|
|
114
|
+
continue;
|
|
115
|
+
}
|
|
116
|
+
const relativePath = currentDir
|
|
117
|
+
? path.join(currentDir, entry.name)
|
|
118
|
+
: entry.name;
|
|
119
|
+
if (entry.isFile() && entry.name === 'CLAUDE.md') {
|
|
120
|
+
results.push(relativePath);
|
|
121
|
+
}
|
|
122
|
+
else if (entry.isDirectory()) {
|
|
123
|
+
const nested = await findClaudeFiles(root, relativePath);
|
|
124
|
+
results.push(...nested);
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
catch {
|
|
129
|
+
// Directory doesn't exist or can't be read
|
|
130
|
+
}
|
|
131
|
+
return results;
|
|
132
|
+
}
|
|
133
|
+
/**
|
|
134
|
+
* Discover AgentIgnore from .claude/settings.json permissions.deny Read rules.
|
|
135
|
+
* Returns null if settings.json doesn't exist or has no Read rules.
|
|
136
|
+
*/
|
|
137
|
+
async function discoverAgentIgnore(root) {
|
|
138
|
+
const settingsPath = path.join(root, '.claude', 'settings.json');
|
|
139
|
+
try {
|
|
140
|
+
const content = await fs.readFile(settingsPath, 'utf-8');
|
|
141
|
+
const settings = JSON.parse(content);
|
|
142
|
+
const permissions = settings.permissions;
|
|
143
|
+
const rawDeny = Array.isArray(permissions?.deny) ? permissions.deny : [];
|
|
144
|
+
// Filter to only string entries to avoid startsWith throwing on non-strings
|
|
145
|
+
const denyRules = rawDeny.filter((r) => typeof r === 'string');
|
|
146
|
+
const readRules = denyRules.filter(r => r.startsWith('Read('));
|
|
147
|
+
const patterns = readRules
|
|
148
|
+
.map(convertReadRuleToPattern)
|
|
149
|
+
.filter((p) => p !== null);
|
|
150
|
+
if (patterns.length === 0)
|
|
151
|
+
return null;
|
|
152
|
+
return {
|
|
153
|
+
id: createId(CustomizationType.AgentIgnore, '.claude/settings.json'),
|
|
154
|
+
type: CustomizationType.AgentIgnore,
|
|
155
|
+
sourcePath: '.claude/settings.json',
|
|
156
|
+
content: JSON.stringify({ permissions: { deny: readRules } }, null, 2),
|
|
157
|
+
patterns,
|
|
158
|
+
metadata: { originalRules: readRules },
|
|
159
|
+
};
|
|
160
|
+
}
|
|
161
|
+
catch {
|
|
162
|
+
return null;
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
/**
|
|
166
|
+
* Discover all CLAUDE.md files and skills in a project directory.
|
|
167
|
+
*/
|
|
168
|
+
export async function discover(root) {
|
|
169
|
+
const items = [];
|
|
170
|
+
const warnings = [];
|
|
171
|
+
// Find all CLAUDE.md files (GlobalPrompt)
|
|
172
|
+
const claudeFiles = await findClaudeFiles(root);
|
|
173
|
+
for (const file of claudeFiles) {
|
|
174
|
+
const fullPath = path.join(root, file);
|
|
175
|
+
// Normalize path separators for cross-platform consistency
|
|
176
|
+
const normalizedPath = file.split(path.sep).join('/');
|
|
177
|
+
try {
|
|
178
|
+
const content = await fs.readFile(fullPath, 'utf-8');
|
|
179
|
+
// Calculate nesting depth
|
|
180
|
+
const depth = file.split(path.sep).length - 1;
|
|
181
|
+
const isNested = depth > 0;
|
|
182
|
+
items.push({
|
|
183
|
+
id: createId(CustomizationType.GlobalPrompt, normalizedPath),
|
|
184
|
+
type: CustomizationType.GlobalPrompt,
|
|
185
|
+
sourcePath: normalizedPath,
|
|
186
|
+
content,
|
|
187
|
+
metadata: {
|
|
188
|
+
nested: isNested,
|
|
189
|
+
depth,
|
|
190
|
+
},
|
|
191
|
+
});
|
|
192
|
+
}
|
|
193
|
+
catch (error) {
|
|
194
|
+
// File couldn't be read - add warning and continue
|
|
195
|
+
warnings.push({
|
|
196
|
+
code: WarningCode.Skipped,
|
|
197
|
+
message: `Could not read ${normalizedPath}: ${error.message}`,
|
|
198
|
+
sources: [normalizedPath],
|
|
199
|
+
});
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
// Find all .claude/skills/*/SKILL.md files (AgentSkill)
|
|
203
|
+
const skillFiles = await findSkillFiles(root);
|
|
204
|
+
for (const skillPath of skillFiles) {
|
|
205
|
+
const fullPath = path.join(root, skillPath);
|
|
206
|
+
try {
|
|
207
|
+
const content = await fs.readFile(fullPath, 'utf-8');
|
|
208
|
+
const { frontmatter, body } = parseSkillFrontmatter(content);
|
|
209
|
+
// Extract skill name from path (e.g., "testing" from ".claude/skills/testing/SKILL.md")
|
|
210
|
+
const skillName = skillPath.split('/')[2] || 'unknown';
|
|
211
|
+
// Skip skills with hooks - they're not convertible to Cursor
|
|
212
|
+
if (frontmatter.hasHooks) {
|
|
213
|
+
const displayName = frontmatter.name || skillName;
|
|
214
|
+
warnings.push({
|
|
215
|
+
code: WarningCode.Skipped,
|
|
216
|
+
message: `Skipped skill '${displayName}': Contains hooks (not convertible to Cursor)`,
|
|
217
|
+
sources: [skillPath],
|
|
218
|
+
});
|
|
219
|
+
continue;
|
|
220
|
+
}
|
|
221
|
+
// Only include skills that have a description
|
|
222
|
+
if (frontmatter.description) {
|
|
223
|
+
const skill = {
|
|
224
|
+
id: createId(CustomizationType.AgentSkill, skillPath),
|
|
225
|
+
type: CustomizationType.AgentSkill,
|
|
226
|
+
sourcePath: skillPath,
|
|
227
|
+
content: body,
|
|
228
|
+
description: frontmatter.description,
|
|
229
|
+
metadata: {
|
|
230
|
+
name: frontmatter.name || skillName,
|
|
231
|
+
},
|
|
232
|
+
};
|
|
233
|
+
items.push(skill);
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
catch (error) {
|
|
237
|
+
warnings.push({
|
|
238
|
+
code: WarningCode.Skipped,
|
|
239
|
+
message: `Could not read ${skillPath}: ${error.message}`,
|
|
240
|
+
sources: [skillPath],
|
|
241
|
+
});
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
// Discover AgentIgnore from .claude/settings.json (Phase 3)
|
|
245
|
+
const agentIgnore = await discoverAgentIgnore(root);
|
|
246
|
+
if (agentIgnore) {
|
|
247
|
+
items.push(agentIgnore);
|
|
248
|
+
}
|
|
249
|
+
return { items, warnings };
|
|
250
|
+
}
|
|
251
|
+
//# sourceMappingURL=discover.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"discover.js","sourceRoot":"","sources":["../src/discover.ts"],"names":[],"mappings":"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"}
|
package/dist/emit.d.ts
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { type AgentCustomization, type EmitResult } from '@a16njs/models';
|
|
2
|
+
/**
|
|
3
|
+
* Emit agent customizations to Claude format.
|
|
4
|
+
* - GlobalPrompts → CLAUDE.md
|
|
5
|
+
* - FileRules → .a16n/rules/ + .claude/settings.local.json
|
|
6
|
+
* - AgentSkills → .claude/skills/ subdirectories
|
|
7
|
+
*/
|
|
8
|
+
export declare function emit(models: AgentCustomization[], root: string): Promise<EmitResult>;
|
|
9
|
+
//# sourceMappingURL=emit.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"emit.d.ts","sourceRoot":"","sources":["../src/emit.ts"],"names":[],"mappings":"AAEA,OAAO,EACL,KAAK,kBAAkB,EACvB,KAAK,UAAU,EAWhB,MAAM,gBAAgB,CAAC;AAgGxB;;;;;GAKG;AACH,wBAAsB,IAAI,CACxB,MAAM,EAAE,kBAAkB,EAAE,EAC5B,IAAI,EAAE,MAAM,GACX,OAAO,CAAC,UAAU,CAAC,CAsOrB"}
|
package/dist/emit.js
ADDED
|
@@ -0,0 +1,292 @@
|
|
|
1
|
+
import * as fs from 'fs/promises';
|
|
2
|
+
import * as path from 'path';
|
|
3
|
+
import { CustomizationType, WarningCode, isGlobalPrompt, isFileRule, isAgentSkill, isAgentIgnore, } from '@a16njs/models';
|
|
4
|
+
/**
|
|
5
|
+
* Convert a gitignore-style pattern to a Claude Read() permission rule.
|
|
6
|
+
* Returns null for patterns that cannot be converted (e.g., negation patterns).
|
|
7
|
+
*/
|
|
8
|
+
function convertPatternToReadRule(pattern) {
|
|
9
|
+
// Negation patterns cannot be converted to deny rules
|
|
10
|
+
// (they would need to REMOVE entries from deny, not add them)
|
|
11
|
+
if (pattern.startsWith('!')) {
|
|
12
|
+
return null;
|
|
13
|
+
}
|
|
14
|
+
// Directory pattern: dist/ → Read(./dist/**)
|
|
15
|
+
if (pattern.endsWith('/')) {
|
|
16
|
+
return `Read(./${pattern}**)`;
|
|
17
|
+
}
|
|
18
|
+
// Glob pattern: *.log → Read(./**/*.log)
|
|
19
|
+
if (pattern.startsWith('*') && !pattern.startsWith('**')) {
|
|
20
|
+
return `Read(./**/${pattern})`;
|
|
21
|
+
}
|
|
22
|
+
// Already has **: **/*.tmp → Read(./**/*.tmp)
|
|
23
|
+
if (pattern.startsWith('**')) {
|
|
24
|
+
return `Read(./${pattern})`;
|
|
25
|
+
}
|
|
26
|
+
// Simple file: .env → Read(./.env)
|
|
27
|
+
return `Read(./${pattern})`;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Sanitize a filename from a source path.
|
|
31
|
+
* Extracts base name and makes it filesystem-safe.
|
|
32
|
+
*/
|
|
33
|
+
function sanitizeFilename(sourcePath) {
|
|
34
|
+
const basename = path.basename(sourcePath);
|
|
35
|
+
const nameWithoutExt = basename.replace(/\.[^.]+$/, '');
|
|
36
|
+
const sanitized = nameWithoutExt
|
|
37
|
+
.toLowerCase()
|
|
38
|
+
.replace(/[^a-z0-9]+/g, '-')
|
|
39
|
+
.replace(/^-+|-+$/g, '');
|
|
40
|
+
return sanitized || 'rule';
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Escape a string for safe use in double-quoted shell arguments.
|
|
44
|
+
* Escapes: backslash, double quote, dollar sign, backtick.
|
|
45
|
+
*/
|
|
46
|
+
function escapeShellArg(str) {
|
|
47
|
+
return str.replace(/[\\"`$]/g, '\\$&');
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Build hook configuration for a FileRule.
|
|
51
|
+
*/
|
|
52
|
+
function buildHookConfig(fileRule, rulePath) {
|
|
53
|
+
// Escape globs and rulePath to prevent command injection
|
|
54
|
+
const escapedGlobs = fileRule.globs.map(g => escapeShellArg(g));
|
|
55
|
+
const globsArg = escapedGlobs.join(',');
|
|
56
|
+
const escapedRulePath = escapeShellArg(rulePath);
|
|
57
|
+
return {
|
|
58
|
+
matcher: 'Read|Write|Edit',
|
|
59
|
+
hooks: [{
|
|
60
|
+
type: 'command',
|
|
61
|
+
command: `npx @a16njs/glob-hook --globs "${globsArg}" --context-file "${escapedRulePath}"`,
|
|
62
|
+
}],
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Format a skill file with YAML frontmatter.
|
|
67
|
+
* Name and description are quoted to handle YAML special characters.
|
|
68
|
+
*/
|
|
69
|
+
function formatSkill(skill) {
|
|
70
|
+
// Quote values to handle YAML special characters (: # { } etc.)
|
|
71
|
+
const safeDescription = JSON.stringify(skill.description);
|
|
72
|
+
const skillName = skill.metadata?.name;
|
|
73
|
+
// Include name in frontmatter if available
|
|
74
|
+
if (skillName) {
|
|
75
|
+
const safeName = JSON.stringify(skillName);
|
|
76
|
+
return `---
|
|
77
|
+
name: ${safeName}
|
|
78
|
+
description: ${safeDescription}
|
|
79
|
+
---
|
|
80
|
+
|
|
81
|
+
${skill.content}
|
|
82
|
+
`;
|
|
83
|
+
}
|
|
84
|
+
return `---
|
|
85
|
+
description: ${safeDescription}
|
|
86
|
+
---
|
|
87
|
+
|
|
88
|
+
${skill.content}
|
|
89
|
+
`;
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Emit agent customizations to Claude format.
|
|
93
|
+
* - GlobalPrompts → CLAUDE.md
|
|
94
|
+
* - FileRules → .a16n/rules/ + .claude/settings.local.json
|
|
95
|
+
* - AgentSkills → .claude/skills/ subdirectories
|
|
96
|
+
*/
|
|
97
|
+
export async function emit(models, root) {
|
|
98
|
+
const written = [];
|
|
99
|
+
const warnings = [];
|
|
100
|
+
const unsupported = [];
|
|
101
|
+
// Separate by type
|
|
102
|
+
const globalPrompts = models.filter(isGlobalPrompt);
|
|
103
|
+
const fileRules = models.filter(isFileRule);
|
|
104
|
+
const agentSkills = models.filter(isAgentSkill);
|
|
105
|
+
const agentIgnores = models.filter(isAgentIgnore);
|
|
106
|
+
// Track unsupported types (future types)
|
|
107
|
+
for (const model of models) {
|
|
108
|
+
if (!isGlobalPrompt(model) && !isFileRule(model) && !isAgentSkill(model) && !isAgentIgnore(model)) {
|
|
109
|
+
unsupported.push(model);
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
// === Emit GlobalPrompts as CLAUDE.md ===
|
|
113
|
+
if (globalPrompts.length > 0) {
|
|
114
|
+
const sections = globalPrompts.map((gp) => {
|
|
115
|
+
const header = `## From: ${gp.sourcePath}`;
|
|
116
|
+
return `${header}\n\n${gp.content}`;
|
|
117
|
+
});
|
|
118
|
+
const content = sections.join('\n\n---\n\n');
|
|
119
|
+
const claudePath = path.join(root, 'CLAUDE.md');
|
|
120
|
+
await fs.writeFile(claudePath, content, 'utf-8');
|
|
121
|
+
written.push({
|
|
122
|
+
path: claudePath,
|
|
123
|
+
type: CustomizationType.GlobalPrompt,
|
|
124
|
+
itemCount: globalPrompts.length,
|
|
125
|
+
});
|
|
126
|
+
if (globalPrompts.length > 1) {
|
|
127
|
+
warnings.push({
|
|
128
|
+
code: WarningCode.Merged,
|
|
129
|
+
message: `Merged ${globalPrompts.length} items into single CLAUDE.md`,
|
|
130
|
+
sources: globalPrompts.map((gp) => gp.sourcePath),
|
|
131
|
+
});
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
// === Emit FileRules as .a16n/rules/*.txt + .claude/settings.local.json ===
|
|
135
|
+
if (fileRules.length > 0) {
|
|
136
|
+
// Create .a16n/rules directory
|
|
137
|
+
const rulesDir = path.join(root, '.a16n', 'rules');
|
|
138
|
+
await fs.mkdir(rulesDir, { recursive: true });
|
|
139
|
+
// Create .claude directory for settings
|
|
140
|
+
const claudeDir = path.join(root, '.claude');
|
|
141
|
+
await fs.mkdir(claudeDir, { recursive: true });
|
|
142
|
+
const hooks = [];
|
|
143
|
+
const usedFilenames = new Set();
|
|
144
|
+
for (const rule of fileRules) {
|
|
145
|
+
// Get unique filename to avoid collisions
|
|
146
|
+
let baseName = sanitizeFilename(rule.sourcePath);
|
|
147
|
+
let filename = baseName + '.txt';
|
|
148
|
+
let counter = 1;
|
|
149
|
+
while (usedFilenames.has(filename)) {
|
|
150
|
+
filename = `${baseName}-${counter}.txt`;
|
|
151
|
+
counter++;
|
|
152
|
+
}
|
|
153
|
+
usedFilenames.add(filename);
|
|
154
|
+
const rulePath = `.a16n/rules/${filename}`;
|
|
155
|
+
const fullPath = path.join(root, rulePath);
|
|
156
|
+
// Write rule content
|
|
157
|
+
await fs.writeFile(fullPath, rule.content, 'utf-8');
|
|
158
|
+
written.push({
|
|
159
|
+
path: fullPath,
|
|
160
|
+
type: CustomizationType.FileRule,
|
|
161
|
+
itemCount: 1,
|
|
162
|
+
});
|
|
163
|
+
// Build hook for this rule
|
|
164
|
+
hooks.push(buildHookConfig(rule, rulePath));
|
|
165
|
+
}
|
|
166
|
+
// Write settings.local.json, merging with existing content if present
|
|
167
|
+
const settingsPath = path.join(claudeDir, 'settings.local.json');
|
|
168
|
+
let settings = { hooks: { PreToolUse: hooks } };
|
|
169
|
+
try {
|
|
170
|
+
const existingContent = await fs.readFile(settingsPath, 'utf-8');
|
|
171
|
+
const existing = JSON.parse(existingContent);
|
|
172
|
+
const existingHooks = existing.hooks;
|
|
173
|
+
const existingPreToolUse = Array.isArray(existingHooks?.PreToolUse)
|
|
174
|
+
? existingHooks.PreToolUse
|
|
175
|
+
: [];
|
|
176
|
+
// Merge: preserve existing settings, append new PreToolUse hooks
|
|
177
|
+
settings = {
|
|
178
|
+
...existing,
|
|
179
|
+
hooks: {
|
|
180
|
+
...existingHooks,
|
|
181
|
+
PreToolUse: [...existingPreToolUse, ...hooks],
|
|
182
|
+
},
|
|
183
|
+
};
|
|
184
|
+
}
|
|
185
|
+
catch (err) {
|
|
186
|
+
// File doesn't exist or isn't valid JSON - use fresh settings
|
|
187
|
+
if (err.code !== 'ENOENT') {
|
|
188
|
+
// Only warn if it's not a "file not found" error
|
|
189
|
+
warnings.push({
|
|
190
|
+
code: WarningCode.Skipped,
|
|
191
|
+
message: `Could not parse existing settings.local.json, overwriting: ${err.message}`,
|
|
192
|
+
sources: [settingsPath],
|
|
193
|
+
});
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
await fs.writeFile(settingsPath, JSON.stringify(settings, null, 2), 'utf-8');
|
|
197
|
+
written.push({
|
|
198
|
+
path: settingsPath,
|
|
199
|
+
type: CustomizationType.FileRule,
|
|
200
|
+
itemCount: fileRules.length,
|
|
201
|
+
});
|
|
202
|
+
// Emit approximation warning
|
|
203
|
+
warnings.push({
|
|
204
|
+
code: WarningCode.Approximated,
|
|
205
|
+
message: `FileRule approximated via @a16njs/glob-hook (behavior may differ slightly)`,
|
|
206
|
+
sources: fileRules.map((r) => r.sourcePath),
|
|
207
|
+
});
|
|
208
|
+
}
|
|
209
|
+
// === Emit AgentSkills as .claude/skills/*/SKILL.md ===
|
|
210
|
+
if (agentSkills.length > 0) {
|
|
211
|
+
const usedSkillNames = new Set();
|
|
212
|
+
for (const skill of agentSkills) {
|
|
213
|
+
// Get unique skill name to avoid directory collisions
|
|
214
|
+
let baseName = sanitizeFilename(skill.sourcePath);
|
|
215
|
+
let skillName = baseName;
|
|
216
|
+
let counter = 1;
|
|
217
|
+
while (usedSkillNames.has(skillName)) {
|
|
218
|
+
skillName = `${baseName}-${counter}`;
|
|
219
|
+
counter++;
|
|
220
|
+
}
|
|
221
|
+
usedSkillNames.add(skillName);
|
|
222
|
+
const skillDir = path.join(root, '.claude', 'skills', skillName);
|
|
223
|
+
await fs.mkdir(skillDir, { recursive: true });
|
|
224
|
+
const skillPath = path.join(skillDir, 'SKILL.md');
|
|
225
|
+
const content = formatSkill(skill);
|
|
226
|
+
await fs.writeFile(skillPath, content, 'utf-8');
|
|
227
|
+
written.push({
|
|
228
|
+
path: skillPath,
|
|
229
|
+
type: CustomizationType.AgentSkill,
|
|
230
|
+
itemCount: 1,
|
|
231
|
+
});
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
// === Emit AgentIgnores as .claude/settings.json permissions.deny ===
|
|
235
|
+
if (agentIgnores.length > 0) {
|
|
236
|
+
const allPatterns = agentIgnores.flatMap(ai => ai.patterns);
|
|
237
|
+
const negationPatterns = allPatterns.filter(p => p.startsWith('!'));
|
|
238
|
+
const convertiblePatterns = allPatterns.filter(p => !p.startsWith('!'));
|
|
239
|
+
const denyRules = convertiblePatterns
|
|
240
|
+
.map(convertPatternToReadRule)
|
|
241
|
+
.filter((rule) => rule !== null);
|
|
242
|
+
// Warn about skipped negation patterns
|
|
243
|
+
if (negationPatterns.length > 0) {
|
|
244
|
+
warnings.push({
|
|
245
|
+
code: WarningCode.Skipped,
|
|
246
|
+
message: `Negation patterns cannot be converted to permissions.deny (skipped ${negationPatterns.length} pattern${negationPatterns.length > 1 ? 's' : ''}: ${negationPatterns.join(', ')})`,
|
|
247
|
+
sources: agentIgnores.map(ai => ai.sourcePath),
|
|
248
|
+
});
|
|
249
|
+
}
|
|
250
|
+
const claudeDir = path.join(root, '.claude');
|
|
251
|
+
await fs.mkdir(claudeDir, { recursive: true });
|
|
252
|
+
const settingsPath = path.join(claudeDir, 'settings.json');
|
|
253
|
+
let settings = {};
|
|
254
|
+
try {
|
|
255
|
+
const existing = await fs.readFile(settingsPath, 'utf-8');
|
|
256
|
+
settings = JSON.parse(existing);
|
|
257
|
+
}
|
|
258
|
+
catch (err) {
|
|
259
|
+
if (err.code !== 'ENOENT') {
|
|
260
|
+
// File exists but is malformed - warn and proceed with fresh settings
|
|
261
|
+
warnings.push({
|
|
262
|
+
code: WarningCode.Skipped,
|
|
263
|
+
message: `Could not parse existing settings.json, overwriting: ${err.message}`,
|
|
264
|
+
sources: [settingsPath],
|
|
265
|
+
});
|
|
266
|
+
}
|
|
267
|
+
// File doesn't exist or is malformed - use empty settings
|
|
268
|
+
}
|
|
269
|
+
// Merge deny rules (deduplicate)
|
|
270
|
+
const existingPermissions = settings.permissions;
|
|
271
|
+
const existingDeny = Array.isArray(existingPermissions?.deny)
|
|
272
|
+
? existingPermissions.deny
|
|
273
|
+
: [];
|
|
274
|
+
settings.permissions = {
|
|
275
|
+
...existingPermissions,
|
|
276
|
+
deny: [...new Set([...existingDeny, ...denyRules])],
|
|
277
|
+
};
|
|
278
|
+
await fs.writeFile(settingsPath, JSON.stringify(settings, null, 2), 'utf-8');
|
|
279
|
+
written.push({
|
|
280
|
+
path: settingsPath,
|
|
281
|
+
type: CustomizationType.AgentIgnore,
|
|
282
|
+
itemCount: agentIgnores.length,
|
|
283
|
+
});
|
|
284
|
+
warnings.push({
|
|
285
|
+
code: WarningCode.Approximated,
|
|
286
|
+
message: `AgentIgnore approximated as permissions.deny (behavior may differ slightly)`,
|
|
287
|
+
sources: agentIgnores.map(ai => ai.sourcePath),
|
|
288
|
+
});
|
|
289
|
+
}
|
|
290
|
+
return { written, warnings, unsupported };
|
|
291
|
+
}
|
|
292
|
+
//# sourceMappingURL=emit.js.map
|
package/dist/emit.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"emit.js","sourceRoot":"","sources":["../src/emit.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,UAAU,EAAqB,MAAM,gBAAgB,CAAC;AAIpE;;;GAGG;AACH,QAAA,MAAM,YAAY,EAAE,UAWnB,CAAC;AAEF,eAAe,YAAY,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { CustomizationType } from '@a16njs/models';
|
|
2
|
+
import { discover } from './discover.js';
|
|
3
|
+
import { emit } from './emit.js';
|
|
4
|
+
/**
|
|
5
|
+
* Claude Code plugin for a16n.
|
|
6
|
+
* Supports discovery and emission of Claude configuration.
|
|
7
|
+
*/
|
|
8
|
+
const claudePlugin = {
|
|
9
|
+
id: 'claude',
|
|
10
|
+
name: 'Claude Code',
|
|
11
|
+
supports: [
|
|
12
|
+
CustomizationType.GlobalPrompt,
|
|
13
|
+
CustomizationType.FileRule,
|
|
14
|
+
CustomizationType.AgentSkill,
|
|
15
|
+
],
|
|
16
|
+
discover,
|
|
17
|
+
emit,
|
|
18
|
+
};
|
|
19
|
+
export default claudePlugin;
|
|
20
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAmB,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AACpE,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACzC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAEjC;;;GAGG;AACH,MAAM,YAAY,GAAe;IAC/B,EAAE,EAAE,QAAQ;IACZ,IAAI,EAAE,aAAa;IACnB,QAAQ,EAAE;QACR,iBAAiB,CAAC,YAAY;QAC9B,iBAAiB,CAAC,QAAQ;QAC1B,iBAAiB,CAAC,UAAU;KAC7B;IAED,QAAQ;IACR,IAAI;CACL,CAAC;AAEF,eAAe,YAAY,CAAC"}
|
package/package.json
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@a16njs/plugin-claude",
|
|
3
|
+
"version": "0.0.1",
|
|
4
|
+
"description": "Claude Code plugin for a16n",
|
|
5
|
+
"license": "AGPL-3.0",
|
|
6
|
+
"author": "Texarkanine",
|
|
7
|
+
"repository": {
|
|
8
|
+
"type": "git",
|
|
9
|
+
"url": "git+https://github.com/Texarkanine/a16n.git",
|
|
10
|
+
"directory": "packages/plugin-claude"
|
|
11
|
+
},
|
|
12
|
+
"homepage": "https://github.com/Texarkanine/a16n#readme",
|
|
13
|
+
"bugs": {
|
|
14
|
+
"url": "https://github.com/Texarkanine/a16n/issues"
|
|
15
|
+
},
|
|
16
|
+
"keywords": [
|
|
17
|
+
"a16n",
|
|
18
|
+
"plugin",
|
|
19
|
+
"claude",
|
|
20
|
+
"anthropic",
|
|
21
|
+
"claude-code"
|
|
22
|
+
],
|
|
23
|
+
"type": "module",
|
|
24
|
+
"main": "./dist/index.js",
|
|
25
|
+
"types": "./dist/index.d.ts",
|
|
26
|
+
"exports": {
|
|
27
|
+
".": {
|
|
28
|
+
"types": "./dist/index.d.ts",
|
|
29
|
+
"import": "./dist/index.js"
|
|
30
|
+
}
|
|
31
|
+
},
|
|
32
|
+
"files": ["dist"],
|
|
33
|
+
"scripts": {
|
|
34
|
+
"build": "tsc",
|
|
35
|
+
"clean": "rimraf dist *.tsbuildinfo",
|
|
36
|
+
"typecheck": "tsc --noEmit",
|
|
37
|
+
"test": "vitest run",
|
|
38
|
+
"test:watch": "vitest"
|
|
39
|
+
},
|
|
40
|
+
"dependencies": {
|
|
41
|
+
"@a16njs/models": "workspace:*"
|
|
42
|
+
},
|
|
43
|
+
"devDependencies": {
|
|
44
|
+
"@types/node": "^20.0.0",
|
|
45
|
+
"typescript": "^5.4.0",
|
|
46
|
+
"vitest": "^2.0.0"
|
|
47
|
+
}
|
|
48
|
+
}
|