@plaited/development-skills 0.5.0 → 0.6.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/{.claude → .plaited}/rules/accuracy.md +3 -10
- package/{.claude → .plaited}/rules/code-review.md +3 -10
- package/.plaited/rules/documentation.md +41 -0
- package/.plaited/rules/git-workflow.md +31 -0
- package/{.claude → .plaited}/rules/github.md +4 -4
- package/{.claude → .plaited}/rules/module-organization.md +0 -7
- package/{.claude → .plaited}/rules/testing.md +0 -5
- package/package.json +2 -2
- package/src/lsp-analyze.ts +1 -1
- package/src/lsp-find.ts +1 -1
- package/src/lsp-hover.ts +1 -1
- package/src/lsp-references.ts +1 -1
- package/src/lsp-symbols.ts +1 -1
- package/src/scaffold-rules.ts +146 -205
- package/src/tests/scaffold-rules.spec.ts +239 -110
- package/.claude/commands/lsp-analyze.md +0 -66
- package/.claude/commands/lsp-find.md +0 -74
- package/.claude/commands/lsp-hover.md +0 -57
- package/.claude/commands/lsp-refs.md +0 -64
- package/.claude/commands/scaffold-rules.md +0 -221
- package/.claude/commands/validate-skill.md +0 -29
- package/.claude/rules/git-workflow.md +0 -66
- package/.claude/skills/code-documentation/SKILL.md +0 -47
- package/.claude/skills/code-documentation/references/internal-templates.md +0 -113
- package/.claude/skills/code-documentation/references/maintenance.md +0 -164
- package/.claude/skills/code-documentation/references/public-api-templates.md +0 -100
- package/.claude/skills/code-documentation/references/type-documentation.md +0 -116
- package/.claude/skills/code-documentation/references/workflow.md +0 -60
- package/.claude/skills/scaffold-rules/SKILL.md +0 -104
- package/.claude/skills/typescript-lsp/SKILL.md +0 -249
- package/.claude/skills/validate-skill/SKILL.md +0 -105
- /package/{.claude → .plaited}/rules/bun-apis.md +0 -0
package/src/scaffold-rules.ts
CHANGED
|
@@ -2,40 +2,42 @@
|
|
|
2
2
|
/**
|
|
3
3
|
* Scaffold development rules from templates
|
|
4
4
|
*
|
|
5
|
-
* Reads bundled rule templates, processes template variables
|
|
5
|
+
* Reads bundled rule templates, processes template variables,
|
|
6
6
|
* and outputs JSON for agent consumption.
|
|
7
7
|
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
* (works with Cursor, Factory, Copilot, Windsurf, Cline, Aider, and 60,000+ others)
|
|
8
|
+
* All agents use `.plaited/rules/` as the unified default location.
|
|
9
|
+
* AGENTS.md serves as the single source of truth for rules content,
|
|
10
|
+
* while CLAUDE.md simply references it via @AGENTS.md syntax.
|
|
12
11
|
*
|
|
13
12
|
* Options:
|
|
14
|
-
* - --
|
|
15
|
-
* - --rules-dir, -d: Custom rules directory path (overrides default)
|
|
16
|
-
* - --agents-md-path, -m: Custom AGENTS.md file path (default: AGENTS.md)
|
|
13
|
+
* - --rules-dir, -d: Custom rules directory path (overrides default .plaited/rules)
|
|
17
14
|
* - --rules, -r: Filter to specific rules (can be used multiple times)
|
|
15
|
+
* - --list, -l: List available rules without full output
|
|
16
|
+
*
|
|
17
|
+
* Output includes:
|
|
18
|
+
* - agentsMdSection: Marker-wrapped section with markdown links for AGENTS.md
|
|
19
|
+
* - claudeMdReference: Short reference snippet pointing to @AGENTS.md
|
|
20
|
+
* - templates: Processed rule content for each selected rule
|
|
18
21
|
*
|
|
19
22
|
* Template syntax:
|
|
20
23
|
* - {{LINK:rule-id}} - Cross-reference to another rule
|
|
21
|
-
* - {{#if development-skills}}...{{/if}} - Conditional block
|
|
22
|
-
* - {{
|
|
23
|
-
* - {{^if condition}}...{{/if}} - Inverse conditional
|
|
24
|
+
* - {{#if development-skills}}...{{/if}} - Conditional block (always true when using CLI)
|
|
25
|
+
* - {{^if development-skills}}...{{/if}} - Inverse conditional
|
|
24
26
|
* - <!-- RULE TEMPLATE ... --> - Template header (removed)
|
|
25
27
|
*
|
|
26
|
-
* Capabilities:
|
|
27
|
-
* - has-sandbox: Agent runs in sandboxed environment (Claude Code only)
|
|
28
|
-
* - supports-slash-commands: Agent has /command syntax (Claude Code only)
|
|
29
|
-
*
|
|
30
28
|
* @example
|
|
31
29
|
* ```bash
|
|
32
|
-
* # Default
|
|
33
|
-
* bunx @plaited/development-skills scaffold-rules
|
|
34
|
-
*
|
|
30
|
+
* # Default: outputs to .plaited/rules/
|
|
31
|
+
* bunx @plaited/development-skills scaffold-rules
|
|
32
|
+
*
|
|
33
|
+
* # Custom rules directory
|
|
34
|
+
* bunx @plaited/development-skills scaffold-rules --rules-dir=.cursor/rules
|
|
35
35
|
*
|
|
36
|
-
* #
|
|
37
|
-
* bunx @plaited/development-skills scaffold-rules --
|
|
38
|
-
*
|
|
36
|
+
* # Filter specific rules
|
|
37
|
+
* bunx @plaited/development-skills scaffold-rules --rules testing --rules bun-apis
|
|
38
|
+
*
|
|
39
|
+
* # List available rules
|
|
40
|
+
* bunx @plaited/development-skills scaffold-rules --list
|
|
39
41
|
* ```
|
|
40
42
|
*/
|
|
41
43
|
|
|
@@ -44,144 +46,101 @@ import { join } from 'node:path'
|
|
|
44
46
|
import { parseArgs } from 'node:util'
|
|
45
47
|
|
|
46
48
|
/**
|
|
47
|
-
*
|
|
49
|
+
* Marker delimiters for programmatic file updates
|
|
48
50
|
*
|
|
49
51
|
* @remarks
|
|
50
|
-
*
|
|
51
|
-
*
|
|
52
|
-
*
|
|
52
|
+
* These markers allow scaffold-rules to update CLAUDE.md and AGENTS.md
|
|
53
|
+
* without destroying user content outside the marked section.
|
|
54
|
+
*
|
|
55
|
+
* Use these markers to implement idempotent updates:
|
|
56
|
+
* 1. Find existing markers in file content
|
|
57
|
+
* 2. Replace content between markers (inclusive) with new section
|
|
58
|
+
* 3. If no markers exist, append section to end of file
|
|
59
|
+
*
|
|
60
|
+
* @property start - Opening marker to place before rules section
|
|
61
|
+
* @property end - Closing marker to place after rules section
|
|
62
|
+
*
|
|
63
|
+
* @public
|
|
53
64
|
*/
|
|
54
|
-
|
|
65
|
+
export const MARKERS = {
|
|
66
|
+
start: '<!-- PLAITED-RULES-START -->',
|
|
67
|
+
end: '<!-- PLAITED-RULES-END -->',
|
|
68
|
+
} as const
|
|
55
69
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
70
|
+
/**
|
|
71
|
+
* Unified rules directory path
|
|
72
|
+
*
|
|
73
|
+
* @remarks
|
|
74
|
+
* All agents use `.plaited/rules/` as the default location.
|
|
75
|
+
* This provides consistency and allows both CLAUDE.md and AGENTS.md
|
|
76
|
+
* to reference the same rule files.
|
|
77
|
+
*/
|
|
78
|
+
const UNIFIED_RULES_PATH = '.plaited/rules' as const
|
|
62
79
|
|
|
63
80
|
type TemplateContext = {
|
|
64
|
-
agent: Agent
|
|
65
|
-
capabilities: AgentCapabilities
|
|
66
|
-
hasDevelopmentSkills: boolean
|
|
67
81
|
rulesPath: string
|
|
68
82
|
}
|
|
69
83
|
|
|
70
|
-
|
|
84
|
+
/**
|
|
85
|
+
* Processed template with filename, content, and description
|
|
86
|
+
*/
|
|
87
|
+
export type ProcessedTemplate = {
|
|
71
88
|
filename: string
|
|
72
89
|
content: string
|
|
73
90
|
description: string
|
|
74
91
|
}
|
|
75
92
|
|
|
76
|
-
type ScaffoldOutput = {
|
|
77
|
-
agent: Agent
|
|
78
|
-
rulesPath: string
|
|
79
|
-
agentsMdPath: string
|
|
80
|
-
format: 'multi-file' | 'agents-md'
|
|
81
|
-
supportsAgentsMd: boolean
|
|
82
|
-
agentsMdContent?: string
|
|
83
|
-
templates: Record<string, ProcessedTemplate>
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
/**
|
|
87
|
-
* Agent capabilities matrix
|
|
88
|
-
*
|
|
89
|
-
* @remarks
|
|
90
|
-
* - hasSandbox: Runs in restricted environment (affects git commands, temp files)
|
|
91
|
-
* - multiFileRules: Supports directory of rule files vs single file
|
|
92
|
-
* - supportsSlashCommands: Has /command syntax for invoking tools
|
|
93
|
-
* - supportsAgentsMd: Reads AGENTS.md format
|
|
94
|
-
*
|
|
95
|
-
* Note: We only support 2 targets now:
|
|
96
|
-
* - claude: Claude Code with unique .claude/ directory system
|
|
97
|
-
* - agents-md: Universal format for all AGENTS.md-compatible agents
|
|
98
|
-
* (Cursor, Factory, Copilot, Windsurf, Cline, Aider, and 60,000+ others)
|
|
99
|
-
*/
|
|
100
|
-
const AGENT_CAPABILITIES: Record<Agent, AgentCapabilities> = {
|
|
101
|
-
claude: {
|
|
102
|
-
hasSandbox: true,
|
|
103
|
-
multiFileRules: true,
|
|
104
|
-
supportsSlashCommands: true,
|
|
105
|
-
supportsAgentsMd: false,
|
|
106
|
-
},
|
|
107
|
-
'agents-md': {
|
|
108
|
-
hasSandbox: false,
|
|
109
|
-
multiFileRules: true,
|
|
110
|
-
supportsSlashCommands: false,
|
|
111
|
-
supportsAgentsMd: true,
|
|
112
|
-
},
|
|
113
|
-
}
|
|
114
|
-
|
|
115
93
|
/**
|
|
116
|
-
*
|
|
94
|
+
* Output from scaffold-rules CLI
|
|
117
95
|
*/
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
if (condition === 'has-sandbox') {
|
|
126
|
-
return context.capabilities.hasSandbox
|
|
127
|
-
}
|
|
128
|
-
if (condition === 'multi-file-rules') {
|
|
129
|
-
return context.capabilities.multiFileRules
|
|
130
|
-
}
|
|
131
|
-
if (condition === 'supports-slash-commands') {
|
|
132
|
-
return context.capabilities.supportsSlashCommands
|
|
133
|
-
}
|
|
134
|
-
if (condition === 'supports-agents-md') {
|
|
135
|
-
return context.capabilities.supportsAgentsMd
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
// Check agent-specific conditions (legacy: agent:name)
|
|
139
|
-
const agentMatch = condition.match(/^agent:(\w+)$/)
|
|
140
|
-
if (agentMatch) {
|
|
141
|
-
return context.agent === agentMatch[1]
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
return false
|
|
96
|
+
export type ScaffoldOutput = {
|
|
97
|
+
rulesPath: string
|
|
98
|
+
/** Marker-wrapped section with markdown links for AGENTS.md */
|
|
99
|
+
agentsMdSection: string
|
|
100
|
+
/** Short reference snippet for CLAUDE.md pointing to AGENTS.md */
|
|
101
|
+
claudeMdReference: string
|
|
102
|
+
templates: Record<string, ProcessedTemplate>
|
|
145
103
|
}
|
|
146
104
|
|
|
147
105
|
/**
|
|
148
106
|
* Process template conditionals
|
|
149
107
|
*
|
|
150
108
|
* Handles:
|
|
151
|
-
* - {{#if development-skills}}...{{/if}}
|
|
152
|
-
* - {{
|
|
153
|
-
* - {{#if agent:name}}...{{/if}} (legacy, still supported)
|
|
154
|
-
* - {{^if condition}}...{{/if}} (inverse)
|
|
109
|
+
* - {{#if development-skills}}...{{/if}} - Always true (using our CLI means dev-skills is installed)
|
|
110
|
+
* - {{^if development-skills}}...{{/if}} - Always false
|
|
155
111
|
*
|
|
156
112
|
* Processes iteratively to handle nested conditionals correctly.
|
|
157
113
|
*/
|
|
158
|
-
const processConditionals = (content: string
|
|
114
|
+
const processConditionals = (content: string): string => {
|
|
159
115
|
let result = content
|
|
160
116
|
let previousResult = ''
|
|
117
|
+
const maxIterations = 100
|
|
118
|
+
let iterations = 0
|
|
161
119
|
|
|
162
120
|
// Process iteratively until no more changes (handles nested conditionals)
|
|
163
|
-
while (result !== previousResult) {
|
|
121
|
+
while (result !== previousResult && iterations < maxIterations) {
|
|
164
122
|
previousResult = result
|
|
123
|
+
iterations++
|
|
165
124
|
|
|
166
|
-
// Process positive conditionals {{#if
|
|
167
|
-
//
|
|
168
|
-
// Note: Nested quantifiers are safe here - input is trusted bundled templates, not user content
|
|
125
|
+
// Process positive conditionals {{#if development-skills}}...{{/if}}
|
|
126
|
+
// Always true - include the block content
|
|
169
127
|
result = result.replace(
|
|
170
|
-
/\{\{#if
|
|
171
|
-
(_,
|
|
172
|
-
return evaluateCondition(condition, context) ? block : ''
|
|
173
|
-
},
|
|
128
|
+
/\{\{#if development-skills\}\}((?:(?!\{\{#if )(?!\{\{\^if )(?!\{\{\/if\}\})[\s\S])*?)\{\{\/if\}\}/g,
|
|
129
|
+
(_, block) => block,
|
|
174
130
|
)
|
|
175
131
|
|
|
176
|
-
// Process inverse conditionals {{^if
|
|
132
|
+
// Process inverse conditionals {{^if development-skills}}...{{/if}}
|
|
133
|
+
// Always false - remove the block content
|
|
177
134
|
result = result.replace(
|
|
178
|
-
/\{\{\^if
|
|
179
|
-
(
|
|
180
|
-
return evaluateCondition(condition, context) ? '' : block
|
|
181
|
-
},
|
|
135
|
+
/\{\{\^if development-skills\}\}((?:(?!\{\{#if )(?!\{\{\^if )(?!\{\{\/if\}\})[\s\S])*?)\{\{\/if\}\}/g,
|
|
136
|
+
() => '',
|
|
182
137
|
)
|
|
183
138
|
}
|
|
184
139
|
|
|
140
|
+
if (iterations >= maxIterations) {
|
|
141
|
+
console.warn('Warning: Max iterations reached in template processing. Some conditionals may be unprocessed.')
|
|
142
|
+
}
|
|
143
|
+
|
|
185
144
|
return result
|
|
186
145
|
}
|
|
187
146
|
|
|
@@ -189,39 +148,23 @@ const processConditionals = (content: string, context: TemplateContext): string
|
|
|
189
148
|
* Process template variables
|
|
190
149
|
*
|
|
191
150
|
* Handles:
|
|
192
|
-
* - {{LINK:rule-id}} - Generate cross-reference
|
|
193
|
-
* - {{AGENT_NAME}} - Agent name
|
|
151
|
+
* - {{LINK:rule-id}} - Generate cross-reference path
|
|
194
152
|
* - {{RULES_PATH}} - Rules path
|
|
195
153
|
*/
|
|
196
154
|
const processVariables = (content: string, context: TemplateContext): string => {
|
|
197
155
|
let result = content
|
|
198
156
|
|
|
199
|
-
// Replace {{LINK:rule-id}} with
|
|
157
|
+
// Replace {{LINK:rule-id}} with path reference
|
|
200
158
|
result = result.replace(/\{\{LINK:(\w+)\}\}/g, (_, ruleId) => {
|
|
201
|
-
return
|
|
159
|
+
return `${context.rulesPath}/${ruleId}.md`
|
|
202
160
|
})
|
|
203
161
|
|
|
204
|
-
// Replace {{AGENT_NAME}}
|
|
205
|
-
result = result.replace(/\{\{AGENT_NAME\}\}/g, context.agent)
|
|
206
|
-
|
|
207
162
|
// Replace {{RULES_PATH}}
|
|
208
163
|
result = result.replace(/\{\{RULES_PATH\}\}/g, context.rulesPath)
|
|
209
164
|
|
|
210
165
|
return result
|
|
211
166
|
}
|
|
212
167
|
|
|
213
|
-
/**
|
|
214
|
-
* Generate cross-reference based on agent format
|
|
215
|
-
*/
|
|
216
|
-
const generateCrossReference = (ruleId: string, context: TemplateContext): string => {
|
|
217
|
-
if (context.agent === 'claude') {
|
|
218
|
-
// Claude Code uses @ syntax for file references
|
|
219
|
-
return `@${context.rulesPath}/${ruleId}.md`
|
|
220
|
-
}
|
|
221
|
-
// Use context.rulesPath for cross-references (supports custom --rules-dir)
|
|
222
|
-
return `${context.rulesPath}/${ruleId}.md`
|
|
223
|
-
}
|
|
224
|
-
|
|
225
168
|
/**
|
|
226
169
|
* Remove template headers
|
|
227
170
|
*/
|
|
@@ -238,7 +181,8 @@ const extractDescription = (content: string): string => {
|
|
|
238
181
|
let description = ''
|
|
239
182
|
|
|
240
183
|
for (let i = 1; i < lines.length; i++) {
|
|
241
|
-
|
|
184
|
+
// Non-null assertion safe: loop condition guarantees i < lines.length
|
|
185
|
+
const line = lines[i]!.trim()
|
|
242
186
|
if (line && !line.startsWith('#') && !line.startsWith('**')) {
|
|
243
187
|
description = line
|
|
244
188
|
break
|
|
@@ -258,7 +202,7 @@ const processTemplate = (content: string, context: TemplateContext): string => {
|
|
|
258
202
|
result = removeTemplateHeaders(result)
|
|
259
203
|
|
|
260
204
|
// 2. Process conditionals
|
|
261
|
-
result = processConditionals(result
|
|
205
|
+
result = processConditionals(result)
|
|
262
206
|
|
|
263
207
|
// 3. Process variables
|
|
264
208
|
result = processVariables(result, context)
|
|
@@ -270,27 +214,39 @@ const processTemplate = (content: string, context: TemplateContext): string => {
|
|
|
270
214
|
}
|
|
271
215
|
|
|
272
216
|
/**
|
|
273
|
-
*
|
|
217
|
+
* Generate marker-wrapped reference snippet for CLAUDE.md
|
|
218
|
+
*
|
|
219
|
+
* @remarks
|
|
220
|
+
* Claude Code uses `@file.md` syntax to include file contents.
|
|
221
|
+
* This generates a short reference pointing to AGENTS.md as the single source of truth.
|
|
222
|
+
* The markers allow this section to be updated without affecting other content.
|
|
274
223
|
*/
|
|
275
|
-
const
|
|
276
|
-
|
|
277
|
-
|
|
224
|
+
const generateClaudeMdReference = (): string => {
|
|
225
|
+
const lines = [
|
|
226
|
+
MARKERS.start,
|
|
227
|
+
'',
|
|
228
|
+
'## Project Rules',
|
|
229
|
+
'',
|
|
230
|
+
'See @AGENTS.md for shared development rules.',
|
|
231
|
+
'',
|
|
232
|
+
MARKERS.end,
|
|
233
|
+
]
|
|
278
234
|
|
|
279
|
-
|
|
280
|
-
* Get output format for agent
|
|
281
|
-
*/
|
|
282
|
-
const getOutputFormat = (agent: Agent): 'multi-file' | 'agents-md' => {
|
|
283
|
-
return agent === 'claude' ? 'multi-file' : 'agents-md'
|
|
235
|
+
return lines.join('\n')
|
|
284
236
|
}
|
|
285
237
|
|
|
286
238
|
/**
|
|
287
|
-
* Generate AGENTS.md
|
|
239
|
+
* Generate marker-wrapped section for AGENTS.md with dual format
|
|
240
|
+
*
|
|
241
|
+
* @remarks
|
|
242
|
+
* AGENTS.md uses both formats for maximum compatibility:
|
|
243
|
+
* - `@path` syntax for Claude Code to load file contents
|
|
244
|
+
* - `[name](path)` markdown links for other tools and GitHub rendering
|
|
245
|
+
* The markers allow this section to be updated without affecting other content.
|
|
288
246
|
*/
|
|
289
|
-
const
|
|
247
|
+
const generateAgentsMdSection = (templates: Record<string, ProcessedTemplate>, rulesPath: string): string => {
|
|
290
248
|
const lines = [
|
|
291
|
-
|
|
292
|
-
'',
|
|
293
|
-
'Development rules for AI coding agents.',
|
|
249
|
+
MARKERS.start,
|
|
294
250
|
'',
|
|
295
251
|
'## Rules',
|
|
296
252
|
'',
|
|
@@ -300,14 +256,12 @@ const generateAgentsMd = (templates: Record<string, ProcessedTemplate>, rulesPat
|
|
|
300
256
|
]
|
|
301
257
|
|
|
302
258
|
for (const [ruleId, template] of Object.entries(templates)) {
|
|
303
|
-
|
|
259
|
+
// Dual format: @ syntax for Claude Code, markdown link for other tools
|
|
260
|
+
lines.push(`- @${rulesPath}/${template.filename} - [${ruleId}](${rulesPath}/${template.filename})`)
|
|
304
261
|
}
|
|
305
262
|
|
|
306
263
|
lines.push('')
|
|
307
|
-
lines.push(
|
|
308
|
-
lines.push('')
|
|
309
|
-
lines.push('For detailed guidance on each topic, see the linked rule files above.')
|
|
310
|
-
lines.push('')
|
|
264
|
+
lines.push(MARKERS.end)
|
|
311
265
|
|
|
312
266
|
return lines.join('\n')
|
|
313
267
|
}
|
|
@@ -319,16 +273,6 @@ export const scaffoldRules = async (args: string[]): Promise<void> => {
|
|
|
319
273
|
const { values } = parseArgs({
|
|
320
274
|
args,
|
|
321
275
|
options: {
|
|
322
|
-
agent: {
|
|
323
|
-
type: 'string',
|
|
324
|
-
short: 'a',
|
|
325
|
-
default: 'claude',
|
|
326
|
-
},
|
|
327
|
-
format: {
|
|
328
|
-
type: 'string',
|
|
329
|
-
short: 'f',
|
|
330
|
-
default: 'json',
|
|
331
|
-
},
|
|
332
276
|
rules: {
|
|
333
277
|
type: 'string',
|
|
334
278
|
short: 'r',
|
|
@@ -338,54 +282,55 @@ export const scaffoldRules = async (args: string[]): Promise<void> => {
|
|
|
338
282
|
type: 'string',
|
|
339
283
|
short: 'd',
|
|
340
284
|
},
|
|
341
|
-
|
|
342
|
-
type: '
|
|
343
|
-
short: '
|
|
285
|
+
list: {
|
|
286
|
+
type: 'boolean',
|
|
287
|
+
short: 'l',
|
|
344
288
|
},
|
|
345
289
|
},
|
|
346
290
|
allowPositionals: true,
|
|
347
291
|
strict: false,
|
|
348
292
|
})
|
|
349
293
|
|
|
350
|
-
const agent = values.agent as Agent
|
|
351
294
|
const rulesFilter = values.rules as string[] | undefined
|
|
352
295
|
const customRulesDir = values['rules-dir'] as string | undefined
|
|
353
|
-
const
|
|
354
|
-
|
|
355
|
-
// Validate agent
|
|
356
|
-
const validAgents: Agent[] = ['claude', 'agents-md']
|
|
357
|
-
if (!validAgents.includes(agent)) {
|
|
358
|
-
console.error(`Error: Invalid agent "${agent}". Must be one of: ${validAgents.join(', ')}`)
|
|
359
|
-
console.error(
|
|
360
|
-
'Note: Use "agents-md" for Cursor, Factory, Copilot, Windsurf, Cline, Aider, and other AGENTS.md-compatible tools.',
|
|
361
|
-
)
|
|
362
|
-
process.exit(1)
|
|
363
|
-
}
|
|
296
|
+
const listOnly = values.list as boolean | undefined
|
|
364
297
|
|
|
365
298
|
// Get bundled templates directory
|
|
366
|
-
const packageRulesDir = join(import.meta.dir, '../.
|
|
299
|
+
const packageRulesDir = join(import.meta.dir, '../.plaited/rules')
|
|
367
300
|
|
|
368
301
|
// Read template files
|
|
369
302
|
const templateFiles = await readdir(packageRulesDir)
|
|
370
303
|
|
|
371
304
|
// Filter to .md files
|
|
372
305
|
const mdFiles = templateFiles.filter((f) => f.endsWith('.md'))
|
|
306
|
+
const availableRuleIds = mdFiles.map((f) => f.replace('.md', ''))
|
|
307
|
+
|
|
308
|
+
// Validate requested rules exist
|
|
309
|
+
if (rulesFilter) {
|
|
310
|
+
const invalidRules = rulesFilter.filter((r) => !availableRuleIds.includes(r))
|
|
311
|
+
if (invalidRules.length > 0) {
|
|
312
|
+
console.error(`Warning: Unknown rules: ${invalidRules.join(', ')}`)
|
|
313
|
+
console.error(`Available rules: ${availableRuleIds.join(', ')}`)
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
// Handle --list flag: output available rules and exit
|
|
318
|
+
if (listOnly) {
|
|
319
|
+
const listOutput = availableRuleIds.map((id) => ({ id, filename: `${id}.md` }))
|
|
320
|
+
console.log(JSON.stringify(listOutput, null, 2))
|
|
321
|
+
return
|
|
322
|
+
}
|
|
373
323
|
|
|
374
324
|
// Filter if specific rules requested
|
|
375
325
|
const rulesToProcess = rulesFilter ? mdFiles.filter((f) => rulesFilter.includes(f.replace('.md', ''))) : mdFiles
|
|
376
326
|
|
|
377
327
|
// Process each template
|
|
378
328
|
const templates: Record<string, ProcessedTemplate> = {}
|
|
379
|
-
const capabilities = AGENT_CAPABILITIES[agent]
|
|
380
329
|
|
|
381
|
-
// Use custom
|
|
382
|
-
const rulesPath = customRulesDir ??
|
|
383
|
-
const agentsMdPath = customAgentsMdPath ?? 'AGENTS.md'
|
|
330
|
+
// Use custom path or unified default
|
|
331
|
+
const rulesPath = customRulesDir ?? UNIFIED_RULES_PATH
|
|
384
332
|
|
|
385
333
|
const context: TemplateContext = {
|
|
386
|
-
agent,
|
|
387
|
-
capabilities,
|
|
388
|
-
hasDevelopmentSkills: true, // Always true when using our CLI
|
|
389
334
|
rulesPath,
|
|
390
335
|
}
|
|
391
336
|
|
|
@@ -405,27 +350,23 @@ export const scaffoldRules = async (args: string[]): Promise<void> => {
|
|
|
405
350
|
description: extractDescription(processed),
|
|
406
351
|
}
|
|
407
352
|
} catch (error) {
|
|
408
|
-
|
|
409
|
-
console.error(`Error processing template ${file}: ${message}`)
|
|
353
|
+
console.error(`Error processing template ${file}:`, error)
|
|
410
354
|
process.exit(1)
|
|
411
355
|
}
|
|
412
356
|
}
|
|
413
357
|
|
|
358
|
+
// Generate marker-wrapped section for AGENTS.md and reference for CLAUDE.md
|
|
359
|
+
const agentsMdSection = generateAgentsMdSection(templates, rulesPath)
|
|
360
|
+
const claudeMdReference = generateClaudeMdReference()
|
|
361
|
+
|
|
414
362
|
// Build output
|
|
415
363
|
const output: ScaffoldOutput = {
|
|
416
|
-
agent,
|
|
417
364
|
rulesPath,
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
supportsAgentsMd: capabilities.supportsAgentsMd,
|
|
365
|
+
agentsMdSection,
|
|
366
|
+
claudeMdReference,
|
|
421
367
|
templates,
|
|
422
368
|
}
|
|
423
369
|
|
|
424
|
-
// Generate AGENTS.md content for agents-md format
|
|
425
|
-
if (agent === 'agents-md') {
|
|
426
|
-
output.agentsMdContent = generateAgentsMd(templates, rulesPath)
|
|
427
|
-
}
|
|
428
|
-
|
|
429
370
|
console.log(JSON.stringify(output, null, 2))
|
|
430
371
|
}
|
|
431
372
|
|