@fro.bot/systematic 1.0.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.
Files changed (73) hide show
  1. package/README.md +158 -0
  2. package/agents/research/framework-docs-researcher.md +19 -0
  3. package/agents/review/architecture-strategist.md +23 -0
  4. package/agents/review/code-simplicity-reviewer.md +30 -0
  5. package/agents/review/pattern-recognition-specialist.md +24 -0
  6. package/agents/review/performance-oracle.md +25 -0
  7. package/agents/review/security-sentinel.md +25 -0
  8. package/commands/agent-native-audit.md +277 -0
  9. package/commands/create-agent-skill.md +8 -0
  10. package/commands/deepen-plan.md +546 -0
  11. package/commands/lfg.md +19 -0
  12. package/commands/workflows/brainstorm.md +115 -0
  13. package/commands/workflows/compound.md +202 -0
  14. package/commands/workflows/plan.md +551 -0
  15. package/commands/workflows/review.md +514 -0
  16. package/commands/workflows/work.md +363 -0
  17. package/dist/cli.js +360 -0
  18. package/dist/index-v8dhd5s2.js +194 -0
  19. package/dist/index.js +297 -0
  20. package/package.json +69 -0
  21. package/skills/agent-browser/SKILL.md +223 -0
  22. package/skills/agent-native-architecture/SKILL.md +435 -0
  23. package/skills/agent-native-architecture/references/action-parity-discipline.md +409 -0
  24. package/skills/agent-native-architecture/references/agent-execution-patterns.md +467 -0
  25. package/skills/agent-native-architecture/references/agent-native-testing.md +582 -0
  26. package/skills/agent-native-architecture/references/architecture-patterns.md +478 -0
  27. package/skills/agent-native-architecture/references/dynamic-context-injection.md +338 -0
  28. package/skills/agent-native-architecture/references/files-universal-interface.md +301 -0
  29. package/skills/agent-native-architecture/references/from-primitives-to-domain-tools.md +359 -0
  30. package/skills/agent-native-architecture/references/mcp-tool-design.md +506 -0
  31. package/skills/agent-native-architecture/references/mobile-patterns.md +871 -0
  32. package/skills/agent-native-architecture/references/product-implications.md +443 -0
  33. package/skills/agent-native-architecture/references/refactoring-to-prompt-native.md +317 -0
  34. package/skills/agent-native-architecture/references/self-modification.md +269 -0
  35. package/skills/agent-native-architecture/references/shared-workspace-architecture.md +680 -0
  36. package/skills/agent-native-architecture/references/system-prompt-design.md +250 -0
  37. package/skills/brainstorming/SKILL.md +190 -0
  38. package/skills/compound-docs/SKILL.md +510 -0
  39. package/skills/compound-docs/assets/critical-pattern-template.md +34 -0
  40. package/skills/compound-docs/assets/resolution-template.md +93 -0
  41. package/skills/compound-docs/references/yaml-schema.md +65 -0
  42. package/skills/compound-docs/schema.yaml +176 -0
  43. package/skills/create-agent-skills/SKILL.md +299 -0
  44. package/skills/create-agent-skills/references/api-security.md +226 -0
  45. package/skills/create-agent-skills/references/be-clear-and-direct.md +531 -0
  46. package/skills/create-agent-skills/references/best-practices.md +404 -0
  47. package/skills/create-agent-skills/references/common-patterns.md +595 -0
  48. package/skills/create-agent-skills/references/core-principles.md +437 -0
  49. package/skills/create-agent-skills/references/executable-code.md +175 -0
  50. package/skills/create-agent-skills/references/iteration-and-testing.md +474 -0
  51. package/skills/create-agent-skills/references/official-spec.md +185 -0
  52. package/skills/create-agent-skills/references/recommended-structure.md +168 -0
  53. package/skills/create-agent-skills/references/skill-structure.md +372 -0
  54. package/skills/create-agent-skills/references/using-scripts.md +113 -0
  55. package/skills/create-agent-skills/references/using-templates.md +112 -0
  56. package/skills/create-agent-skills/references/workflows-and-validation.md +510 -0
  57. package/skills/create-agent-skills/templates/router-skill.md +73 -0
  58. package/skills/create-agent-skills/templates/simple-skill.md +33 -0
  59. package/skills/create-agent-skills/workflows/add-reference.md +96 -0
  60. package/skills/create-agent-skills/workflows/add-script.md +93 -0
  61. package/skills/create-agent-skills/workflows/add-template.md +74 -0
  62. package/skills/create-agent-skills/workflows/add-workflow.md +120 -0
  63. package/skills/create-agent-skills/workflows/audit-skill.md +138 -0
  64. package/skills/create-agent-skills/workflows/create-domain-expertise-skill.md +605 -0
  65. package/skills/create-agent-skills/workflows/create-new-skill.md +191 -0
  66. package/skills/create-agent-skills/workflows/get-guidance.md +121 -0
  67. package/skills/create-agent-skills/workflows/upgrade-to-router.md +161 -0
  68. package/skills/create-agent-skills/workflows/verify-skill.md +204 -0
  69. package/skills/file-todos/SKILL.md +251 -0
  70. package/skills/file-todos/assets/todo-template.md +155 -0
  71. package/skills/git-worktree/SKILL.md +302 -0
  72. package/skills/git-worktree/scripts/worktree-manager.sh +345 -0
  73. package/skills/using-systematic/SKILL.md +94 -0
package/dist/cli.js ADDED
@@ -0,0 +1,360 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ findAgentsInDir,
4
+ findCommandsInDir,
5
+ findSkillsInDir
6
+ } from "./index-v8dhd5s2.js";
7
+
8
+ // src/cli.ts
9
+ import fs2 from "node:fs";
10
+ import path2 from "node:path";
11
+
12
+ // src/lib/converter.ts
13
+ import fs from "node:fs";
14
+ import path from "node:path";
15
+ function parseFrontmatter(raw) {
16
+ const lines = raw.split(/\r?\n/);
17
+ if (lines.length === 0 || lines[0].trim() !== "---") {
18
+ return { data: {}, body: raw };
19
+ }
20
+ let endIndex = -1;
21
+ for (let i = 1;i < lines.length; i++) {
22
+ if (lines[i].trim() === "---") {
23
+ endIndex = i;
24
+ break;
25
+ }
26
+ }
27
+ if (endIndex === -1) {
28
+ return { data: {}, body: raw };
29
+ }
30
+ const yamlLines = lines.slice(1, endIndex);
31
+ const body = lines.slice(endIndex + 1).join(`
32
+ `);
33
+ const data = {};
34
+ for (const line of yamlLines) {
35
+ const match = line.match(/^(\w+):\s*(.*)$/);
36
+ if (match) {
37
+ const [, key, value] = match;
38
+ if (value === "true")
39
+ data[key] = true;
40
+ else if (value === "false")
41
+ data[key] = false;
42
+ else if (/^\d+(\.\d+)?$/.test(value))
43
+ data[key] = parseFloat(value);
44
+ else
45
+ data[key] = value;
46
+ }
47
+ }
48
+ return { data, body };
49
+ }
50
+ function formatFrontmatter(data, body) {
51
+ const lines = [];
52
+ if (data.description)
53
+ lines.push(`description: ${data.description}`);
54
+ if (data.mode)
55
+ lines.push(`mode: ${data.mode}`);
56
+ if (data.model)
57
+ lines.push(`model: ${data.model}`);
58
+ if (data.temperature !== undefined)
59
+ lines.push(`temperature: ${data.temperature}`);
60
+ if (lines.length === 0)
61
+ return body;
62
+ return ["---", ...lines, "---", "", body].join(`
63
+ `);
64
+ }
65
+ function inferTemperature(name, description) {
66
+ const sample = `${name} ${description || ""}`.toLowerCase();
67
+ if (/(review|audit|security|sentinel|oracle|lint|verification|guardian)/.test(sample)) {
68
+ return 0.1;
69
+ }
70
+ if (/(plan|planning|architecture|strategist|analysis|research)/.test(sample)) {
71
+ return 0.2;
72
+ }
73
+ if (/(doc|readme|changelog|editor|writer)/.test(sample)) {
74
+ return 0.3;
75
+ }
76
+ if (/(brainstorm|creative|ideate|design|concept)/.test(sample)) {
77
+ return 0.6;
78
+ }
79
+ return 0.3;
80
+ }
81
+ function normalizeModel(model) {
82
+ if (model.includes("/"))
83
+ return model;
84
+ if (/^claude-/.test(model))
85
+ return `anthropic/${model}`;
86
+ if (/^(gpt-|o1-|o3-)/.test(model))
87
+ return `openai/${model}`;
88
+ if (/^gemini-/.test(model))
89
+ return `google/${model}`;
90
+ return `anthropic/${model}`;
91
+ }
92
+ function convertAgent(sourcePath, options = {}) {
93
+ const content = fs.readFileSync(sourcePath, "utf-8");
94
+ const name = path.basename(sourcePath, ".md");
95
+ const { data, body } = parseFrontmatter(content);
96
+ const existingDescription = data.description;
97
+ const existingModel = data.model;
98
+ let description = existingDescription;
99
+ if (!description) {
100
+ const firstLine = body.split(`
101
+ `).find((l) => l.trim() && !l.startsWith("#"));
102
+ description = firstLine?.slice(0, 100) || `${name} agent`;
103
+ }
104
+ const frontmatter = {
105
+ description,
106
+ mode: "subagent",
107
+ temperature: inferTemperature(name, description)
108
+ };
109
+ if (existingModel && existingModel !== "inherit") {
110
+ frontmatter.model = normalizeModel(existingModel);
111
+ }
112
+ const converted = formatFrontmatter(frontmatter, body.trim());
113
+ const outputPath = options.output || sourcePath;
114
+ if (!options.dryRun) {
115
+ fs.mkdirSync(path.dirname(outputPath), { recursive: true });
116
+ fs.writeFileSync(outputPath, converted);
117
+ }
118
+ return {
119
+ type: "agent",
120
+ sourcePath,
121
+ outputPath,
122
+ converted: true,
123
+ files: [path.basename(outputPath)]
124
+ };
125
+ }
126
+ function convertCommand(sourcePath, options = {}) {
127
+ const content = fs.readFileSync(sourcePath, "utf-8");
128
+ const outputPath = options.output || sourcePath;
129
+ if (!options.dryRun) {
130
+ fs.mkdirSync(path.dirname(outputPath), { recursive: true });
131
+ fs.writeFileSync(outputPath, content);
132
+ }
133
+ return {
134
+ type: "command",
135
+ sourcePath,
136
+ outputPath,
137
+ converted: true,
138
+ files: [path.basename(outputPath)]
139
+ };
140
+ }
141
+ function convertSkill(sourcePath, options = {}) {
142
+ const stats = fs.statSync(sourcePath);
143
+ if (!stats.isDirectory()) {
144
+ throw new Error(`Skill source must be a directory: ${sourcePath}`);
145
+ }
146
+ const skillName = path.basename(sourcePath);
147
+ const outputPath = options.output || sourcePath;
148
+ const files = [];
149
+ function copyDir(src, dest) {
150
+ if (!options.dryRun) {
151
+ fs.mkdirSync(dest, { recursive: true });
152
+ }
153
+ for (const entry of fs.readdirSync(src, { withFileTypes: true })) {
154
+ const srcPath = path.join(src, entry.name);
155
+ const destPath = path.join(dest, entry.name);
156
+ if (entry.isDirectory()) {
157
+ copyDir(srcPath, destPath);
158
+ } else {
159
+ files.push(path.relative(outputPath, destPath));
160
+ if (!options.dryRun) {
161
+ fs.copyFileSync(srcPath, destPath);
162
+ }
163
+ }
164
+ }
165
+ }
166
+ copyDir(sourcePath, outputPath);
167
+ return {
168
+ type: "skill",
169
+ sourcePath,
170
+ outputPath,
171
+ converted: true,
172
+ files
173
+ };
174
+ }
175
+ function convert(type, sourcePath, options = {}) {
176
+ switch (type) {
177
+ case "agent":
178
+ return convertAgent(sourcePath, options);
179
+ case "command":
180
+ return convertCommand(sourcePath, options);
181
+ case "skill":
182
+ return convertSkill(sourcePath, options);
183
+ default:
184
+ throw new Error(`Unknown type: ${type}`);
185
+ }
186
+ }
187
+
188
+ // src/cli.ts
189
+ var VERSION = "0.1.0";
190
+ var HELP = `
191
+ systematic - OpenCode plugin for systematic engineering workflows
192
+
193
+ Usage:
194
+ systematic <command> [options]
195
+
196
+ Commands:
197
+ list [type] List available skills, agents, or commands
198
+ convert <type> <source> [--output <path>] [--dry-run]
199
+ Convert Claude Code content to OpenCode format
200
+ Types: skill, agent, command
201
+ config [subcommand] Configuration management
202
+ show Show configuration
203
+ path Print config file locations
204
+
205
+ Options:
206
+ --output, -o Output path for convert command
207
+ --dry-run Preview conversion without writing files
208
+ -h, --help Show this help message
209
+ -v, --version Show version
210
+
211
+ Examples:
212
+ systematic list skills
213
+ systematic convert skill /path/to/cep/skills/agent-browser -o ./skills/agent-browser
214
+ systematic convert agent /path/to/agent.md --dry-run
215
+ `;
216
+ function getUserConfigDir() {
217
+ return path2.join(process.env.HOME || process.env.USERPROFILE || ".", ".config/opencode");
218
+ }
219
+ function getProjectConfigDir() {
220
+ return path2.join(process.cwd(), ".opencode");
221
+ }
222
+ function listItems(type) {
223
+ const packageRoot = path2.resolve(import.meta.dirname, "..");
224
+ const bundledDir = packageRoot;
225
+ let finder;
226
+ let subdir;
227
+ switch (type) {
228
+ case "skills":
229
+ finder = findSkillsInDir;
230
+ subdir = "skills";
231
+ break;
232
+ case "agents":
233
+ finder = findAgentsInDir;
234
+ subdir = "agents";
235
+ break;
236
+ case "commands":
237
+ finder = findCommandsInDir;
238
+ subdir = "commands";
239
+ break;
240
+ default:
241
+ console.error(`Unknown type: ${type}. Use: skills, agents, commands`);
242
+ process.exit(1);
243
+ }
244
+ const items = finder(path2.join(bundledDir, subdir), "bundled");
245
+ if (items.length === 0) {
246
+ console.log(`No ${type} found.`);
247
+ return;
248
+ }
249
+ console.log(`Available ${type}:
250
+ `);
251
+ for (const item of items.sort((a, b) => a.name.localeCompare(b.name))) {
252
+ console.log(` ${item.name} (${item.sourceType})`);
253
+ }
254
+ }
255
+ function configShow() {
256
+ const userDir = getUserConfigDir();
257
+ const projectDir = getProjectConfigDir();
258
+ console.log(`Configuration locations:
259
+ `);
260
+ console.log(` User config: ${path2.join(userDir, "systematic.json")}`);
261
+ console.log(` Project config: ${path2.join(projectDir, "systematic.json")}`);
262
+ const projectConfig = path2.join(projectDir, "systematic.json");
263
+ if (fs2.existsSync(projectConfig)) {
264
+ console.log(`
265
+ Project configuration:`);
266
+ console.log(fs2.readFileSync(projectConfig, "utf-8"));
267
+ }
268
+ const userConfig = path2.join(userDir, "systematic.json");
269
+ if (fs2.existsSync(userConfig)) {
270
+ console.log(`
271
+ User configuration:`);
272
+ console.log(fs2.readFileSync(userConfig, "utf-8"));
273
+ }
274
+ }
275
+ function configPath() {
276
+ const userDir = getUserConfigDir();
277
+ const projectDir = getProjectConfigDir();
278
+ console.log("Config file paths:");
279
+ console.log(` User: ${path2.join(userDir, "systematic.json")}`);
280
+ console.log(` Project: ${path2.join(projectDir, "systematic.json")}`);
281
+ }
282
+ function runConvert(args) {
283
+ const typeArg = args[1];
284
+ const sourceArg = args[2];
285
+ if (!typeArg || !sourceArg) {
286
+ console.error("Usage: systematic convert <type> <source> [--output <path>] [--dry-run]");
287
+ console.error("Types: skill, agent, command");
288
+ process.exit(1);
289
+ }
290
+ const validTypes = ["skill", "agent", "command"];
291
+ if (!validTypes.includes(typeArg)) {
292
+ console.error(`Invalid type: ${typeArg}. Must be one of: ${validTypes.join(", ")}`);
293
+ process.exit(1);
294
+ }
295
+ const sourcePath = path2.resolve(sourceArg);
296
+ if (!fs2.existsSync(sourcePath)) {
297
+ console.error(`Source not found: ${sourcePath}`);
298
+ process.exit(1);
299
+ }
300
+ const outputIndex = args.findIndex((a) => a === "--output" || a === "-o");
301
+ const outputPath = outputIndex !== -1 ? path2.resolve(args[outputIndex + 1]) : undefined;
302
+ const dryRun = args.includes("--dry-run");
303
+ try {
304
+ const result = convert(typeArg, sourcePath, { output: outputPath, dryRun });
305
+ if (dryRun) {
306
+ console.log(`[DRY RUN] Would convert ${result.type}:`);
307
+ } else {
308
+ console.log(`Converted ${result.type}:`);
309
+ }
310
+ console.log(` Source: ${result.sourcePath}`);
311
+ console.log(` Output: ${result.outputPath}`);
312
+ console.log(" Files:");
313
+ for (const file of result.files) {
314
+ console.log(` - ${file}`);
315
+ }
316
+ } catch (err) {
317
+ console.error(`Conversion failed: ${err.message}`);
318
+ process.exit(1);
319
+ }
320
+ }
321
+ var args = process.argv.slice(2);
322
+ var command = args[0];
323
+ switch (command) {
324
+ case "list":
325
+ listItems(args[1] || "skills");
326
+ break;
327
+ case "convert":
328
+ runConvert(args);
329
+ break;
330
+ case "config":
331
+ switch (args[1]) {
332
+ case "show":
333
+ case undefined:
334
+ configShow();
335
+ break;
336
+ case "path":
337
+ configPath();
338
+ break;
339
+ default:
340
+ console.error(`Unknown config subcommand: ${args[1]}`);
341
+ console.log("Available: show, path");
342
+ process.exit(1);
343
+ }
344
+ break;
345
+ case "version":
346
+ case "--version":
347
+ case "-v":
348
+ console.log(`systematic v${VERSION}`);
349
+ break;
350
+ case "help":
351
+ case "--help":
352
+ case "-h":
353
+ case undefined:
354
+ console.log(HELP);
355
+ break;
356
+ default:
357
+ console.error(`Unknown command: ${command}`);
358
+ console.log(HELP);
359
+ process.exit(1);
360
+ }
@@ -0,0 +1,194 @@
1
+ // src/lib/skills-core.ts
2
+ import fs from "node:fs";
3
+ import path from "node:path";
4
+ function extractFrontmatter(filePath) {
5
+ try {
6
+ const content = fs.readFileSync(filePath, "utf8");
7
+ const lines = content.split(`
8
+ `);
9
+ let inFrontmatter = false;
10
+ let name = "";
11
+ let description = "";
12
+ for (const line of lines) {
13
+ if (line.trim() === "---") {
14
+ if (inFrontmatter)
15
+ break;
16
+ inFrontmatter = true;
17
+ continue;
18
+ }
19
+ if (inFrontmatter) {
20
+ const match = line.match(/^(\w+):\s*(.*)$/);
21
+ if (match) {
22
+ const [, key, value] = match;
23
+ if (key === "name")
24
+ name = value.trim();
25
+ if (key === "description")
26
+ description = value.trim();
27
+ }
28
+ }
29
+ }
30
+ return { name, description };
31
+ } catch {
32
+ return { name: "", description: "" };
33
+ }
34
+ }
35
+ function stripFrontmatter(content) {
36
+ const lines = content.split(`
37
+ `);
38
+ let inFrontmatter = false;
39
+ let frontmatterEnded = false;
40
+ const contentLines = [];
41
+ for (const line of lines) {
42
+ if (line.trim() === "---") {
43
+ if (inFrontmatter) {
44
+ frontmatterEnded = true;
45
+ continue;
46
+ }
47
+ inFrontmatter = true;
48
+ continue;
49
+ }
50
+ if (frontmatterEnded || !inFrontmatter) {
51
+ contentLines.push(line);
52
+ }
53
+ }
54
+ return contentLines.join(`
55
+ `).trim();
56
+ }
57
+ function findSkillsInDir(dir, sourceType, maxDepth = 3) {
58
+ const skills = [];
59
+ if (!fs.existsSync(dir))
60
+ return skills;
61
+ function recurse(currentDir, depth) {
62
+ if (depth > maxDepth)
63
+ return;
64
+ const entries = fs.readdirSync(currentDir, { withFileTypes: true });
65
+ for (const entry of entries) {
66
+ const fullPath = path.join(currentDir, entry.name);
67
+ if (entry.isDirectory()) {
68
+ const skillFile = path.join(fullPath, "SKILL.md");
69
+ if (fs.existsSync(skillFile)) {
70
+ const { name, description } = extractFrontmatter(skillFile);
71
+ skills.push({
72
+ path: fullPath,
73
+ skillFile,
74
+ name: name || entry.name,
75
+ description: description || "",
76
+ sourceType
77
+ });
78
+ }
79
+ recurse(fullPath, depth + 1);
80
+ }
81
+ }
82
+ }
83
+ recurse(dir, 0);
84
+ return skills;
85
+ }
86
+ function findAgentsInDir(dir, sourceType, maxDepth = 2) {
87
+ const agents = [];
88
+ if (!fs.existsSync(dir))
89
+ return agents;
90
+ function recurse(currentDir, depth, category) {
91
+ if (depth > maxDepth)
92
+ return;
93
+ const entries = fs.readdirSync(currentDir, { withFileTypes: true });
94
+ for (const entry of entries) {
95
+ const fullPath = path.join(currentDir, entry.name);
96
+ if (entry.isDirectory()) {
97
+ recurse(fullPath, depth + 1, entry.name);
98
+ } else if (entry.name.endsWith(".md")) {
99
+ agents.push({
100
+ name: entry.name.replace(/\.md$/, ""),
101
+ file: fullPath,
102
+ sourceType,
103
+ category
104
+ });
105
+ }
106
+ }
107
+ }
108
+ recurse(dir, 0);
109
+ return agents;
110
+ }
111
+ function findCommandsInDir(dir, sourceType, maxDepth = 2) {
112
+ const commands = [];
113
+ if (!fs.existsSync(dir))
114
+ return commands;
115
+ function recurse(currentDir, depth, category) {
116
+ if (depth > maxDepth)
117
+ return;
118
+ const entries = fs.readdirSync(currentDir, { withFileTypes: true });
119
+ for (const entry of entries) {
120
+ const fullPath = path.join(currentDir, entry.name);
121
+ if (entry.isDirectory()) {
122
+ recurse(fullPath, depth + 1, entry.name);
123
+ } else if (entry.name.endsWith(".md")) {
124
+ const baseName = entry.name.replace(/\.md$/, "");
125
+ const commandName = category ? `/${category}:${baseName}` : `/${baseName}`;
126
+ commands.push({
127
+ name: commandName,
128
+ file: fullPath,
129
+ sourceType,
130
+ category
131
+ });
132
+ }
133
+ }
134
+ }
135
+ recurse(dir, 0);
136
+ return commands;
137
+ }
138
+ function extractAgentFrontmatter(content) {
139
+ const lines = content.split(`
140
+ `);
141
+ let inFrontmatter = false;
142
+ let name = "";
143
+ let description = "";
144
+ for (const line of lines) {
145
+ if (line.trim() === "---") {
146
+ if (inFrontmatter)
147
+ break;
148
+ inFrontmatter = true;
149
+ continue;
150
+ }
151
+ if (inFrontmatter) {
152
+ const match = line.match(/^(\w+(?:-\w+)*):\s*(.*)$/);
153
+ if (match) {
154
+ const [, key, value] = match;
155
+ if (key === "name")
156
+ name = value.trim();
157
+ if (key === "description")
158
+ description = value.trim();
159
+ }
160
+ }
161
+ }
162
+ return { name, description, prompt: stripFrontmatter(content) };
163
+ }
164
+ function extractCommandFrontmatter(content) {
165
+ const lines = content.split(`
166
+ `);
167
+ let inFrontmatter = false;
168
+ let name = "";
169
+ let description = "";
170
+ let argumentHint = "";
171
+ for (const line of lines) {
172
+ if (line.trim() === "---") {
173
+ if (inFrontmatter)
174
+ break;
175
+ inFrontmatter = true;
176
+ continue;
177
+ }
178
+ if (inFrontmatter) {
179
+ const match = line.match(/^(\w+(?:-\w+)*):\s*(.*)$/);
180
+ if (match) {
181
+ const [, key, value] = match;
182
+ if (key === "name")
183
+ name = value.trim();
184
+ if (key === "description")
185
+ description = value.trim();
186
+ if (key === "argument-hint")
187
+ argumentHint = value.trim().replace(/^["']|["']$/g, "");
188
+ }
189
+ }
190
+ }
191
+ return { name, description, argumentHint };
192
+ }
193
+
194
+ export { stripFrontmatter, findSkillsInDir, findAgentsInDir, findCommandsInDir, extractAgentFrontmatter, extractCommandFrontmatter };