ai-eng-system 0.0.13 → 0.0.15
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 +24 -5
- package/dist/.claude-plugin/agents/agent-creator.md +1 -1
- package/dist/.claude-plugin/agents/command-creator.md +0 -1
- package/dist/.claude-plugin/agents/docs-writer.md +0 -1
- package/dist/.claude-plugin/agents/documentation_specialist.md +0 -1
- package/dist/.claude-plugin/agents/plugin-validator.md +0 -1
- package/dist/.claude-plugin/agents/subagent-orchestration.md +224 -0
- package/dist/.claude-plugin/analyzer.ts +447 -0
- package/dist/.claude-plugin/commands/create-skill.md +2 -2
- package/dist/.claude-plugin/commands/optimize.md +1075 -32
- package/dist/.claude-plugin/commands/plan.md +62 -32
- package/dist/.claude-plugin/commands/research.md +67 -63
- package/dist/.claude-plugin/commands/review.md +83 -10
- package/dist/.claude-plugin/commands/specify.md +54 -16
- package/dist/.claude-plugin/commands/work.md +57 -14
- package/dist/.claude-plugin/formatter.ts +274 -0
- package/dist/.claude-plugin/hooks/hooks.json +0 -0
- package/dist/.claude-plugin/hooks/prompt-optimizer-hook.py +0 -0
- package/dist/.claude-plugin/index.ts +54 -0
- package/dist/.claude-plugin/marketplace.json +3 -3
- package/dist/.claude-plugin/optimizer.ts +441 -0
- package/dist/.claude-plugin/plugin.json +9 -9
- package/dist/.claude-plugin/skills/plugin-dev/SKILL.md +0 -2
- package/dist/.claude-plugin/skills/plugin-dev/references/agent-format.md +1 -6
- package/dist/.claude-plugin/skills/plugin-dev/references/claude-code-plugins.md +0 -2
- package/dist/.claude-plugin/skills/plugin-dev/references/command-format.md +0 -3
- package/dist/.claude-plugin/skills/plugin-dev/references/opencode-plugins.md +7 -7
- package/dist/.claude-plugin/skills/plugin-dev/references/skill-format.md +1 -1
- package/dist/.claude-plugin/techniques.ts +230 -0
- package/dist/.claude-plugin/types.ts +214 -0
- package/dist/.opencode/agent/ai-eng/development/docs-writer.md +0 -1
- package/dist/.opencode/agent/ai-eng/development/documentation_specialist.md +0 -1
- package/dist/.opencode/agent/ai-eng/general/subagent-orchestration.md +225 -0
- package/dist/.opencode/agent/ai-eng/meta/agent-creator.md +1 -1
- package/dist/.opencode/agent/ai-eng/meta/command-creator.md +0 -1
- package/dist/.opencode/agent/ai-eng/quality-testing/plugin-validator.md +0 -1
- package/dist/.opencode/command/ai-eng/create-skill.md +2 -2
- package/dist/.opencode/command/ai-eng/optimize.md +1075 -32
- package/dist/.opencode/command/ai-eng/plan.md +62 -32
- package/dist/.opencode/command/ai-eng/research.md +67 -63
- package/dist/.opencode/command/ai-eng/review.md +83 -10
- package/dist/.opencode/command/ai-eng/specify.md +54 -16
- package/dist/.opencode/command/ai-eng/work.md +57 -14
- package/dist/.opencode/skill/plugin-dev/SKILL.md +0 -2
- package/dist/.opencode/skill/plugin-dev/references/agent-format.md +1 -6
- package/dist/.opencode/skill/plugin-dev/references/claude-code-plugins.md +0 -2
- package/dist/.opencode/skill/plugin-dev/references/command-format.md +0 -3
- package/dist/.opencode/skill/plugin-dev/references/opencode-plugins.md +7 -7
- package/dist/.opencode/skill/plugin-dev/references/skill-format.md +1 -1
- package/dist/.opencode/tool/prompt-optimize.ts +184 -0
- package/dist/index.js +13 -46
- package/dist/prompt-optimization/analyzer.ts +447 -0
- package/dist/prompt-optimization/formatter.ts +274 -0
- package/dist/prompt-optimization/index.ts +54 -0
- package/dist/prompt-optimization/optimizer.ts +441 -0
- package/dist/prompt-optimization/techniques.ts +230 -0
- package/dist/prompt-optimization/types.ts +214 -0
- package/dist/skills/plugin-dev/SKILL.md +0 -2
- package/dist/skills/plugin-dev/references/agent-format.md +1 -6
- package/dist/skills/plugin-dev/references/claude-code-plugins.md +0 -2
- package/dist/skills/plugin-dev/references/command-format.md +0 -3
- package/dist/skills/plugin-dev/references/opencode-plugins.md +7 -7
- package/dist/skills/plugin-dev/references/skill-format.md +1 -1
- package/package.json +5 -3
- package/scripts/install.js +333 -47
- package/dist/.claude-plugin/hooks.json +0 -17
|
@@ -0,0 +1,447 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Prompt Analyzer
|
|
3
|
+
*
|
|
4
|
+
* Analyzes user prompts to determine complexity, domain,
|
|
5
|
+
* and missing context. Uses a combination of word count,
|
|
6
|
+
* keyword detection, and pattern matching.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import type { AnalysisResult, Complexity, Domain, TechniqueId } from "./types";
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Keywords for complexity detection
|
|
13
|
+
*/
|
|
14
|
+
const COMPLEXITY_KEYWORDS = {
|
|
15
|
+
debug: ["debug", "fix", "error", "bug", "issue", "problem", "troubleshoot"],
|
|
16
|
+
design: [
|
|
17
|
+
"design",
|
|
18
|
+
"architecture",
|
|
19
|
+
"architect",
|
|
20
|
+
"structure",
|
|
21
|
+
"pattern",
|
|
22
|
+
"approach",
|
|
23
|
+
],
|
|
24
|
+
optimize: [
|
|
25
|
+
"optimize",
|
|
26
|
+
"improve",
|
|
27
|
+
"performance",
|
|
28
|
+
"efficient",
|
|
29
|
+
"fast",
|
|
30
|
+
"scale",
|
|
31
|
+
],
|
|
32
|
+
implement: ["implement", "build", "create", "develop", "write", "code"],
|
|
33
|
+
complex: ["complex", "challenge", "difficult", "advanced", "sophisticated"],
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Domain-specific keywords
|
|
38
|
+
*/
|
|
39
|
+
const DOMAIN_KEYWORDS: Record<Domain, string[]> = {
|
|
40
|
+
security: [
|
|
41
|
+
"auth",
|
|
42
|
+
"authentication",
|
|
43
|
+
"jwt",
|
|
44
|
+
"oauth",
|
|
45
|
+
"password",
|
|
46
|
+
"encrypt",
|
|
47
|
+
"decrypt",
|
|
48
|
+
"security",
|
|
49
|
+
"token",
|
|
50
|
+
"session",
|
|
51
|
+
"csrf",
|
|
52
|
+
"xss",
|
|
53
|
+
"injection",
|
|
54
|
+
"vulnerability",
|
|
55
|
+
"hack",
|
|
56
|
+
"attack",
|
|
57
|
+
],
|
|
58
|
+
frontend: [
|
|
59
|
+
"react",
|
|
60
|
+
"vue",
|
|
61
|
+
"angular",
|
|
62
|
+
"component",
|
|
63
|
+
"css",
|
|
64
|
+
"html",
|
|
65
|
+
"ui",
|
|
66
|
+
"ux",
|
|
67
|
+
"render",
|
|
68
|
+
"state",
|
|
69
|
+
"hook",
|
|
70
|
+
"props",
|
|
71
|
+
"dom",
|
|
72
|
+
"frontend",
|
|
73
|
+
"client",
|
|
74
|
+
],
|
|
75
|
+
backend: [
|
|
76
|
+
"api",
|
|
77
|
+
"server",
|
|
78
|
+
"endpoint",
|
|
79
|
+
"database",
|
|
80
|
+
"query",
|
|
81
|
+
"backend",
|
|
82
|
+
"service",
|
|
83
|
+
"microservice",
|
|
84
|
+
"rest",
|
|
85
|
+
"graphql",
|
|
86
|
+
"http",
|
|
87
|
+
"request",
|
|
88
|
+
"response",
|
|
89
|
+
],
|
|
90
|
+
database: [
|
|
91
|
+
"sql",
|
|
92
|
+
"postgresql",
|
|
93
|
+
"mysql",
|
|
94
|
+
"mongodb",
|
|
95
|
+
"redis",
|
|
96
|
+
"query",
|
|
97
|
+
"index",
|
|
98
|
+
"schema",
|
|
99
|
+
"migration",
|
|
100
|
+
"database",
|
|
101
|
+
"db",
|
|
102
|
+
"join",
|
|
103
|
+
"transaction",
|
|
104
|
+
"orm",
|
|
105
|
+
],
|
|
106
|
+
devops: [
|
|
107
|
+
"deploy",
|
|
108
|
+
"ci/cd",
|
|
109
|
+
"docker",
|
|
110
|
+
"kubernetes",
|
|
111
|
+
"k8s",
|
|
112
|
+
"pipeline",
|
|
113
|
+
"infrastructure",
|
|
114
|
+
"aws",
|
|
115
|
+
"gcp",
|
|
116
|
+
"azure",
|
|
117
|
+
"terraform",
|
|
118
|
+
"ansible",
|
|
119
|
+
"jenkins",
|
|
120
|
+
"devops",
|
|
121
|
+
"ops",
|
|
122
|
+
],
|
|
123
|
+
architecture: [
|
|
124
|
+
"architecture",
|
|
125
|
+
"design",
|
|
126
|
+
"pattern",
|
|
127
|
+
"microservices",
|
|
128
|
+
"monolith",
|
|
129
|
+
"scalability",
|
|
130
|
+
"system",
|
|
131
|
+
"distributed",
|
|
132
|
+
"architect",
|
|
133
|
+
"high-level",
|
|
134
|
+
],
|
|
135
|
+
testing: [
|
|
136
|
+
"test",
|
|
137
|
+
"spec",
|
|
138
|
+
"unit test",
|
|
139
|
+
"integration test",
|
|
140
|
+
"e2e",
|
|
141
|
+
"jest",
|
|
142
|
+
"cypress",
|
|
143
|
+
"playwright",
|
|
144
|
+
"testing",
|
|
145
|
+
"tdd",
|
|
146
|
+
"coverage",
|
|
147
|
+
"mock",
|
|
148
|
+
"stub",
|
|
149
|
+
],
|
|
150
|
+
general: [], // Fallback domain
|
|
151
|
+
};
|
|
152
|
+
|
|
153
|
+
/**
|
|
154
|
+
* Simple prompt patterns (greetings, simple questions)
|
|
155
|
+
*/
|
|
156
|
+
const SIMPLE_PATTERNS = [
|
|
157
|
+
/^(hello|hi|hey|greetings|good morning|good evening)/i,
|
|
158
|
+
/^(thanks|thank you|thx)/i,
|
|
159
|
+
/^(yes|no|ok|sure|alright)/i,
|
|
160
|
+
/^(what|how|why|when|where|who|which)\s+\w+\??$/i, // Simple single questions
|
|
161
|
+
/^(help|assist)\s*$/i,
|
|
162
|
+
];
|
|
163
|
+
|
|
164
|
+
/**
|
|
165
|
+
* Calculate complexity score for a prompt
|
|
166
|
+
*/
|
|
167
|
+
function calculateComplexityScore(prompt: string): number {
|
|
168
|
+
const words = prompt.split(/\s+/);
|
|
169
|
+
const wordCount = words.length;
|
|
170
|
+
|
|
171
|
+
let score = 0;
|
|
172
|
+
|
|
173
|
+
// Word count contribution (0-10 points)
|
|
174
|
+
if (wordCount < 5) score += 0;
|
|
175
|
+
else if (wordCount < 10) score += 3;
|
|
176
|
+
else if (wordCount < 20) score += 6;
|
|
177
|
+
else score += 10;
|
|
178
|
+
|
|
179
|
+
// Keyword contribution (0-10 points)
|
|
180
|
+
const lowerPrompt = prompt.toLowerCase();
|
|
181
|
+
for (const category of Object.values(COMPLEXITY_KEYWORDS)) {
|
|
182
|
+
for (const keyword of category) {
|
|
183
|
+
if (lowerPrompt.includes(keyword)) {
|
|
184
|
+
score += 2;
|
|
185
|
+
break; // One keyword per category
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
// Question marks reduce complexity (asking for info is simpler)
|
|
191
|
+
const questionMarks = (prompt.match(/\?/g) || []).length;
|
|
192
|
+
score -= Math.min(questionMarks * 2, 5);
|
|
193
|
+
|
|
194
|
+
// Technical terms increase complexity
|
|
195
|
+
const techTerms = words.filter((word) => {
|
|
196
|
+
const lower = word.toLowerCase();
|
|
197
|
+
return (
|
|
198
|
+
/\w{4,}/.test(word) &&
|
|
199
|
+
!["this", "that", "with", "from", "into"].includes(lower)
|
|
200
|
+
);
|
|
201
|
+
});
|
|
202
|
+
score += Math.min(techTerms.length * 0.5, 5);
|
|
203
|
+
|
|
204
|
+
return Math.max(0, Math.min(20, score));
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
/**
|
|
208
|
+
* Determine complexity from score
|
|
209
|
+
*/
|
|
210
|
+
function scoreToComplexity(score: number): Complexity {
|
|
211
|
+
if (score < 5) return "simple";
|
|
212
|
+
if (score < 12) return "medium";
|
|
213
|
+
return "complex";
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
/**
|
|
217
|
+
* Check if prompt matches simple patterns
|
|
218
|
+
*/
|
|
219
|
+
function isSimplePrompt(prompt: string): boolean {
|
|
220
|
+
for (const pattern of SIMPLE_PATTERNS) {
|
|
221
|
+
if (pattern.test(prompt.trim())) {
|
|
222
|
+
return true;
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
return false;
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
/**
|
|
229
|
+
* Detect domain from prompt keywords
|
|
230
|
+
*/
|
|
231
|
+
function detectDomain(prompt: string): Domain {
|
|
232
|
+
const lowerPrompt = prompt.toLowerCase();
|
|
233
|
+
|
|
234
|
+
// Count keyword matches per domain
|
|
235
|
+
const scores: Record<Domain, number> = {
|
|
236
|
+
security: 0,
|
|
237
|
+
frontend: 0,
|
|
238
|
+
backend: 0,
|
|
239
|
+
database: 0,
|
|
240
|
+
devops: 0,
|
|
241
|
+
architecture: 0,
|
|
242
|
+
testing: 0,
|
|
243
|
+
general: 0,
|
|
244
|
+
};
|
|
245
|
+
|
|
246
|
+
for (const [domain, keywords] of Object.entries(DOMAIN_KEYWORDS)) {
|
|
247
|
+
for (const keyword of keywords) {
|
|
248
|
+
if (lowerPrompt.includes(keyword)) {
|
|
249
|
+
scores[domain as Domain]++;
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
// Find domain with highest score
|
|
255
|
+
let bestDomain: Domain = "general";
|
|
256
|
+
let bestScore = 0;
|
|
257
|
+
|
|
258
|
+
for (const [domain, score] of Object.entries(scores)) {
|
|
259
|
+
if (score > bestScore) {
|
|
260
|
+
bestScore = score;
|
|
261
|
+
bestDomain = domain as Domain;
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
return bestDomain;
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
/**
|
|
269
|
+
* Extract keywords from prompt
|
|
270
|
+
*/
|
|
271
|
+
function extractKeywords(prompt: string): string[] {
|
|
272
|
+
const keywords: string[] = [];
|
|
273
|
+
const lowerPrompt = prompt.toLowerCase();
|
|
274
|
+
|
|
275
|
+
// Extract from complexity keywords
|
|
276
|
+
for (const [category, terms] of Object.entries(COMPLEXITY_KEYWORDS)) {
|
|
277
|
+
for (const term of terms) {
|
|
278
|
+
if (lowerPrompt.includes(term) && !keywords.includes(term)) {
|
|
279
|
+
keywords.push(term);
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
// Extract from domain keywords
|
|
285
|
+
for (const [domain, terms] of Object.entries(DOMAIN_KEYWORDS)) {
|
|
286
|
+
for (const term of terms) {
|
|
287
|
+
if (lowerPrompt.includes(term) && !keywords.includes(term)) {
|
|
288
|
+
keywords.push(term);
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
return keywords;
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
/**
|
|
297
|
+
* Identify missing context based on prompt content
|
|
298
|
+
*/
|
|
299
|
+
function identifyMissingContext(prompt: string, domain: Domain): string[] {
|
|
300
|
+
const missing: string[] = [];
|
|
301
|
+
const lowerPrompt = prompt.toLowerCase();
|
|
302
|
+
|
|
303
|
+
// Check for debug/fix requests
|
|
304
|
+
if (
|
|
305
|
+
lowerPrompt.includes("fix") ||
|
|
306
|
+
lowerPrompt.includes("debug") ||
|
|
307
|
+
lowerPrompt.includes("error")
|
|
308
|
+
) {
|
|
309
|
+
if (
|
|
310
|
+
!lowerPrompt.includes("error") &&
|
|
311
|
+
!lowerPrompt.includes("exception")
|
|
312
|
+
) {
|
|
313
|
+
missing.push("error message or stack trace");
|
|
314
|
+
}
|
|
315
|
+
if (!/\.(js|ts|py|go|java|rb|php)/i.test(prompt)) {
|
|
316
|
+
missing.push("file or code location");
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
// Check for tech stack
|
|
321
|
+
const techKeywords = [
|
|
322
|
+
"javascript",
|
|
323
|
+
"typescript",
|
|
324
|
+
"python",
|
|
325
|
+
"go",
|
|
326
|
+
"java",
|
|
327
|
+
"rust",
|
|
328
|
+
"react",
|
|
329
|
+
"vue",
|
|
330
|
+
"angular",
|
|
331
|
+
"node",
|
|
332
|
+
"express",
|
|
333
|
+
"django",
|
|
334
|
+
"flask",
|
|
335
|
+
];
|
|
336
|
+
const hasTech = techKeywords.some((tech) => lowerPrompt.includes(tech));
|
|
337
|
+
if (!hasTech && !/\.(js|ts|py|go|java|rb|php)/i.test(prompt)) {
|
|
338
|
+
missing.push("technology stack");
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
// Domain-specific missing context
|
|
342
|
+
if (domain === "security") {
|
|
343
|
+
if (
|
|
344
|
+
!lowerPrompt.includes("jwt") &&
|
|
345
|
+
!lowerPrompt.includes("oauth") &&
|
|
346
|
+
!lowerPrompt.includes("session")
|
|
347
|
+
) {
|
|
348
|
+
missing.push("authentication method (JWT, OAuth, session, etc.)");
|
|
349
|
+
}
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
if (domain === "database") {
|
|
353
|
+
if (
|
|
354
|
+
!lowerPrompt.includes("sql") &&
|
|
355
|
+
!lowerPrompt.includes("mysql") &&
|
|
356
|
+
!lowerPrompt.includes("postgresql") &&
|
|
357
|
+
!lowerPrompt.includes("mongodb")
|
|
358
|
+
) {
|
|
359
|
+
missing.push("database type");
|
|
360
|
+
}
|
|
361
|
+
if (!lowerPrompt.includes("index")) {
|
|
362
|
+
missing.push("index information");
|
|
363
|
+
}
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
return missing;
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
/**
|
|
370
|
+
* Suggest techniques based on analysis
|
|
371
|
+
*/
|
|
372
|
+
function suggestTechniques(
|
|
373
|
+
complexity: Complexity,
|
|
374
|
+
domain: Domain,
|
|
375
|
+
): TechniqueId[] {
|
|
376
|
+
const techniques: TechniqueId[] = [];
|
|
377
|
+
|
|
378
|
+
// Always start with analysis
|
|
379
|
+
techniques.push("analysis");
|
|
380
|
+
|
|
381
|
+
// Expert persona for medium and complex
|
|
382
|
+
if (complexity === "medium" || complexity === "complex") {
|
|
383
|
+
techniques.push("expert_persona");
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
// Reasoning chain for medium and complex
|
|
387
|
+
if (complexity === "medium" || complexity === "complex") {
|
|
388
|
+
techniques.push("reasoning_chain");
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
// Stakes language for medium and complex
|
|
392
|
+
if (complexity === "medium" || complexity === "complex") {
|
|
393
|
+
techniques.push("stakes_language");
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
// Challenge framing only for complex
|
|
397
|
+
if (complexity === "complex") {
|
|
398
|
+
techniques.push("challenge_framing");
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
// Self-evaluation for medium and complex
|
|
402
|
+
if (complexity === "medium" || complexity === "complex") {
|
|
403
|
+
techniques.push("self_evaluation");
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
return techniques;
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
/**
|
|
410
|
+
* Main analysis function
|
|
411
|
+
*/
|
|
412
|
+
export function analyzePrompt(prompt: string): AnalysisResult {
|
|
413
|
+
// Check for simple patterns first
|
|
414
|
+
if (isSimplePrompt(prompt)) {
|
|
415
|
+
return {
|
|
416
|
+
complexity: "simple",
|
|
417
|
+
domain: "general",
|
|
418
|
+
keywords: [],
|
|
419
|
+
missingContext: [],
|
|
420
|
+
suggestedTechniques: ["analysis"],
|
|
421
|
+
};
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
// Calculate complexity
|
|
425
|
+
const complexityScore = calculateComplexityScore(prompt);
|
|
426
|
+
const complexity = scoreToComplexity(complexityScore);
|
|
427
|
+
|
|
428
|
+
// Detect domain
|
|
429
|
+
const domain = detectDomain(prompt);
|
|
430
|
+
|
|
431
|
+
// Extract keywords
|
|
432
|
+
const keywords = extractKeywords(prompt);
|
|
433
|
+
|
|
434
|
+
// Identify missing context
|
|
435
|
+
const missingContext = identifyMissingContext(prompt, domain);
|
|
436
|
+
|
|
437
|
+
// Suggest techniques
|
|
438
|
+
const suggestedTechniques = suggestTechniques(complexity, domain);
|
|
439
|
+
|
|
440
|
+
return {
|
|
441
|
+
complexity,
|
|
442
|
+
domain,
|
|
443
|
+
keywords,
|
|
444
|
+
missingContext,
|
|
445
|
+
suggestedTechniques,
|
|
446
|
+
};
|
|
447
|
+
}
|
|
@@ -24,8 +24,8 @@ Create a new OpenCode skill using AI assistance.
|
|
|
24
24
|
## Output Location
|
|
25
25
|
|
|
26
26
|
Skill will be saved to:
|
|
27
|
-
- Project-local: `.opencode/
|
|
28
|
-
- Global: `~/.config/opencode/
|
|
27
|
+
- Project-local: `.opencode/skill/[skill-name]/SKILL.md`
|
|
28
|
+
- Global: `~/.config/opencode/skill/[skill-name]/SKILL.md`
|
|
29
29
|
- Ferg content: `content/skills/[skill-name]/SKILL.md`
|
|
30
30
|
|
|
31
31
|
## Examples
|