locus-product-planning 1.0.0 → 1.1.0
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-plugin/marketplace.json +31 -0
- package/.claude-plugin/plugin.json +32 -0
- package/README.md +127 -45
- package/agents/engineering/architect-reviewer.md +122 -0
- package/agents/engineering/engineering-manager.md +101 -0
- package/agents/engineering/principal-engineer.md +98 -0
- package/agents/engineering/staff-engineer.md +86 -0
- package/agents/engineering/tech-lead.md +114 -0
- package/agents/executive/ceo-strategist.md +81 -0
- package/agents/executive/cfo-analyst.md +97 -0
- package/agents/executive/coo-operations.md +100 -0
- package/agents/executive/cpo-product.md +104 -0
- package/agents/executive/cto-architect.md +90 -0
- package/agents/product/product-manager.md +70 -0
- package/agents/product/project-manager.md +95 -0
- package/agents/product/qa-strategist.md +132 -0
- package/agents/product/scrum-master.md +70 -0
- package/dist/index.d.ts +10 -25
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +231 -95
- package/dist/lib/skills-core.d.ts +95 -0
- package/dist/lib/skills-core.d.ts.map +1 -0
- package/dist/lib/skills-core.js +361 -0
- package/hooks/hooks.json +15 -0
- package/hooks/run-hook.cmd +32 -0
- package/hooks/session-start.cmd +13 -0
- package/hooks/session-start.sh +70 -0
- package/opencode.json +11 -7
- package/package.json +18 -4
- package/skills/01-executive-suite/ceo-strategist/SKILL.md +132 -0
- package/skills/01-executive-suite/cfo-analyst/SKILL.md +187 -0
- package/skills/01-executive-suite/coo-operations/SKILL.md +211 -0
- package/skills/01-executive-suite/cpo-product/SKILL.md +231 -0
- package/skills/01-executive-suite/cto-architect/SKILL.md +173 -0
- package/skills/02-product-management/estimation-expert/SKILL.md +139 -0
- package/skills/02-product-management/product-manager/SKILL.md +265 -0
- package/skills/02-product-management/program-manager/SKILL.md +178 -0
- package/skills/02-product-management/project-manager/SKILL.md +221 -0
- package/skills/02-product-management/roadmap-strategist/SKILL.md +186 -0
- package/skills/02-product-management/scrum-master/SKILL.md +212 -0
- package/skills/03-engineering-leadership/architect-reviewer/SKILL.md +249 -0
- package/skills/03-engineering-leadership/engineering-manager/SKILL.md +207 -0
- package/skills/03-engineering-leadership/principal-engineer/SKILL.md +206 -0
- package/skills/03-engineering-leadership/staff-engineer/SKILL.md +237 -0
- package/skills/03-engineering-leadership/tech-lead/SKILL.md +296 -0
- package/skills/04-developer-specializations/core/backend-developer/SKILL.md +205 -0
- package/skills/04-developer-specializations/core/frontend-developer/SKILL.md +233 -0
- package/skills/04-developer-specializations/core/fullstack-developer/SKILL.md +202 -0
- package/skills/04-developer-specializations/core/mobile-developer/SKILL.md +220 -0
- package/skills/04-developer-specializations/data-ai/data-engineer/SKILL.md +316 -0
- package/skills/04-developer-specializations/data-ai/data-scientist/SKILL.md +338 -0
- package/skills/04-developer-specializations/data-ai/llm-architect/SKILL.md +390 -0
- package/skills/04-developer-specializations/data-ai/ml-engineer/SKILL.md +349 -0
- package/skills/04-developer-specializations/infrastructure/cloud-architect/SKILL.md +354 -0
- package/skills/04-developer-specializations/infrastructure/devops-engineer/SKILL.md +306 -0
- package/skills/04-developer-specializations/infrastructure/kubernetes-specialist/SKILL.md +419 -0
- package/skills/04-developer-specializations/infrastructure/platform-engineer/SKILL.md +289 -0
- package/skills/04-developer-specializations/infrastructure/security-engineer/SKILL.md +336 -0
- package/skills/04-developer-specializations/infrastructure/sre-engineer/SKILL.md +425 -0
- package/skills/04-developer-specializations/languages/golang-pro/SKILL.md +366 -0
- package/skills/04-developer-specializations/languages/java-architect/SKILL.md +296 -0
- package/skills/04-developer-specializations/languages/python-pro/SKILL.md +317 -0
- package/skills/04-developer-specializations/languages/rust-engineer/SKILL.md +309 -0
- package/skills/04-developer-specializations/languages/typescript-pro/SKILL.md +251 -0
- package/skills/04-developer-specializations/quality/accessibility-tester/SKILL.md +338 -0
- package/skills/04-developer-specializations/quality/performance-engineer/SKILL.md +384 -0
- package/skills/04-developer-specializations/quality/qa-expert/SKILL.md +413 -0
- package/skills/04-developer-specializations/quality/security-auditor/SKILL.md +359 -0
- package/skills/05-specialists/compliance-specialist/SKILL.md +171 -0
- package/skills/using-locus/SKILL.md +124 -0
- package/.opencode/skills/locus/SKILL.md +0 -299
package/dist/index.js
CHANGED
|
@@ -1,114 +1,250 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Locus - OpenCode Plugin
|
|
3
3
|
*
|
|
4
|
-
* AI-powered project planning
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
* The main skill is auto-discovered from .opencode/skills/locus/SKILL.md
|
|
4
|
+
* AI-powered project planning with skills framework.
|
|
5
|
+
* Provides custom tools for loading and discovering skills,
|
|
6
|
+
* with automatic bootstrap on session start.
|
|
8
7
|
*/
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
8
|
+
import { tool } from "@opencode-ai/plugin/tool";
|
|
9
|
+
import { readFileSync } from "fs";
|
|
10
|
+
import { join, dirname, resolve } from "path";
|
|
11
11
|
import { fileURLToPath } from "url";
|
|
12
|
+
import { homedir } from "os";
|
|
13
|
+
import { findSkillsInDir, findAgentsInDir, resolveSkillPath, extractFrontmatter, stripFrontmatter, getBootstrapContent, normalizePath, } from "./lib/skills-core.js";
|
|
12
14
|
const __filename = fileURLToPath(import.meta.url);
|
|
13
15
|
const __dirname = dirname(__filename);
|
|
14
|
-
// Path to skill file (relative to dist/)
|
|
15
|
-
const SKILL_PATH = join(__dirname, "..", ".opencode", "skills", "locus", "SKILL.md");
|
|
16
|
-
/**
|
|
17
|
-
* Read the Locus skill content
|
|
18
|
-
*/
|
|
19
|
-
function getSkillContent() {
|
|
20
|
-
try {
|
|
21
|
-
return readFileSync(SKILL_PATH, "utf-8");
|
|
22
|
-
}
|
|
23
|
-
catch {
|
|
24
|
-
return "Locus skill not found. Please reinstall opencode-locus.";
|
|
25
|
-
}
|
|
26
|
-
}
|
|
27
16
|
/**
|
|
28
|
-
*
|
|
17
|
+
* Locus Plugin for OpenCode
|
|
18
|
+
*
|
|
19
|
+
* Provides:
|
|
20
|
+
* - use_skill: Load and read a specific skill
|
|
21
|
+
* - find_skills: List all available skills
|
|
22
|
+
* - find_agents: List all available agents
|
|
23
|
+
* - Bootstrap injection on session start
|
|
29
24
|
*/
|
|
30
|
-
|
|
31
|
-
const
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
25
|
+
export const LocusPlugin = async ({ client, directory }) => {
|
|
26
|
+
const homeDir = homedir();
|
|
27
|
+
// Skill directories with priority: project > personal > locus
|
|
28
|
+
const projectSkillsDir = join(directory, '.opencode/skills');
|
|
29
|
+
// Derive locus skills dir from plugin location
|
|
30
|
+
const locusSkillsDir = resolve(__dirname, '..', 'skills');
|
|
31
|
+
// Agents directory
|
|
32
|
+
const locusAgentsDir = resolve(__dirname, '..', 'agents');
|
|
33
|
+
const projectAgentsDir = join(directory, 'agents');
|
|
34
|
+
// Personal skills directory (respect OPENCODE_CONFIG_DIR if set)
|
|
35
|
+
const envConfigDir = normalizePath(process.env.OPENCODE_CONFIG_DIR, homeDir);
|
|
36
|
+
const configDir = envConfigDir || join(homeDir, '.config/opencode');
|
|
37
|
+
const personalSkillsDir = join(configDir, 'skills');
|
|
38
|
+
/**
|
|
39
|
+
* Generate bootstrap content for session injection
|
|
40
|
+
*/
|
|
41
|
+
const generateBootstrap = (compact = false) => {
|
|
42
|
+
return getBootstrapContent(locusSkillsDir, compact);
|
|
43
|
+
};
|
|
44
|
+
/**
|
|
45
|
+
* Inject bootstrap via session.prompt
|
|
46
|
+
*/
|
|
47
|
+
const injectBootstrap = async (sessionID, compact = false) => {
|
|
48
|
+
const bootstrapContent = generateBootstrap(compact);
|
|
49
|
+
if (!bootstrapContent)
|
|
50
|
+
return false;
|
|
51
|
+
try {
|
|
52
|
+
await client.session.prompt({
|
|
53
|
+
path: { id: sessionID },
|
|
54
|
+
body: {
|
|
55
|
+
noReply: true,
|
|
56
|
+
parts: [{ type: "text", text: bootstrapContent, synthetic: true }]
|
|
57
|
+
}
|
|
58
|
+
});
|
|
59
|
+
return true;
|
|
44
60
|
}
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
catch {
|
|
48
|
-
return null;
|
|
49
|
-
}
|
|
50
|
-
}
|
|
51
|
-
/**
|
|
52
|
-
* List all projects in the projects/ directory
|
|
53
|
-
*/
|
|
54
|
-
function listProjects(directory) {
|
|
55
|
-
const projectsDir = join(directory, "projects");
|
|
56
|
-
if (!existsSync(projectsDir))
|
|
57
|
-
return [];
|
|
58
|
-
const projects = [];
|
|
59
|
-
try {
|
|
60
|
-
const entries = readdirSync(projectsDir);
|
|
61
|
-
for (const entry of entries) {
|
|
62
|
-
const entryPath = join(projectsDir, entry);
|
|
63
|
-
const stat = statSync(entryPath);
|
|
64
|
-
if (stat.isDirectory() && !entry.startsWith(".")) {
|
|
65
|
-
projects.push({
|
|
66
|
-
name: entry,
|
|
67
|
-
path: entryPath,
|
|
68
|
-
state: getProjectState(entryPath),
|
|
69
|
-
});
|
|
70
|
-
}
|
|
61
|
+
catch {
|
|
62
|
+
return false;
|
|
71
63
|
}
|
|
72
|
-
}
|
|
73
|
-
catch {
|
|
74
|
-
// Ignore errors
|
|
75
|
-
}
|
|
76
|
-
return projects;
|
|
77
|
-
}
|
|
78
|
-
/**
|
|
79
|
-
* Format project status for display
|
|
80
|
-
*/
|
|
81
|
-
function formatProjectStatus(state, projectName) {
|
|
82
|
-
const steps = ["Vision", "Features", "Design", "Build"];
|
|
83
|
-
if (!state) {
|
|
84
|
-
return `📋 ${projectName}\n━━━━━━━━━━━━━━━━━━\nNo state found. Start with /locus.`;
|
|
85
|
-
}
|
|
86
|
-
const currentStep = Number(state.current_step) || 1;
|
|
87
|
-
let output = `📋 ${state.project || projectName}\n━━━━━━━━━━━━━━━━━━\n`;
|
|
88
|
-
for (let i = 0; i < steps.length; i++) {
|
|
89
|
-
const stepNum = i + 1;
|
|
90
|
-
const prefix = stepNum < currentStep ? "✓" : stepNum === currentStep ? "→" : " ";
|
|
91
|
-
const suffix = stepNum === currentStep ? " ◄ you are here" : "";
|
|
92
|
-
output += `${prefix} Step ${stepNum}: ${steps[i]}${suffix}\n`;
|
|
93
|
-
}
|
|
94
|
-
const progress = Math.round(((currentStep - 1) / 4) * 100);
|
|
95
|
-
output += `\nProgress: ${progress}% complete`;
|
|
96
|
-
return output;
|
|
97
|
-
}
|
|
98
|
-
/**
|
|
99
|
-
* Locus Plugin for OpenCode
|
|
100
|
-
*/
|
|
101
|
-
export const LocusPlugin = async ({ directory }) => {
|
|
64
|
+
};
|
|
102
65
|
return {
|
|
103
|
-
|
|
66
|
+
tool: {
|
|
67
|
+
/**
|
|
68
|
+
* Load and read a specific skill to guide work
|
|
69
|
+
*/
|
|
70
|
+
use_skill: tool({
|
|
71
|
+
description: 'Load and read a specific skill to guide your work. Skills contain proven workflows, mandatory processes, and expert techniques for project planning and development.',
|
|
72
|
+
args: {
|
|
73
|
+
skill_name: tool.schema.string().describe('Name of the skill to load (e.g., "locus:product-manager", "project:my-skill", or "brainstorming")')
|
|
74
|
+
},
|
|
75
|
+
execute: async (args, context) => {
|
|
76
|
+
const { skill_name } = args;
|
|
77
|
+
// Resolve skill with priority: project > personal > locus
|
|
78
|
+
const resolved = resolveSkillPath(skill_name, locusSkillsDir, personalSkillsDir, projectSkillsDir);
|
|
79
|
+
if (!resolved) {
|
|
80
|
+
return `Error: Skill "${skill_name}" not found.\n\nRun find_skills to see available skills.`;
|
|
81
|
+
}
|
|
82
|
+
const fullContent = readFileSync(resolved.skillFile, 'utf-8');
|
|
83
|
+
const { name, description } = extractFrontmatter(resolved.skillFile);
|
|
84
|
+
const content = stripFrontmatter(fullContent);
|
|
85
|
+
const skillDirectory = dirname(resolved.skillFile);
|
|
86
|
+
const skillHeader = `# ${name || skill_name}
|
|
87
|
+
# ${description || ''}
|
|
88
|
+
# Supporting tools and docs are in ${skillDirectory}
|
|
89
|
+
# ============================================`;
|
|
90
|
+
// Insert as user message with noReply for persistence across compaction
|
|
91
|
+
try {
|
|
92
|
+
await client.session.prompt({
|
|
93
|
+
path: { id: context.sessionID },
|
|
94
|
+
body: {
|
|
95
|
+
agent: context.agent,
|
|
96
|
+
noReply: true,
|
|
97
|
+
parts: [
|
|
98
|
+
{ type: "text", text: `Loading skill: ${name || skill_name}`, synthetic: true },
|
|
99
|
+
{ type: "text", text: `${skillHeader}\n\n${content}`, synthetic: true }
|
|
100
|
+
]
|
|
101
|
+
}
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
catch {
|
|
105
|
+
// Fallback: return content directly if message insertion fails
|
|
106
|
+
return `${skillHeader}\n\n${content}`;
|
|
107
|
+
}
|
|
108
|
+
return `Launching skill: ${name || skill_name}`;
|
|
109
|
+
}
|
|
110
|
+
}),
|
|
111
|
+
/**
|
|
112
|
+
* List all available skills with optional filtering
|
|
113
|
+
*/
|
|
114
|
+
find_skills: tool({
|
|
115
|
+
description: 'List all available skills. Filter by category (e.g., "core", "infrastructure"), tier (e.g., "executive", "developer-specialization"), or search term.',
|
|
116
|
+
args: {
|
|
117
|
+
category: tool.schema.string().optional().describe('Filter by category (e.g., "core", "infrastructure", "data-ai", "quality", "languages")'),
|
|
118
|
+
tier: tool.schema.string().optional().describe('Filter by tier (e.g., "executive", "product-management", "engineering-leadership", "developer-specialization")'),
|
|
119
|
+
search: tool.schema.string().optional().describe('Search term to filter skills by name or description'),
|
|
120
|
+
},
|
|
121
|
+
execute: async (args) => {
|
|
122
|
+
const { category, tier, search } = args;
|
|
123
|
+
const projectSkills = findSkillsInDir(projectSkillsDir, 'project', 4);
|
|
124
|
+
const personalSkills = findSkillsInDir(personalSkillsDir, 'personal', 4);
|
|
125
|
+
const locusSkills = findSkillsInDir(locusSkillsDir, 'locus', 4);
|
|
126
|
+
let allSkills = [...projectSkills, ...personalSkills, ...locusSkills];
|
|
127
|
+
// Apply filters
|
|
128
|
+
if (category) {
|
|
129
|
+
const categoryLower = category.toLowerCase();
|
|
130
|
+
allSkills = allSkills.filter(s => s.category?.toLowerCase().includes(categoryLower) ||
|
|
131
|
+
s.path.toLowerCase().includes(categoryLower));
|
|
132
|
+
}
|
|
133
|
+
if (tier) {
|
|
134
|
+
const tierLower = tier.toLowerCase();
|
|
135
|
+
allSkills = allSkills.filter(s => s.tier?.toLowerCase().includes(tierLower) ||
|
|
136
|
+
s.path.toLowerCase().includes(tierLower));
|
|
137
|
+
}
|
|
138
|
+
if (search) {
|
|
139
|
+
const searchLower = search.toLowerCase();
|
|
140
|
+
allSkills = allSkills.filter(s => s.name.toLowerCase().includes(searchLower) ||
|
|
141
|
+
s.description.toLowerCase().includes(searchLower));
|
|
142
|
+
}
|
|
143
|
+
if (allSkills.length === 0) {
|
|
144
|
+
const filterDesc = [category && `category="${category}"`, tier && `tier="${tier}"`, search && `search="${search}"`]
|
|
145
|
+
.filter(Boolean).join(', ');
|
|
146
|
+
return filterDesc
|
|
147
|
+
? `No skills found matching: ${filterDesc}\n\nTry find_skills without filters to see all available skills.`
|
|
148
|
+
: `No skills found.\n\nInstall locus skills or add personal skills to ${personalSkillsDir}/`;
|
|
149
|
+
}
|
|
150
|
+
let output = `Found ${allSkills.length} skill(s):\n\n`;
|
|
151
|
+
// Group by source type
|
|
152
|
+
const grouped = {
|
|
153
|
+
project: allSkills.filter(s => s.sourceType === 'project'),
|
|
154
|
+
personal: allSkills.filter(s => s.sourceType === 'personal'),
|
|
155
|
+
locus: allSkills.filter(s => s.sourceType === 'locus'),
|
|
156
|
+
};
|
|
157
|
+
for (const [sourceType, skills] of Object.entries(grouped)) {
|
|
158
|
+
if (skills.length === 0)
|
|
159
|
+
continue;
|
|
160
|
+
output += `## ${sourceType.charAt(0).toUpperCase() + sourceType.slice(1)} Skills\n\n`;
|
|
161
|
+
for (const skill of skills) {
|
|
162
|
+
const namespace = sourceType === 'personal' ? '' : `${sourceType}:`;
|
|
163
|
+
output += `**${namespace}${skill.name}**`;
|
|
164
|
+
if (skill.tier || skill.category) {
|
|
165
|
+
output += ` [${[skill.tier, skill.category].filter(Boolean).join('/')}]`;
|
|
166
|
+
}
|
|
167
|
+
output += '\n';
|
|
168
|
+
if (skill.description) {
|
|
169
|
+
output += ` ${skill.description}\n`;
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
output += '\n';
|
|
173
|
+
}
|
|
174
|
+
return output;
|
|
175
|
+
}
|
|
176
|
+
}),
|
|
177
|
+
/**
|
|
178
|
+
* List all available agents
|
|
179
|
+
*/
|
|
180
|
+
find_agents: tool({
|
|
181
|
+
description: 'List all available agent definitions for specialized tasks.',
|
|
182
|
+
args: {},
|
|
183
|
+
execute: async () => {
|
|
184
|
+
const locusAgents = findAgentsInDir(locusAgentsDir, 3);
|
|
185
|
+
const projectAgents = findAgentsInDir(projectAgentsDir, 3);
|
|
186
|
+
const allAgents = [...projectAgents, ...locusAgents];
|
|
187
|
+
if (allAgents.length === 0) {
|
|
188
|
+
return 'No agents found.';
|
|
189
|
+
}
|
|
190
|
+
let output = 'Available agents:\n\n';
|
|
191
|
+
// Group by category
|
|
192
|
+
const byCategory = new Map();
|
|
193
|
+
for (const agent of allAgents) {
|
|
194
|
+
const cat = agent.category || 'general';
|
|
195
|
+
if (!byCategory.has(cat)) {
|
|
196
|
+
byCategory.set(cat, []);
|
|
197
|
+
}
|
|
198
|
+
byCategory.get(cat).push(agent);
|
|
199
|
+
}
|
|
200
|
+
for (const [category, agents] of byCategory) {
|
|
201
|
+
output += `## ${category.charAt(0).toUpperCase() + category.slice(1)}\n\n`;
|
|
202
|
+
for (const agent of agents) {
|
|
203
|
+
output += `**${agent.name}**\n`;
|
|
204
|
+
if (agent.description) {
|
|
205
|
+
// Truncate long descriptions
|
|
206
|
+
const desc = agent.description.length > 200
|
|
207
|
+
? agent.description.substring(0, 200) + '...'
|
|
208
|
+
: agent.description;
|
|
209
|
+
output += ` ${desc}\n`;
|
|
210
|
+
}
|
|
211
|
+
output += ` Path: ${agent.path}\n\n`;
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
return output;
|
|
215
|
+
}
|
|
216
|
+
}),
|
|
217
|
+
},
|
|
218
|
+
/**
|
|
219
|
+
* Event handlers for session lifecycle
|
|
220
|
+
*/
|
|
104
221
|
event: async ({ event }) => {
|
|
105
|
-
|
|
106
|
-
|
|
222
|
+
// Extract sessionID from various event structures
|
|
223
|
+
const getSessionID = () => {
|
|
224
|
+
const props = event.properties;
|
|
225
|
+
const session = event.session;
|
|
226
|
+
return props?.info?.id ||
|
|
227
|
+
props?.sessionID ||
|
|
228
|
+
session?.id;
|
|
229
|
+
};
|
|
230
|
+
// Inject bootstrap at session creation (before first user message)
|
|
231
|
+
if (event.type === 'session.created') {
|
|
232
|
+
const sessionID = getSessionID();
|
|
233
|
+
if (sessionID) {
|
|
234
|
+
await injectBootstrap(sessionID, false);
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
// Re-inject bootstrap after context compaction (compact version to save tokens)
|
|
238
|
+
if (event.type === 'session.compacted') {
|
|
239
|
+
const sessionID = getSessionID();
|
|
240
|
+
if (sessionID) {
|
|
241
|
+
await injectBootstrap(sessionID, true);
|
|
242
|
+
}
|
|
107
243
|
}
|
|
108
244
|
},
|
|
109
245
|
};
|
|
110
246
|
};
|
|
111
247
|
// Default export for OpenCode plugin loading
|
|
112
248
|
export default LocusPlugin;
|
|
113
|
-
//
|
|
114
|
-
export
|
|
249
|
+
// Re-export utilities for programmatic use
|
|
250
|
+
export * from "./lib/skills-core.js";
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Skills Core Library
|
|
3
|
+
* Shared utilities for skill discovery, loading, and management
|
|
4
|
+
*/
|
|
5
|
+
export interface SkillMetadata {
|
|
6
|
+
name: string;
|
|
7
|
+
description: string;
|
|
8
|
+
license?: string;
|
|
9
|
+
version?: string;
|
|
10
|
+
author?: string;
|
|
11
|
+
category?: string;
|
|
12
|
+
tier?: string;
|
|
13
|
+
council?: string;
|
|
14
|
+
tools?: string;
|
|
15
|
+
metadata?: {
|
|
16
|
+
version?: string;
|
|
17
|
+
tier?: string;
|
|
18
|
+
category?: string;
|
|
19
|
+
council?: string;
|
|
20
|
+
[key: string]: string | undefined;
|
|
21
|
+
};
|
|
22
|
+
[key: string]: string | Record<string, string | undefined> | undefined;
|
|
23
|
+
}
|
|
24
|
+
export interface SkillInfo {
|
|
25
|
+
path: string;
|
|
26
|
+
skillFile: string;
|
|
27
|
+
name: string;
|
|
28
|
+
description: string;
|
|
29
|
+
sourceType: 'project' | 'personal' | 'locus';
|
|
30
|
+
tier?: string;
|
|
31
|
+
category?: string;
|
|
32
|
+
council?: string;
|
|
33
|
+
version?: string;
|
|
34
|
+
}
|
|
35
|
+
export interface AgentInfo {
|
|
36
|
+
path: string;
|
|
37
|
+
name: string;
|
|
38
|
+
description: string;
|
|
39
|
+
model?: string;
|
|
40
|
+
category: string;
|
|
41
|
+
}
|
|
42
|
+
export interface ResolvedSkill {
|
|
43
|
+
skillFile: string;
|
|
44
|
+
sourceType: 'project' | 'personal' | 'locus';
|
|
45
|
+
skillPath: string;
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Extract YAML frontmatter from a skill or agent file.
|
|
49
|
+
*
|
|
50
|
+
* Supports:
|
|
51
|
+
* - Simple key: value pairs
|
|
52
|
+
* - Multiline values with |
|
|
53
|
+
* - Nested objects (one level deep, e.g., metadata:)
|
|
54
|
+
*
|
|
55
|
+
* Format:
|
|
56
|
+
* ---
|
|
57
|
+
* name: skill-name
|
|
58
|
+
* description: Use when [condition] - [what it does]
|
|
59
|
+
* metadata:
|
|
60
|
+
* version: "1.0.0"
|
|
61
|
+
* tier: developer
|
|
62
|
+
* ---
|
|
63
|
+
*/
|
|
64
|
+
export declare function extractFrontmatter(filePath: string): SkillMetadata;
|
|
65
|
+
/**
|
|
66
|
+
* Strip YAML frontmatter from content, returning just the body.
|
|
67
|
+
*/
|
|
68
|
+
export declare function stripFrontmatter(content: string): string;
|
|
69
|
+
/**
|
|
70
|
+
* Find all SKILL.md files in a directory recursively.
|
|
71
|
+
*/
|
|
72
|
+
export declare function findSkillsInDir(dir: string, sourceType: 'project' | 'personal' | 'locus', maxDepth?: number): SkillInfo[];
|
|
73
|
+
/**
|
|
74
|
+
* Find all agent definition files in a directory.
|
|
75
|
+
*/
|
|
76
|
+
export declare function findAgentsInDir(dir: string, maxDepth?: number): AgentInfo[];
|
|
77
|
+
/**
|
|
78
|
+
* Resolve a skill name to its file path, handling namespacing and shadowing.
|
|
79
|
+
* Priority: project > personal > locus
|
|
80
|
+
*
|
|
81
|
+
* Skill names can be:
|
|
82
|
+
* - "skill-name" - searches all locations
|
|
83
|
+
* - "project:skill-name" - forces project skills only
|
|
84
|
+
* - "locus:skill-name" - forces locus skills only
|
|
85
|
+
*/
|
|
86
|
+
export declare function resolveSkillPath(skillName: string, locusSkillsDir: string, personalSkillsDir: string | null, projectSkillsDir: string | null): ResolvedSkill | null;
|
|
87
|
+
/**
|
|
88
|
+
* Get the using-locus bootstrap skill content.
|
|
89
|
+
*/
|
|
90
|
+
export declare function getBootstrapContent(locusSkillsDir: string, compact?: boolean): string | null;
|
|
91
|
+
/**
|
|
92
|
+
* Normalize a path: trim whitespace, expand ~, resolve to absolute.
|
|
93
|
+
*/
|
|
94
|
+
export declare function normalizePath(p: string | undefined, homeDir: string): string | null;
|
|
95
|
+
//# sourceMappingURL=skills-core.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"skills-core.d.ts","sourceRoot":"","sources":["../../src/lib/skills-core.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAKH,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE;QACT,OAAO,CAAC,EAAE,MAAM,CAAC;QACjB,IAAI,CAAC,EAAE,MAAM,CAAC;QACd,QAAQ,CAAC,EAAE,MAAM,CAAC;QAClB,OAAO,CAAC,EAAE,MAAM,CAAC;QACjB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAAC;KACnC,CAAC;IACF,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,GAAG,SAAS,CAAC;CACxE;AAED,MAAM,WAAW,SAAS;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,SAAS,GAAG,UAAU,GAAG,OAAO,CAAC;IAC7C,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,SAAS;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,aAAa;IAC5B,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,SAAS,GAAG,UAAU,GAAG,OAAO,CAAC;IAC7C,SAAS,EAAE,MAAM,CAAC;CACnB;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,kBAAkB,CAAC,QAAQ,EAAE,MAAM,GAAG,aAAa,CA2GlE;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAsBxD;AAED;;GAEG;AACH,wBAAgB,eAAe,CAC7B,GAAG,EAAE,MAAM,EACX,UAAU,EAAE,SAAS,GAAG,UAAU,GAAG,OAAO,EAC5C,QAAQ,SAAI,GACX,SAAS,EAAE,CA8Cb;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,GAAG,EAAE,MAAM,EAAE,QAAQ,SAAI,GAAG,SAAS,EAAE,CAuCtE;AAED;;;;;;;;GAQG;AACH,wBAAgB,gBAAgB,CAC9B,SAAS,EAAE,MAAM,EACjB,cAAc,EAAE,MAAM,EACtB,iBAAiB,EAAE,MAAM,GAAG,IAAI,EAChC,gBAAgB,EAAE,MAAM,GAAG,IAAI,GAC9B,aAAa,GAAG,IAAI,CA4BtB;AAsCD;;GAEG;AACH,wBAAgB,mBAAmB,CACjC,cAAc,EAAE,MAAM,EACtB,OAAO,UAAQ,GACd,MAAM,GAAG,IAAI,CA2Cf;AAED;;GAEG;AACH,wBAAgB,aAAa,CAAC,CAAC,EAAE,MAAM,GAAG,SAAS,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAanF"}
|