@deimoscloud/coreai 0.1.15 → 0.1.17

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 (49) hide show
  1. package/agents/_templates/master-context.md +76 -0
  2. package/agents/_templates/master-protocols.md +39 -0
  3. package/agents/android-engineer.md +177 -0
  4. package/agents/backend-engineer.md +175 -0
  5. package/agents/database-administrator.md +177 -0
  6. package/agents/devops-engineer.md +211 -0
  7. package/agents/{examples/engineering-manager.md → engineering-manager.md} +208 -171
  8. package/agents/frontend-engineer.md +175 -0
  9. package/agents/product-manager.md +371 -0
  10. package/agents/react-engineer.md +177 -0
  11. package/agents/react-native-engineer.md +177 -0
  12. package/agents/software-security-engineer.md +339 -0
  13. package/agents/software-solutions-architect.md +469 -0
  14. package/agents/sre-huawei-cloud-architect.md +177 -0
  15. package/agents/sre-iac-specialist.md +177 -0
  16. package/agents/sre-kubernetes-specialist.md +177 -0
  17. package/agents/sre-network-specialist.md +177 -0
  18. package/agents/wearos-engineer.md +177 -0
  19. package/dist/cli/index.js +494 -826
  20. package/dist/cli/index.js.map +1 -1
  21. package/dist/index.d.ts +75 -84
  22. package/dist/index.js +437 -784
  23. package/dist/index.js.map +1 -1
  24. package/package.json +1 -1
  25. package/agents/android-engineer.yaml +0 -108
  26. package/agents/backend-engineer.yaml +0 -106
  27. package/agents/database-administrator.yaml +0 -108
  28. package/agents/devops-engineer.yaml +0 -106
  29. package/agents/engineering-manager.yaml +0 -104
  30. package/agents/examples/android-engineer.md +0 -302
  31. package/agents/examples/backend-engineer.md +0 -320
  32. package/agents/examples/devops-engineer.md +0 -742
  33. package/agents/examples/frontend-engineer.md +0 -58
  34. package/agents/examples/product-manager.md +0 -315
  35. package/agents/examples/qa-engineer.md +0 -371
  36. package/agents/examples/security-engineer.md +0 -525
  37. package/agents/examples/solutions-architect.md +0 -351
  38. package/agents/examples/wearos-engineer.md +0 -359
  39. package/agents/frontend-engineer.yaml +0 -106
  40. package/agents/product-manager.yaml +0 -109
  41. package/agents/react-engineer.yaml +0 -108
  42. package/agents/react-native-engineer.yaml +0 -108
  43. package/agents/software-security-engineer.yaml +0 -108
  44. package/agents/software-solutions-architect.yaml +0 -107
  45. package/agents/sre-huawei-cloud-architect.yaml +0 -108
  46. package/agents/sre-iac-specialist.yaml +0 -108
  47. package/agents/sre-kubernetes-specialist.yaml +0 -108
  48. package/agents/sre-network-specialist.yaml +0 -108
  49. package/agents/wearos-engineer.yaml +0 -108
package/dist/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  // src/index.ts
2
- import { readFileSync as readFileSync5 } from "fs";
3
- import { dirname as dirname5, join as join8 } from "path";
2
+ import { readFileSync as readFileSync6 } from "fs";
3
+ import { dirname as dirname6, join as join8 } from "path";
4
4
  import { fileURLToPath } from "url";
5
5
 
6
6
  // src/config/loader.ts
@@ -149,6 +149,61 @@ var AgentError = class extends Error {
149
149
  this.name = "AgentError";
150
150
  }
151
151
  };
152
+ function extractFrontmatter(content) {
153
+ const match = content.match(/^---\n([\s\S]*?)\n---\n?([\s\S]*)$/);
154
+ if (!match) {
155
+ throw new AgentError(
156
+ "No YAML frontmatter found. Agent MD files must start with YAML frontmatter (---)",
157
+ "PARSE_ERROR"
158
+ );
159
+ }
160
+ const frontmatterYaml = match[1];
161
+ const body = match[2] ?? "";
162
+ let frontmatter;
163
+ try {
164
+ frontmatter = parseYaml2(frontmatterYaml);
165
+ } catch (error) {
166
+ const message = error instanceof Error ? error.message : "Unknown parse error";
167
+ throw new AgentError(`Failed to parse YAML frontmatter: ${message}`, "PARSE_ERROR", error);
168
+ }
169
+ if (!frontmatter || typeof frontmatter !== "object") {
170
+ throw new AgentError("Invalid frontmatter: expected an object", "PARSE_ERROR");
171
+ }
172
+ return { frontmatter, body };
173
+ }
174
+ function loadAgentFromMdFile(filePath) {
175
+ if (!existsSync2(filePath)) {
176
+ throw new AgentError(`Agent file not found: ${filePath}`, "NOT_FOUND");
177
+ }
178
+ let content;
179
+ try {
180
+ content = readFileSync2(filePath, "utf-8");
181
+ } catch (error) {
182
+ const message = error instanceof Error ? error.message : "Unknown read error";
183
+ throw new AgentError(`Failed to read agent file ${filePath}: ${message}`, "READ_ERROR", error);
184
+ }
185
+ const { frontmatter } = extractFrontmatter(content);
186
+ const role = frontmatter.name || getRoleFromFilename(filePath);
187
+ if (!role) {
188
+ throw new AgentError(
189
+ `Agent MD file must have a 'name' field in frontmatter or a valid filename: ${filePath}`,
190
+ "VALIDATION_ERROR"
191
+ );
192
+ }
193
+ const description = frontmatter.description || "";
194
+ const tools = typeof frontmatter.tools === "string" ? frontmatter.tools.split(",").map((t) => t.trim()).filter(Boolean) : void 0;
195
+ const definition = {
196
+ role,
197
+ type: "ic-engineer",
198
+ // Default, actual identity is in the MD content
199
+ display_name: role.split("-").map((w) => w.charAt(0).toUpperCase() + w.slice(1)).join(" "),
200
+ description
201
+ };
202
+ if (tools) {
203
+ definition.tools = tools;
204
+ }
205
+ return definition;
206
+ }
152
207
  function parseAgentYaml(content, filePath) {
153
208
  try {
154
209
  return parseYaml2(content);
@@ -180,7 +235,7 @@ function validateAgentDefinition(agent) {
180
235
  }
181
236
  return agent;
182
237
  }
183
- function loadAgentFromFile(filePath) {
238
+ function loadAgentFromYamlFile(filePath) {
184
239
  if (!existsSync2(filePath)) {
185
240
  throw new AgentError(`Agent file not found: ${filePath}`, "NOT_FOUND");
186
241
  }
@@ -194,18 +249,36 @@ function loadAgentFromFile(filePath) {
194
249
  const parsed = parseAgentYaml(content, filePath);
195
250
  return validateAgentDefinition(parsed);
196
251
  }
197
- function listYamlFiles(dir) {
252
+ function loadAgentFromFile(filePath) {
253
+ const ext = extname(filePath).toLowerCase();
254
+ if (ext === ".md") {
255
+ return loadAgentFromMdFile(filePath);
256
+ }
257
+ if (ext === ".yaml" || ext === ".yml") {
258
+ console.warn(
259
+ `Warning: YAML agent definitions are deprecated and will be removed in a future version.
260
+ Please migrate ${basename(filePath)} to Markdown format.`
261
+ );
262
+ return loadAgentFromYamlFile(filePath);
263
+ }
264
+ throw new AgentError(
265
+ `Unsupported agent file format: ${ext}. Use .md (recommended) or .yaml/.yml (deprecated)`,
266
+ "PARSE_ERROR"
267
+ );
268
+ }
269
+ function listAgentFiles(dir) {
198
270
  if (!existsSync2(dir)) {
199
271
  return [];
200
272
  }
201
273
  return readdirSync(dir).filter((file) => {
274
+ if (file.startsWith("_")) return false;
202
275
  const ext = extname(file).toLowerCase();
203
- return ext === ".yaml" || ext === ".yml";
276
+ return ext === ".md" || ext === ".yaml" || ext === ".yml";
204
277
  }).map((file) => join2(dir, file));
205
278
  }
206
279
  function loadAgentsFromDirectory(dir, source) {
207
280
  const agents = /* @__PURE__ */ new Map();
208
- const files = listYamlFiles(dir);
281
+ const files = listAgentFiles(dir);
209
282
  for (const filePath of files) {
210
283
  try {
211
284
  const definition = loadAgentFromFile(filePath);
@@ -372,193 +445,73 @@ function resolveAgentDefinition(agent, config, options = {}) {
372
445
  }
373
446
 
374
447
  // src/agents/compiler.ts
375
- import { existsSync as existsSync3, mkdirSync, writeFileSync } from "fs";
376
- import { join as join3, dirname as dirname2 } from "path";
448
+ import { existsSync as existsSync3, mkdirSync, readFileSync as readFileSync3, writeFileSync } from "fs";
449
+ import { join as join3, dirname as dirname2, extname as extname2, isAbsolute } from "path";
450
+ import { parse as parseYaml3, stringify as stringifyYaml } from "yaml";
377
451
  function buildAgentTools(agent, mcpServers) {
378
452
  const tools = agent.tools ? [...agent.tools] : [...DEFAULT_AGENT_TOOLS];
379
453
  if (mcpServers && mcpServers.length > 0) {
380
454
  for (const server of mcpServers) {
381
- tools.push(`mcp__${server}`);
382
- }
383
- }
384
- return tools.join(", ");
385
- }
386
- function generateKnowledgeLibrarySection(agent, lines) {
387
- const kl = agent.knowledge_library;
388
- if (!kl) return;
389
- lines.push("## Knowledge Library Structure");
390
- lines.push("");
391
- if (kl.shared) {
392
- lines.push("### Shared Context (Root - All Agents)");
393
- lines.push("```");
394
- lines.push("/KnowledgeLibrary/");
395
- if (kl.shared.context) {
396
- const filename = kl.shared.context.split("/").pop() ?? "context.txt";
397
- lines.push(`\u251C\u2500\u2500 ${filename}`);
398
- }
399
- if (kl.shared.architecture) {
400
- const filename = kl.shared.architecture.split("/").pop() ?? "architecture.txt";
401
- lines.push(`\u251C\u2500\u2500 ${filename}`);
402
- }
403
- if (kl.shared.prd) {
404
- const filename = kl.shared.prd.split("/").pop() ?? "prd.txt";
405
- lines.push(`\u2514\u2500\u2500 ${filename}`);
406
- }
407
- lines.push("```");
408
- if (kl.shared.remote && kl.shared.remote.length > 0) {
409
- lines.push("");
410
- lines.push("**Remote Documentation:**");
411
- for (const remote of kl.shared.remote) {
412
- lines.push(`- ${remote}`);
455
+ const mcpTool = `mcp__${server}`;
456
+ if (!tools.includes(mcpTool)) {
457
+ tools.push(mcpTool);
413
458
  }
414
459
  }
415
- lines.push("");
416
460
  }
417
- if (kl.personal) {
418
- lines.push(`### Personal Context (${agent.role})`);
419
- lines.push("```");
420
- lines.push(`/KnowledgeLibrary/${agent.role}/`);
421
- if (kl.personal.context) {
422
- lines.push("\u251C\u2500\u2500 context/");
423
- lines.push("\u2502 \u2514\u2500\u2500 current.txt # Your current state, priorities, decisions, issues");
424
- }
425
- if (kl.personal.history) {
426
- lines.push("\u251C\u2500\u2500 history/");
427
- lines.push("\u2502 \u2514\u2500\u2500 [archived context files, timestamped]");
428
- }
429
- if (kl.personal.inbox) {
430
- lines.push("\u251C\u2500\u2500 inbox/");
431
- lines.push("\u2502 \u2514\u2500\u2500 YYYYMMDD_HHMM-[agent-name]-[topic].txt # Messages from other agents");
432
- }
433
- if (kl.personal.outbox) {
434
- lines.push("\u251C\u2500\u2500 outbox/");
435
- lines.push("\u2502 \u2514\u2500\u2500 YYYYMMDD_HHMM-to-[agent-name]-[topic].txt # Copies of sent messages");
436
- }
437
- if (kl.personal.tech) {
438
- lines.push("\u251C\u2500\u2500 tech/");
439
- lines.push("\u2502 \u2514\u2500\u2500 [Technical docs, implementation details, working drafts]");
440
- }
441
- if (kl.personal.control) {
442
- lines.push("\u2514\u2500\u2500 control/");
443
- if (kl.personal.control.objectives) {
444
- lines.push(" \u251C\u2500\u2500 objectives.txt # Current job objectives and goals");
445
- }
446
- if (kl.personal.control.decisions) {
447
- lines.push(" \u251C\u2500\u2500 decisions.txt # Log of key decisions with rationale");
448
- }
449
- if (kl.personal.control.dependencies) {
450
- lines.push(" \u251C\u2500\u2500 dependencies.txt # Dependencies on other jobs");
451
- }
452
- if (kl.personal.control.index) {
453
- lines.push(" \u2514\u2500\u2500 index.txt # Optional index of files/folders");
454
- }
455
- }
456
- lines.push("```");
457
- lines.push("");
458
- }
459
- lines.push("---");
460
- lines.push("");
461
+ return tools.join(", ");
461
462
  }
462
- function generateCommunicationSection(agent, lines) {
463
- const comm = agent.communication;
464
- if (!comm) return;
465
- lines.push("## Communication");
466
- lines.push("");
467
- if (comm.inbox) {
468
- lines.push(`**Inbox:** \`${comm.inbox}\``);
469
- }
470
- if (comm.outbox) {
471
- lines.push(`**Outbox:** \`${comm.outbox}\``);
463
+ function processIncludes(template, templateDir, depth = 0, maxDepth = 3) {
464
+ if (depth > maxDepth) {
465
+ throw new Error(`Include depth exceeded maximum of ${maxDepth}`);
472
466
  }
473
- lines.push("");
474
- if (comm.message_format || comm.outbox_format || comm.processed_dir) {
475
- lines.push("### Message Conventions");
476
- lines.push("");
477
- if (comm.message_format) {
478
- lines.push(`- **Inbox message naming:** \`${comm.message_format}\``);
467
+ const includePattern = /<!--\s*include:\s*(\S+)\s*-->/g;
468
+ return template.replace(includePattern, (_match, includePath) => {
469
+ const resolvedPath = isAbsolute(includePath) ? includePath : join3(templateDir, includePath);
470
+ if (!existsSync3(resolvedPath)) {
471
+ throw new Error(`Include file not found: ${includePath} (resolved to ${resolvedPath})`);
479
472
  }
480
- if (comm.outbox_format) {
481
- lines.push(`- **Outbox message naming:** \`${comm.outbox_format}\``);
482
- }
483
- if (comm.processed_dir) {
484
- lines.push(`- **Processed messages:** Move handled inbox messages to \`${comm.processed_dir}\``);
485
- }
486
- lines.push("");
487
- }
473
+ const includedContent = readFileSync3(resolvedPath, "utf-8");
474
+ return processIncludes(includedContent, dirname2(resolvedPath), depth + 1, maxDepth);
475
+ });
488
476
  }
489
- function generateStartupProtocolSection(agent, lines) {
490
- const protocols = agent.protocols;
491
- if (!protocols?.startup) return;
492
- lines.push("## When Invoked");
493
- lines.push("");
494
- lines.push("> **MANDATORY STARTUP PROTOCOL** - Execute before proceeding with any task.");
495
- lines.push("");
496
- lines.push("### Session Context Check");
497
- lines.push("");
498
- lines.push("First, determine if you have already loaded context in this session:");
499
- lines.push("");
500
- if (protocols.startup.first_session && protocols.startup.first_session.length > 0) {
501
- lines.push("**If this is your FIRST invocation in this session** (no prior context loaded):");
502
- lines.push("");
503
- for (const step of protocols.startup.first_session) {
504
- lines.push(`- [ ] ${step}`);
505
- }
506
- lines.push("");
507
- lines.push('Acknowledge: "Startup protocol complete. Full context loaded."');
508
- lines.push("");
477
+ function processAgentTemplate(templatePath, agent, config, mcpServers) {
478
+ const template = readFileSync3(templatePath, "utf-8");
479
+ const templateDir = dirname2(templatePath);
480
+ const expandedTemplate = processIncludes(template, templateDir);
481
+ const earlyMatch = expandedTemplate.match(/^---\n([\s\S]*?)\n---\n?([\s\S]*)$/);
482
+ if (!earlyMatch) {
483
+ throw new Error(`Invalid markdown format in ${templatePath}: no frontmatter found`);
509
484
  }
510
- if (protocols.startup.subsequent && protocols.startup.subsequent.length > 0) {
511
- lines.push("**If you have ALREADY loaded context in this session** (subsequent invocation):");
512
- lines.push("");
513
- for (const step of protocols.startup.subsequent) {
514
- lines.push(`- [ ] ${step}`);
485
+ const earlyFrontmatter = parseYaml3(earlyMatch[1]);
486
+ const reservedKeys = /* @__PURE__ */ new Set(["name", "description", "tools"]);
487
+ const extendedAgent = { ...agent };
488
+ for (const [key, value] of Object.entries(earlyFrontmatter)) {
489
+ if (!reservedKeys.has(key) && !(key in extendedAgent)) {
490
+ extendedAgent[key] = value;
515
491
  }
516
- lines.push("");
517
- lines.push('Acknowledge: "Context already loaded. Checked inbox for new messages."');
518
- lines.push("");
519
492
  }
520
- lines.push("Then proceed with the task.");
521
- lines.push("");
522
- lines.push("---");
523
- lines.push("");
524
- }
525
- function generateCompletionProtocolSection(agent, lines) {
526
- const protocols = agent.protocols;
527
- if (!protocols?.completion || protocols.completion.length === 0) return;
528
- lines.push("## Before Finishing");
529
- lines.push("");
530
- lines.push("> **MANDATORY COMPLETION PROTOCOL** - Execute ALL steps before ending any task.");
531
- lines.push("");
532
- for (let i = 0; i < protocols.completion.length; i++) {
533
- lines.push(`### ${i + 1}. ${protocols.completion[i]}`);
534
- lines.push("");
493
+ const context = { agent: extendedAgent };
494
+ if (config) {
495
+ context.config = config;
535
496
  }
536
- lines.push('Acknowledge: "Completion protocol finished. Context updated."');
537
- lines.push("");
538
- lines.push("---");
539
- lines.push("");
540
- }
541
- function generateLegacyContextSourcesSection(agent, lines) {
542
- if (!agent.context_sources) return;
543
- if (agent.knowledge_library) return;
544
- lines.push("## Context Sources");
545
- lines.push("");
546
- if (agent.context_sources.shared && agent.context_sources.shared.length > 0) {
547
- lines.push("### Shared");
548
- lines.push("");
549
- for (const source of agent.context_sources.shared) {
550
- lines.push(`- ${source}`);
551
- }
552
- lines.push("");
497
+ const resolved = resolveString(expandedTemplate, context);
498
+ const frontmatterMatch = resolved.match(/^---\n([\s\S]*?)\n---\n?([\s\S]*)$/);
499
+ if (!frontmatterMatch) {
500
+ throw new Error(`Invalid markdown format after resolution in ${templatePath}`);
553
501
  }
554
- if (agent.context_sources.personal && agent.context_sources.personal.length > 0) {
555
- lines.push("### Personal");
556
- lines.push("");
557
- for (const source of agent.context_sources.personal) {
558
- lines.push(`- ${source}`);
559
- }
560
- lines.push("");
502
+ const frontmatterYaml = frontmatterMatch[1];
503
+ const body = frontmatterMatch[2] ?? "";
504
+ const frontmatter = parseYaml3(frontmatterYaml);
505
+ const tools = buildAgentTools(agent, mcpServers);
506
+ frontmatter.tools = tools;
507
+ if (typeof frontmatter.description === "string") {
508
+ frontmatter.description = frontmatter.description.replace(/\n/g, " ").trim();
561
509
  }
510
+ const updatedFrontmatter = stringifyYaml(frontmatter, { lineWidth: 0 }).trim();
511
+ return `---
512
+ ${updatedFrontmatter}
513
+ ---
514
+ ${body}`;
562
515
  }
563
516
  function generateAgentMarkdown(agent, mcpServers) {
564
517
  const lines = [];
@@ -581,8 +534,8 @@ function generateAgentMarkdown(agent, mcpServers) {
581
534
  if (agent.responsibilities && agent.responsibilities.length > 0) {
582
535
  lines.push("## Responsibilities");
583
536
  lines.push("");
584
- for (const responsibility of agent.responsibilities) {
585
- lines.push(`- ${responsibility}`);
537
+ for (const r of agent.responsibilities) {
538
+ lines.push(`- ${r}`);
586
539
  }
587
540
  lines.push("");
588
541
  }
@@ -600,12 +553,12 @@ function generateAgentMarkdown(agent, mcpServers) {
600
553
  if (agent.expertise.tech_stack) {
601
554
  lines.push("### Tech Stack");
602
555
  lines.push("");
603
- const techStack = agent.expertise.tech_stack;
604
- if (typeof techStack === "string") {
605
- lines.push(techStack);
606
- } else if (typeof techStack === "object") {
556
+ const ts = agent.expertise.tech_stack;
557
+ if (typeof ts === "string") {
558
+ lines.push(ts);
559
+ } else if (typeof ts === "object") {
607
560
  lines.push("```json");
608
- lines.push(JSON.stringify(techStack, null, 2));
561
+ lines.push(JSON.stringify(ts, null, 2));
609
562
  lines.push("```");
610
563
  }
611
564
  lines.push("");
@@ -624,7 +577,7 @@ function generateAgentMarkdown(agent, mcpServers) {
624
577
  lines.push("");
625
578
  for (const [category, items] of Object.entries(agent.principles)) {
626
579
  if (items && Array.isArray(items) && items.length > 0) {
627
- const title = formatTitle(category);
580
+ const title = category.replace(/[_-]/g, " ").replace(/\b\w/g, (c) => c.toUpperCase());
628
581
  lines.push(`### ${title}`);
629
582
  lines.push("");
630
583
  for (const item of items) {
@@ -655,21 +608,161 @@ function generateAgentMarkdown(agent, mcpServers) {
655
608
  lines.push("");
656
609
  }
657
610
  }
658
- generateKnowledgeLibrarySection(agent, lines);
659
- generateCommunicationSection(agent, lines);
660
- generateStartupProtocolSection(agent, lines);
661
- generateCompletionProtocolSection(agent, lines);
662
- generateLegacyContextSourcesSection(agent, lines);
611
+ if (agent.knowledge_library) {
612
+ generateKnowledgeLibrarySection(agent, lines);
613
+ }
614
+ if (agent.communication) {
615
+ generateCommunicationSection(agent, lines);
616
+ }
617
+ if (agent.protocols?.startup) {
618
+ generateStartupProtocolSection(agent, lines);
619
+ }
620
+ if (agent.protocols?.completion) {
621
+ generateCompletionProtocolSection(agent, lines);
622
+ }
623
+ if (agent.context_sources && !agent.knowledge_library) {
624
+ lines.push("## Context Sources");
625
+ lines.push("");
626
+ if (agent.context_sources.shared?.length) {
627
+ lines.push("### Shared");
628
+ lines.push("");
629
+ for (const s of agent.context_sources.shared) lines.push(`- ${s}`);
630
+ lines.push("");
631
+ }
632
+ if (agent.context_sources.personal?.length) {
633
+ lines.push("### Personal");
634
+ lines.push("");
635
+ for (const p of agent.context_sources.personal) lines.push(`- ${p}`);
636
+ lines.push("");
637
+ }
638
+ }
663
639
  lines.push("---");
664
640
  lines.push("");
665
641
  lines.push("*Generated by CoreAI*");
666
642
  lines.push("");
667
643
  return lines.join("\n");
668
644
  }
669
- function formatTitle(str) {
670
- return str.replace(/[_-]/g, " ").replace(/\b\w/g, (c) => c.toUpperCase());
645
+ function generateKnowledgeLibrarySection(agent, lines) {
646
+ const kl = agent.knowledge_library;
647
+ if (!kl) return;
648
+ lines.push("## Knowledge Library Structure");
649
+ lines.push("");
650
+ if (kl.shared) {
651
+ lines.push("### Shared Context (Root - All Agents)");
652
+ lines.push("```");
653
+ lines.push("/KnowledgeLibrary/");
654
+ if (kl.shared.context) lines.push(`\u251C\u2500\u2500 ${kl.shared.context.split("/").pop()}`);
655
+ if (kl.shared.architecture) lines.push(`\u251C\u2500\u2500 ${kl.shared.architecture.split("/").pop()}`);
656
+ if (kl.shared.prd) lines.push(`\u2514\u2500\u2500 ${kl.shared.prd.split("/").pop()}`);
657
+ lines.push("```");
658
+ if (kl.shared.remote?.length) {
659
+ lines.push("");
660
+ lines.push("**Remote Documentation:**");
661
+ for (const r of kl.shared.remote) lines.push(`- ${r}`);
662
+ }
663
+ lines.push("");
664
+ }
665
+ if (kl.personal) {
666
+ lines.push(`### Personal Context (${agent.role})`);
667
+ lines.push("```");
668
+ lines.push(`/KnowledgeLibrary/${agent.role}/`);
669
+ if (kl.personal.context) {
670
+ lines.push("\u251C\u2500\u2500 context/");
671
+ lines.push("\u2502 \u2514\u2500\u2500 current.txt");
672
+ }
673
+ if (kl.personal.history) {
674
+ lines.push("\u251C\u2500\u2500 history/");
675
+ }
676
+ if (kl.personal.inbox) {
677
+ lines.push("\u251C\u2500\u2500 inbox/");
678
+ }
679
+ if (kl.personal.outbox) {
680
+ lines.push("\u251C\u2500\u2500 outbox/");
681
+ }
682
+ if (kl.personal.tech) {
683
+ lines.push("\u251C\u2500\u2500 tech/");
684
+ }
685
+ if (kl.personal.control) {
686
+ lines.push("\u2514\u2500\u2500 control/");
687
+ if (kl.personal.control.objectives) lines.push(" \u251C\u2500\u2500 objectives.txt");
688
+ if (kl.personal.control.decisions) lines.push(" \u251C\u2500\u2500 decisions.txt");
689
+ if (kl.personal.control.dependencies) lines.push(" \u251C\u2500\u2500 dependencies.txt");
690
+ if (kl.personal.control.index) lines.push(" \u2514\u2500\u2500 index.txt");
691
+ }
692
+ lines.push("```");
693
+ lines.push("");
694
+ }
695
+ lines.push("---");
696
+ lines.push("");
697
+ }
698
+ function generateCommunicationSection(agent, lines) {
699
+ const comm = agent.communication;
700
+ if (!comm) return;
701
+ lines.push("## Communication");
702
+ lines.push("");
703
+ if (comm.inbox) lines.push(`**Inbox:** \`${comm.inbox}\``);
704
+ if (comm.outbox) lines.push(`**Outbox:** \`${comm.outbox}\``);
705
+ lines.push("");
706
+ if (comm.message_format || comm.outbox_format || comm.processed_dir) {
707
+ lines.push("### Message Conventions");
708
+ lines.push("");
709
+ if (comm.message_format) lines.push(`- **Inbox message naming:** \`${comm.message_format}\``);
710
+ if (comm.outbox_format) lines.push(`- **Outbox message naming:** \`${comm.outbox_format}\``);
711
+ if (comm.processed_dir) lines.push(`- **Processed messages:** Move handled inbox messages to \`${comm.processed_dir}\``);
712
+ lines.push("");
713
+ }
714
+ }
715
+ function generateStartupProtocolSection(agent, lines) {
716
+ const p = agent.protocols;
717
+ if (!p?.startup) return;
718
+ lines.push("## When Invoked");
719
+ lines.push("");
720
+ lines.push("> **MANDATORY STARTUP PROTOCOL** - Execute before proceeding with any task.");
721
+ lines.push("");
722
+ lines.push("### Session Context Check");
723
+ lines.push("");
724
+ if (p.startup.first_session?.length) {
725
+ lines.push("**If this is your FIRST invocation in this session:**");
726
+ lines.push("");
727
+ for (const s of p.startup.first_session) lines.push(`- [ ] ${s}`);
728
+ lines.push("");
729
+ lines.push('Acknowledge: "Startup protocol complete. Full context loaded."');
730
+ lines.push("");
731
+ }
732
+ if (p.startup.subsequent?.length) {
733
+ lines.push("**If you have ALREADY loaded context in this session:**");
734
+ lines.push("");
735
+ for (const s of p.startup.subsequent) lines.push(`- [ ] ${s}`);
736
+ lines.push("");
737
+ lines.push('Acknowledge: "Context already loaded. Checked inbox for new messages."');
738
+ lines.push("");
739
+ }
740
+ lines.push("Then proceed with the task.");
741
+ lines.push("");
742
+ lines.push("---");
743
+ lines.push("");
671
744
  }
672
- function compileAgent(agent, config, mcpServers) {
745
+ function generateCompletionProtocolSection(agent, lines) {
746
+ const p = agent.protocols;
747
+ if (!p?.completion?.length) return;
748
+ lines.push("## Before Finishing");
749
+ lines.push("");
750
+ lines.push("> **MANDATORY COMPLETION PROTOCOL** - Execute ALL steps before ending any task.");
751
+ lines.push("");
752
+ for (let i = 0; i < p.completion.length; i++) {
753
+ lines.push(`### ${i + 1}. ${p.completion[i]}`);
754
+ lines.push("");
755
+ }
756
+ lines.push('Acknowledge: "Completion protocol finished. Context updated."');
757
+ lines.push("");
758
+ lines.push("---");
759
+ lines.push("");
760
+ }
761
+ function compileAgent(agent, filePath, config, mcpServers) {
762
+ const ext = extname2(filePath).toLowerCase();
763
+ if (ext === ".md") {
764
+ return processAgentTemplate(filePath, agent, config, mcpServers);
765
+ }
673
766
  const resolved = resolveAgentDefinition(agent, config);
674
767
  return generateAgentMarkdown(resolved, mcpServers);
675
768
  }
@@ -729,7 +822,12 @@ function compileAgents(config, options = {}) {
729
822
  continue;
730
823
  }
731
824
  try {
732
- const markdown = compileAgent(metadata.definition, config, options.mcpServers);
825
+ const markdown = compileAgent(
826
+ metadata.definition,
827
+ metadata.filePath,
828
+ config,
829
+ options.mcpServers
830
+ );
733
831
  const outputPath = join3(outputDir, `${role}.md`);
734
832
  writeFileSync(outputPath, markdown, "utf-8");
735
833
  result.compiled.push({
@@ -2596,470 +2694,124 @@ var StepTracker = class {
2596
2694
  };
2597
2695
 
2598
2696
  // src/skills/generator.ts
2599
- import { existsSync as existsSync4, mkdirSync as mkdirSync2, writeFileSync as writeFileSync2, readFileSync as readFileSync3, readdirSync as readdirSync2, statSync } from "fs";
2600
- import { join as join6, basename as basename3 } from "path";
2601
-
2602
- // src/skills/templates.ts
2603
- var checkInboxSkill = {
2604
- name: "check-inbox",
2605
- description: "Check your inbox for pending tasks and messages",
2606
- category: "core",
2607
- content: `---
2608
- description: Check your inbox for pending tasks and messages
2609
- ---
2610
-
2611
- # Check Inbox
2612
-
2613
- Check the inbox at \`KnowledgeLibrary/{{AGENT_NAME}}/inbox/\` for new messages.
2614
-
2615
- ## Instructions
2616
-
2617
- 1. Read all unprocessed messages in the inbox directory
2618
- 2. For each message:
2619
- - Parse the frontmatter (type, from, date, priority)
2620
- - Understand the request or task
2621
- - Take appropriate action based on message type
2622
- 3. After processing, move message to \`inbox/processed/\`
2623
- 4. Update your context file at \`KnowledgeLibrary/{{AGENT_NAME}}/context/current.txt\`
2624
-
2625
- ## Message Types
2626
-
2627
- - **task-assignment**: New work assigned to you
2628
- - **completion-report**: Another agent completed work
2629
- - **review-request**: Code review needed
2630
- - **feedback**: Response to your previous work
2631
-
2632
- ## Output Format
2633
-
2634
- Report what messages were processed and actions taken.
2635
- `
2636
- };
2637
- var delegateSkill = {
2638
- name: "delegate",
2639
- description: "Delegate a task to another agent via inbox messaging",
2640
- argumentHint: "<task-description> to <agent-name>",
2641
- category: "core",
2642
- content: `---
2643
- description: Delegate a task to another agent via inbox messaging
2644
- argument-hint: <task-description> to <agent-name>
2645
- ---
2646
-
2647
- # Delegate Task
2648
-
2649
- Delegate work to another agent using the inbox-based messaging system.
2650
-
2651
- ## CRITICAL: Do NOT use the Task tool
2652
-
2653
- Agent-to-agent delegation MUST use file-based messaging, not the Task tool.
2654
- The Task tool spawns subagents that lose MCP access.
2655
-
2656
- ## Instructions
2657
-
2658
- 1. Parse the delegation request to identify:
2659
- - The task to delegate
2660
- - The target agent
2661
-
2662
- 2. Create a message file in the target agent's inbox:
2663
- - Path: \`KnowledgeLibrary/<target-agent>/inbox/\`
2664
- - Filename: \`YYYYMMDD_HHMM-{{AGENT_NAME}}-<subject>.md\`
2665
-
2666
- 3. Use this message format:
2667
- \`\`\`markdown
2668
- ---
2669
- type: task-assignment
2670
- from: {{AGENT_NAME}}
2671
- to: <target-agent>
2672
- date: YYYY-MM-DD HH:MM
2673
- priority: P2
2674
- ---
2675
-
2676
- ## Task Assignment
2677
-
2678
- ### Description
2679
- <Clear description of what needs to be done>
2680
-
2681
- ### Context
2682
- <Any relevant context or background>
2683
-
2684
- ### Expected Deliverables
2685
- 1. <Deliverable 1>
2686
- 2. <Deliverable 2>
2687
-
2688
- ### Success Criteria
2689
- - <Criterion 1>
2690
- - <Criterion 2>
2691
- \`\`\`
2692
-
2693
- 4. Tell the user to invoke the target agent:
2694
- "Please invoke @<target-agent> to process this task."
2695
-
2696
- ## Output
2697
-
2698
- Confirm the delegation message was created and instruct user to invoke the agent.
2699
- `
2700
- };
2701
- var gitCommitSkill = {
2702
- name: "git-commit",
2703
- description: "Create a quality-gated git commit",
2704
- argumentHint: "<commit-message>",
2705
- category: "core",
2706
- dependencies: [{ type: "git", required: false, description: "For commit operations" }],
2707
- content: `---
2708
- description: Create a quality-gated git commit
2709
- argument-hint: <commit-message>
2710
- optional: [git]
2711
- ---
2712
-
2713
- # Git Commit
2714
-
2715
- Create a git commit after passing all quality gates.
2716
-
2717
- ## Quality Gates
2718
-
2719
- Run these checks before committing:
2720
-
2721
- 1. **Lint**: \`{{LINT_CMD}}\`
2722
- 2. **Tests**: \`{{TEST_CMD}}\`
2723
- 3. **Build**: \`{{BUILD_CMD}}\`
2724
-
2725
- ## Instructions
2726
-
2727
- 1. Stage the relevant files with \`git add\`
2728
- 2. Run all quality gate commands
2729
- 3. If any gate fails:
2730
- - Fix the issues
2731
- - Re-run the failed gate
2732
- - Continue only when all pass
2733
- 4. Create the commit with the provided message
2734
- 5. Format: Include ticket reference if applicable
2735
-
2736
- ## Commit Message Format
2737
-
2738
- \`\`\`
2739
- <type>(<scope>): <description>
2740
-
2741
- [optional body]
2742
-
2743
- [optional footer]
2744
- \`\`\`
2745
-
2746
- Types: feat, fix, docs, style, refactor, test, chore
2747
-
2748
- ## Fallbacks
2749
-
2750
- If quality gate commands are not configured:
2751
- - Ask the user what commands to run
2752
- - Or skip gates with user confirmation
2753
- `
2754
- };
2755
- var prCreateSkill = {
2756
- name: "pr-create",
2757
- description: "Create a pull request with proper format",
2758
- argumentHint: "[branch-name]",
2759
- category: "core",
2760
- dependencies: [{ type: "git", required: true, description: "For PR creation" }],
2761
- content: `---
2762
- description: Create a pull request with proper format
2763
- argument-hint: [branch-name]
2764
- requires: [git]
2765
- ---
2766
-
2767
- # Create Pull Request
2768
-
2769
- Create a well-formatted pull request for the current branch.
2770
-
2771
- ## Instructions
2772
-
2773
- 1. Ensure all changes are committed
2774
- 2. Push the branch to remote
2775
- 3. Create PR with proper format:
2776
-
2777
- \`\`\`markdown
2778
- ## Summary
2779
- <Brief description of changes>
2780
-
2781
- ## Changes
2782
- - <Change 1>
2783
- - <Change 2>
2784
-
2785
- ## Test Plan
2786
- - [ ] <Test case 1>
2787
- - [ ] <Test case 2>
2788
-
2789
- ## Related Issues
2790
- Closes {{JIRA_PROJECT}}-XXX
2791
- \`\`\`
2792
-
2793
- 4. Request reviewers if specified
2794
-
2795
- ## Using GitHub CLI
2796
-
2797
- \`\`\`bash
2798
- gh pr create --title "<title>" --body "<body>"
2799
- \`\`\`
2800
-
2801
- ## Output
2802
-
2803
- Provide the PR URL and summary of what was created.
2804
- `
2805
- };
2806
- var reviewSkill = {
2807
- name: "review",
2808
- description: "Request or perform a code review",
2809
- argumentHint: "<pr-number-or-url>",
2810
- category: "core",
2811
- dependencies: [{ type: "git", required: true, description: "For PR review" }],
2812
- content: `---
2813
- description: Request or perform a code review
2814
- argument-hint: <pr-number-or-url>
2815
- requires: [git]
2816
- ---
2817
-
2818
- # Code Review
2819
-
2820
- Review a pull request or delegate review to a specialist.
2821
-
2822
- ## Instructions
2823
-
2824
- ### If you are reviewing:
2825
-
2826
- 1. Fetch the PR details and diff
2827
- 2. Review for:
2828
- - Code quality and style
2829
- - Logic errors or bugs
2830
- - Security concerns
2831
- - Test coverage
2832
- - Documentation
2833
- 3. Provide feedback with specific line references
2834
- 4. Approve, request changes, or comment
2835
-
2836
- ### If delegating to a reviewer:
2837
-
2838
- 1. Identify the appropriate reviewer based on the changes
2839
- 2. Create a review request message in their inbox
2840
- 3. Include PR link and context
2841
-
2842
- ## Review Checklist
2843
-
2844
- - [ ] Code follows project conventions
2845
- - [ ] No obvious bugs or edge cases
2846
- - [ ] Tests cover the changes
2847
- - [ ] Documentation updated if needed
2848
- - [ ] No security vulnerabilities
2849
-
2850
- ## Output
2851
-
2852
- Provide review summary with actionable feedback.
2853
- `
2854
- };
2855
- var sprintStatusSkill = {
2856
- name: "sprint-status",
2857
- description: "Get current sprint status and progress",
2858
- category: "optional",
2859
- dependencies: [{ type: "issue_tracker", required: true, description: "For sprint data" }],
2860
- content: `---
2861
- description: Get current sprint status and progress
2862
- requires: [issue_tracker]
2863
- ---
2864
-
2865
- # Sprint Status
2866
-
2867
- Get the current sprint status and team progress.
2868
-
2869
- ## Instructions
2870
-
2871
- 1. Query the active sprint for project {{JIRA_PROJECT}}
2872
- 2. Gather metrics:
2873
- - Total story points committed
2874
- - Points completed
2875
- - Points in progress
2876
- - Points remaining
2877
- 3. List tickets by status
2878
- 4. Identify blockers or at-risk items
2879
-
2880
- ## Output Format
2881
-
2882
- \`\`\`
2883
- Sprint: <sprint-name>
2884
- Progress: XX/YY points (ZZ%)
2885
-
2886
- ## Completed
2887
- - [{{JIRA_PROJECT}}-123] Task name (3 pts)
2888
-
2889
- ## In Progress
2890
- - [{{JIRA_PROJECT}}-124] Task name (5 pts) - @assignee
2891
-
2892
- ## To Do
2893
- - [{{JIRA_PROJECT}}-125] Task name (2 pts)
2894
-
2895
- ## Blocked
2896
- - [{{JIRA_PROJECT}}-126] Task name - Reason
2897
- \`\`\`
2898
-
2899
- ## Fallbacks
2900
-
2901
- If issue tracker is unavailable:
2902
- - Report that sprint data cannot be fetched
2903
- - Suggest checking the issue tracker directly at {{JIRA_URL}}
2904
- `
2905
- };
2906
- var jiraCreateSkill = {
2907
- name: "jira-create",
2908
- description: "Create a new Jira ticket",
2909
- argumentHint: "<ticket-type> <summary>",
2910
- category: "optional",
2911
- dependencies: [{ type: "issue_tracker", required: true, description: "For ticket creation" }],
2912
- content: `---
2913
- description: Create a new Jira ticket
2914
- argument-hint: <ticket-type> <summary>
2915
- requires: [issue_tracker]
2916
- ---
2917
-
2918
- # Create Jira Ticket
2919
-
2920
- Create a new ticket in project {{JIRA_PROJECT}}.
2921
-
2922
- ## Instructions
2923
-
2924
- 1. Parse the ticket type and summary from arguments
2925
- 2. Gather additional details:
2926
- - Description
2927
- - Priority
2928
- - Labels
2929
- - Components (if applicable)
2930
- 3. Create the ticket via the issue tracker integration
2931
- 4. Return the ticket key and URL
2932
-
2933
- ## Ticket Types
2934
-
2935
- - **Story**: User-facing feature
2936
- - **Bug**: Defect to fix
2937
- - **Task**: Technical work
2938
- - **Spike**: Research/investigation
2939
-
2940
- ## Output
2941
-
2942
- \`\`\`
2943
- Created: {{JIRA_PROJECT}}-XXX
2944
- URL: {{JIRA_URL}}/browse/{{JIRA_PROJECT}}-XXX
2945
- Summary: <summary>
2946
- Type: <type>
2947
- \`\`\`
2948
-
2949
- ## Fallbacks
2950
-
2951
- If issue tracker is unavailable:
2952
- - Provide the user with manual creation instructions
2953
- - Include all details they should enter
2954
- `
2955
- };
2956
- var jiraTransitionSkill = {
2957
- name: "jira-transition",
2958
- description: "Transition a Jira ticket to a new status",
2959
- argumentHint: "<ticket-key> to <status>",
2960
- category: "optional",
2961
- dependencies: [{ type: "issue_tracker", required: true, description: "For ticket transitions" }],
2962
- content: `---
2963
- description: Transition a Jira ticket to a new status
2964
- argument-hint: <ticket-key> to <status>
2965
- requires: [issue_tracker]
2966
- ---
2967
-
2968
- # Transition Jira Ticket
2969
-
2970
- Update the status of a ticket in {{JIRA_PROJECT}}.
2971
-
2972
- ## Status Mapping
2973
-
2974
- | Workflow Status | Jira Status |
2975
- |-----------------|-------------|
2976
- | BACKLOG | Backlog |
2977
- | IN_PROGRESS | In Progress |
2978
- | PR_CREATED | In Review |
2979
- | IN_REVIEW | In Review |
2980
- | APPROVED | Ready to Merge |
2981
- | MERGED | Done |
2982
- | DONE | Done |
2983
-
2984
- ## Instructions
2985
-
2986
- 1. Parse ticket key and target status
2987
- 2. Validate the transition is allowed
2988
- 3. Add a comment explaining the transition
2989
- 4. Execute the transition
2990
-
2991
- ## Transition Comment Format
2992
-
2993
- \`\`\`
2994
- Status updated to <status>.
2995
- <optional context about why>
2996
- \`\`\`
2997
-
2998
- ## Fallbacks
2999
-
3000
- If issue tracker is unavailable:
3001
- - Instruct user to manually transition at {{JIRA_URL}}
3002
- - Provide the target status name
3003
- `
3004
- };
3005
- var docsUpdateSkill = {
3006
- name: "docs-update",
3007
- description: "Update project documentation",
3008
- argumentHint: "<doc-path-or-topic>",
3009
- category: "optional",
3010
- dependencies: [{ type: "documentation", required: false, description: "For remote docs" }],
3011
- content: `---
3012
- description: Update project documentation
3013
- argument-hint: <doc-path-or-topic>
3014
- optional: [documentation]
3015
- ---
3016
-
3017
- # Update Documentation
3018
-
3019
- Update project documentation for a specific topic or file.
3020
-
3021
- ## Instructions
3022
-
3023
- 1. Identify the documentation to update:
3024
- - Local: \`{{DOCS_PATH}}/\`
3025
- - Remote: {{CONFLUENCE_SPACE}} (if configured)
3026
-
3027
- 2. Make the necessary updates:
3028
- - Keep formatting consistent
3029
- - Update examples if code changed
3030
- - Add/update version information
3031
-
3032
- 3. For remote documentation:
3033
- - Use the documentation integration
3034
- - Or provide content for manual update
3035
-
3036
- ## Documentation Types
3037
-
3038
- - **README**: Project overview and setup
3039
- - **API Docs**: Endpoint documentation
3040
- - **Architecture**: Design decisions
3041
- - **Runbooks**: Operational procedures
3042
-
3043
- ## Fallbacks
3044
-
3045
- If documentation integration is unavailable:
3046
- - Create/update local markdown files
3047
- - Provide instructions for manual remote update
3048
- `
3049
- };
3050
- var builtInSkills = [
3051
- checkInboxSkill,
3052
- delegateSkill,
3053
- gitCommitSkill,
3054
- prCreateSkill,
3055
- reviewSkill,
3056
- sprintStatusSkill,
3057
- jiraCreateSkill,
3058
- jiraTransitionSkill,
3059
- docsUpdateSkill
3060
- ];
3061
-
3062
- // src/skills/generator.ts
2697
+ import { existsSync as existsSync4, mkdirSync as mkdirSync2, writeFileSync as writeFileSync2, readFileSync as readFileSync4, readdirSync as readdirSync2, statSync } from "fs";
2698
+ import { join as join6, dirname as dirname5 } from "path";
2699
+ function getCoreSkillsDir() {
2700
+ let currentDir = dirname5(import.meta.url.replace("file://", ""));
2701
+ for (let i = 0; i < 5; i++) {
2702
+ if (existsSync4(join6(currentDir, "package.json"))) {
2703
+ return join6(currentDir, "skills");
2704
+ }
2705
+ currentDir = dirname5(currentDir);
2706
+ }
2707
+ return join6(dirname5(dirname5(dirname5(import.meta.url.replace("file://", "")))), "skills");
2708
+ }
2709
+ function discoverSkills(skillsDir) {
2710
+ const templates = [];
2711
+ if (!existsSync4(skillsDir)) {
2712
+ return templates;
2713
+ }
2714
+ const categories = readdirSync2(skillsDir);
2715
+ for (const category of categories) {
2716
+ const categoryPath = join6(skillsDir, category);
2717
+ const stat = statSync(categoryPath);
2718
+ if (!stat.isDirectory()) continue;
2719
+ if (category.startsWith(".") || category.startsWith("_")) continue;
2720
+ const skillDirs = readdirSync2(categoryPath);
2721
+ for (const skillName of skillDirs) {
2722
+ const skillDir = join6(categoryPath, skillName);
2723
+ const skillStat = statSync(skillDir);
2724
+ if (!skillStat.isDirectory()) continue;
2725
+ const skillFile = join6(skillDir, "SKILL.md");
2726
+ if (!existsSync4(skillFile)) continue;
2727
+ try {
2728
+ const content = readFileSync4(skillFile, "utf-8");
2729
+ const template = parseSkillFile(skillName, category, content);
2730
+ templates.push(template);
2731
+ } catch {
2732
+ }
2733
+ }
2734
+ }
2735
+ return templates;
2736
+ }
2737
+ function parseSkillFile(name, category, content) {
2738
+ const template = {
2739
+ name,
2740
+ description: name,
2741
+ category,
2742
+ content
2743
+ };
2744
+ const frontmatterMatch = content.match(/^---\r?\n([\s\S]*?)\r?\n---\r?\n/);
2745
+ if (!frontmatterMatch) {
2746
+ return template;
2747
+ }
2748
+ const frontmatter = frontmatterMatch[1];
2749
+ const lines = frontmatter.split(/\r?\n/);
2750
+ const dependencies = [];
2751
+ for (const line of lines) {
2752
+ const colonIndex = line.indexOf(":");
2753
+ if (colonIndex === -1) continue;
2754
+ const key = line.slice(0, colonIndex).trim();
2755
+ let value = line.slice(colonIndex + 1).trim();
2756
+ if (value.startsWith('"') && value.endsWith('"') || value.startsWith("'") && value.endsWith("'")) {
2757
+ value = value.slice(1, -1);
2758
+ }
2759
+ switch (key) {
2760
+ case "name":
2761
+ template.name = value;
2762
+ break;
2763
+ case "description":
2764
+ template.description = value;
2765
+ break;
2766
+ case "argument-hint":
2767
+ template.argumentHint = value;
2768
+ break;
2769
+ case "requires":
2770
+ if (value.startsWith("[") && value.endsWith("]")) {
2771
+ const items = value.slice(1, -1).split(",").map((s) => s.trim().replace(/['"]/g, ""));
2772
+ for (const item of items) {
2773
+ if (item) {
2774
+ dependencies.push({
2775
+ type: mapIntegrationName(item),
2776
+ required: true
2777
+ });
2778
+ }
2779
+ }
2780
+ }
2781
+ break;
2782
+ case "optional":
2783
+ if (value.startsWith("[") && value.endsWith("]")) {
2784
+ const items = value.slice(1, -1).split(",").map((s) => s.trim().replace(/['"]/g, ""));
2785
+ for (const item of items) {
2786
+ if (item) {
2787
+ dependencies.push({
2788
+ type: mapIntegrationName(item),
2789
+ required: false
2790
+ });
2791
+ }
2792
+ }
2793
+ }
2794
+ break;
2795
+ }
2796
+ }
2797
+ if (dependencies.length > 0) {
2798
+ template.dependencies = dependencies;
2799
+ }
2800
+ return template;
2801
+ }
2802
+ function mapIntegrationName(name) {
2803
+ const lower = name.toLowerCase();
2804
+ if (["jira", "linear", "issue_tracker", "issues", "github-issues"].includes(lower)) {
2805
+ return "issue_tracker";
2806
+ }
2807
+ if (["git", "github", "gitlab", "bitbucket"].includes(lower)) {
2808
+ return "git";
2809
+ }
2810
+ if (["docs", "documentation", "confluence", "notion", "wiki"].includes(lower)) {
2811
+ return "documentation";
2812
+ }
2813
+ return "state";
2814
+ }
3063
2815
  function extractVariables2(config) {
3064
2816
  const vars = {};
3065
2817
  if (!config) {
@@ -3169,112 +2921,12 @@ function checkDependencies(skill, config) {
3169
2921
  missing
3170
2922
  };
3171
2923
  }
3172
- function loadCustomTemplates(templatesDir) {
3173
- const templates = [];
3174
- if (!existsSync4(templatesDir)) {
3175
- return templates;
3176
- }
3177
- const files = readdirSync2(templatesDir);
3178
- for (const file of files) {
3179
- if (!file.endsWith(".md")) continue;
3180
- const filePath = join6(templatesDir, file);
3181
- const stat = statSync(filePath);
3182
- if (!stat.isFile()) continue;
3183
- try {
3184
- const content = readFileSync3(filePath, "utf-8");
3185
- const template = parseSkillTemplate(file, content);
3186
- templates.push(template);
3187
- } catch {
3188
- }
3189
- }
3190
- return templates;
3191
- }
3192
- function parseSkillTemplate(filename, content) {
3193
- const name = basename3(filename, ".md");
3194
- const frontmatterMatch = content.match(/^---\r?\n([\s\S]*?)\r?\n---\r?\n([\s\S]*)$/);
3195
- let description = name;
3196
- let argumentHint;
3197
- const dependencies = [];
3198
- if (frontmatterMatch) {
3199
- const frontmatter = frontmatterMatch[1] ?? "";
3200
- const lines = frontmatter.split(/\r?\n/);
3201
- for (const line of lines) {
3202
- const colonIndex = line.indexOf(":");
3203
- if (colonIndex === -1) continue;
3204
- const key = line.slice(0, colonIndex).trim();
3205
- let value = line.slice(colonIndex + 1).trim();
3206
- if (value.startsWith('"') && value.endsWith('"') || value.startsWith("'") && value.endsWith("'")) {
3207
- value = value.slice(1, -1);
3208
- }
3209
- switch (key) {
3210
- case "description":
3211
- description = value;
3212
- break;
3213
- case "argument-hint":
3214
- argumentHint = value;
3215
- break;
3216
- case "requires":
3217
- if (value.startsWith("[") && value.endsWith("]")) {
3218
- const items = value.slice(1, -1).split(",").map((s) => s.trim().replace(/['"]/g, ""));
3219
- for (const item of items) {
3220
- if (item) {
3221
- dependencies.push({
3222
- type: mapIntegrationName(item),
3223
- required: true
3224
- });
3225
- }
3226
- }
3227
- }
3228
- break;
3229
- case "optional":
3230
- if (value.startsWith("[") && value.endsWith("]")) {
3231
- const items = value.slice(1, -1).split(",").map((s) => s.trim().replace(/['"]/g, ""));
3232
- for (const item of items) {
3233
- if (item) {
3234
- dependencies.push({
3235
- type: mapIntegrationName(item),
3236
- required: false
3237
- });
3238
- }
3239
- }
3240
- }
3241
- break;
3242
- }
3243
- }
3244
- }
3245
- const template = {
3246
- name,
3247
- description,
3248
- category: "custom",
3249
- content
3250
- };
3251
- if (argumentHint) {
3252
- template.argumentHint = argumentHint;
3253
- }
3254
- if (dependencies.length > 0) {
3255
- template.dependencies = dependencies;
3256
- }
3257
- return template;
3258
- }
3259
- function mapIntegrationName(name) {
3260
- const lower = name.toLowerCase();
3261
- if (["jira", "linear", "issue_tracker", "issues", "github-issues"].includes(lower)) {
3262
- return "issue_tracker";
3263
- }
3264
- if (["git", "github", "gitlab", "bitbucket"].includes(lower)) {
3265
- return "git";
3266
- }
3267
- if (["docs", "documentation", "confluence", "notion", "wiki"].includes(lower)) {
3268
- return "documentation";
3269
- }
3270
- return "state";
3271
- }
3272
2924
  function generateSkills(config, options = {}) {
3273
2925
  const projectRoot = options.projectRoot ?? process.cwd();
3274
- const outputDir = options.outputDir ?? join6(projectRoot, ".claude", "commands");
2926
+ const coreSkillsDir = options.coreSkillsDir ?? getCoreSkillsDir();
2927
+ const outputDir = options.outputDir ?? join6(projectRoot, ".claude", "skills");
3275
2928
  const includeCoreSkills = options.includeCoreSkills ?? true;
3276
- const includeOptionalSkills = options.includeOptionalSkills ?? true;
3277
- const overwrite = options.overwrite ?? false;
2929
+ const overwrite = options.overwrite ?? true;
3278
2930
  const result = {
3279
2931
  generated: [],
3280
2932
  errors: [],
@@ -3287,21 +2939,17 @@ function generateSkills(config, options = {}) {
3287
2939
  result.variables = variables;
3288
2940
  let templates = [];
3289
2941
  if (includeCoreSkills) {
3290
- templates.push(...builtInSkills.filter((s) => s.category === "core"));
3291
- }
3292
- if (includeOptionalSkills) {
3293
- templates.push(...builtInSkills.filter((s) => s.category === "optional"));
2942
+ const discovered = discoverSkills(coreSkillsDir);
2943
+ templates.push(...discovered);
3294
2944
  }
3295
2945
  if (options.customTemplatesDir && existsSync4(options.customTemplatesDir)) {
3296
- templates.push(...loadCustomTemplates(options.customTemplatesDir));
2946
+ const custom = discoverSkills(options.customTemplatesDir);
2947
+ templates.push(...custom);
3297
2948
  }
3298
2949
  if (options.skills && options.skills.length > 0) {
3299
2950
  const skillsToInclude = options.skills;
3300
2951
  templates = templates.filter((t) => skillsToInclude.includes(t.name));
3301
2952
  }
3302
- if (!existsSync4(outputDir)) {
3303
- mkdirSync2(outputDir, { recursive: true });
3304
- }
3305
2953
  for (const template of templates) {
3306
2954
  try {
3307
2955
  const generated = generateSkill(template, variables, config, outputDir, overwrite);
@@ -3316,7 +2964,8 @@ function generateSkills(config, options = {}) {
3316
2964
  return result;
3317
2965
  }
3318
2966
  function generateSkill(template, variables, config, outputDir, overwrite) {
3319
- const outputPath = join6(outputDir, `${template.name}.md`);
2967
+ const skillDir = join6(outputDir, template.name);
2968
+ const outputPath = join6(skillDir, "SKILL.md");
3320
2969
  if (existsSync4(outputPath) && !overwrite) {
3321
2970
  return {
3322
2971
  name: template.name,
@@ -3339,6 +2988,9 @@ function generateSkill(template, variables, config, outputDir, overwrite) {
3339
2988
  }
3340
2989
  const content = substituteVariables(template.content, variables);
3341
2990
  const isUpdate = existsSync4(outputPath);
2991
+ if (!existsSync4(skillDir)) {
2992
+ mkdirSync2(skillDir, { recursive: true });
2993
+ }
3342
2994
  writeFileSync2(outputPath, content, "utf-8");
3343
2995
  return {
3344
2996
  name: template.name,
@@ -3382,7 +3034,7 @@ function formatGenerateResult(result) {
3382
3034
  }
3383
3035
  const total = created.length + updated.length;
3384
3036
  if (total > 0) {
3385
- lines.push(`Generated ${total} skill(s) to .claude/commands/`);
3037
+ lines.push(`Generated ${total} skill(s) to .claude/skills/`);
3386
3038
  } else if (result.generated.length === 0 && result.errors.length === 0) {
3387
3039
  lines.push("No skills to generate.");
3388
3040
  }
@@ -3394,12 +3046,12 @@ import {
3394
3046
  existsSync as existsSync5,
3395
3047
  mkdirSync as mkdirSync3,
3396
3048
  writeFileSync as writeFileSync3,
3397
- readFileSync as readFileSync4,
3049
+ readFileSync as readFileSync5,
3398
3050
  readdirSync as readdirSync3,
3399
3051
  renameSync,
3400
3052
  statSync as statSync2
3401
3053
  } from "fs";
3402
- import { join as join7, basename as basename4 } from "path";
3054
+ import { join as join7, basename as basename3 } from "path";
3403
3055
  var DEFAULT_KNOWLEDGE_LIBRARY_PATH = "KnowledgeLibrary";
3404
3056
  var STANDARD_FILES = {
3405
3057
  context: "context.txt",
@@ -3649,7 +3301,7 @@ function getAgentKnowledgeState(agentName, options = {}) {
3649
3301
  let context;
3650
3302
  const currentContextPath = join7(dirs.context, "current.txt");
3651
3303
  if (existsSync5(currentContextPath)) {
3652
- const content = readFileSync4(currentContextPath, "utf-8");
3304
+ const content = readFileSync5(currentContextPath, "utf-8");
3653
3305
  context = parseContextFile(content);
3654
3306
  }
3655
3307
  const state = {
@@ -3749,7 +3401,7 @@ function readInboxMessages(agentName, options = {}) {
3749
3401
  );
3750
3402
  for (const file of files) {
3751
3403
  const filePath = join7(dirs.inbox, file);
3752
- const rawContent = readFileSync4(filePath, "utf-8");
3404
+ const rawContent = readFileSync5(filePath, "utf-8");
3753
3405
  const { metadata, body } = parseMessageFrontmatter(rawContent);
3754
3406
  if (options.type && metadata.type !== options.type) continue;
3755
3407
  if (options.from && metadata.from !== options.from) continue;
@@ -3769,7 +3421,7 @@ function readInboxMessages(agentName, options = {}) {
3769
3421
  );
3770
3422
  for (const file of files) {
3771
3423
  const filePath = join7(dirs.inboxProcessed, file);
3772
- const rawContent = readFileSync4(filePath, "utf-8");
3424
+ const rawContent = readFileSync5(filePath, "utf-8");
3773
3425
  const { metadata, body } = parseMessageFrontmatter(rawContent);
3774
3426
  if (options.type && metadata.type !== options.type) continue;
3775
3427
  if (options.from && metadata.from !== options.from) continue;
@@ -3923,9 +3575,9 @@ function formatKnowledgeLibraryState(state) {
3923
3575
  lines.push(`KnowledgeLibrary: ${state.basePath}
3924
3576
  `);
3925
3577
  lines.push("Global files:");
3926
- lines.push(` - ${basename4(state.contextPath)}`);
3927
- lines.push(` - ${basename4(state.architecturePath)}`);
3928
- lines.push(` - ${basename4(state.prdPath)}`);
3578
+ lines.push(` - ${basename3(state.contextPath)}`);
3579
+ lines.push(` - ${basename3(state.architecturePath)}`);
3580
+ lines.push(` - ${basename3(state.prdPath)}`);
3929
3581
  lines.push("");
3930
3582
  if (state.agents.length > 0) {
3931
3583
  lines.push(`Agents (${state.agents.length}):`);
@@ -3970,18 +3622,18 @@ function formatAgentKnowledgeState(state) {
3970
3622
 
3971
3623
  // src/index.ts
3972
3624
  function findPackageJson() {
3973
- let dir = dirname5(fileURLToPath(import.meta.url));
3974
- while (dir !== dirname5(dir)) {
3625
+ let dir = dirname6(fileURLToPath(import.meta.url));
3626
+ while (dir !== dirname6(dir)) {
3975
3627
  const pkgPath = join8(dir, "package.json");
3976
3628
  try {
3977
- const content = readFileSync5(pkgPath, "utf-8");
3629
+ const content = readFileSync6(pkgPath, "utf-8");
3978
3630
  const pkg = JSON.parse(content);
3979
3631
  if (pkg.name === "@deimoscloud/coreai") {
3980
3632
  return content;
3981
3633
  }
3982
3634
  } catch {
3983
3635
  }
3984
- dir = dirname5(dir);
3636
+ dir = dirname6(dir);
3985
3637
  }
3986
3638
  return '{"version": "unknown"}';
3987
3639
  }
@@ -4007,7 +3659,6 @@ export {
4007
3659
  StepTracker,
4008
3660
  VERSION,
4009
3661
  agentKnowledgeLibraryExists,
4010
- builtInSkills,
4011
3662
  checkDependencies,
4012
3663
  cleanupContext,
4013
3664
  compileAgent,
@@ -4021,6 +3672,7 @@ export {
4021
3672
  createContextLoader,
4022
3673
  createDegradingHandler,
4023
3674
  createFileCacheProvider,
3675
+ discoverSkills,
4024
3676
  executeWithDegradation,
4025
3677
  extractVariables2 as extractSkillVariables,
4026
3678
  extractVariables,
@@ -4036,6 +3688,7 @@ export {
4036
3688
  getAgentKnowledgeState,
4037
3689
  getConfigPath,
4038
3690
  getCoreAgentsDir,
3691
+ getCoreSkillsDir,
4039
3692
  getGlobalRegistry,
4040
3693
  getKnowledgeLibraryState,
4041
3694
  getRoleFromFilename,
@@ -4051,9 +3704,9 @@ export {
4051
3704
  loadConfig,
4052
3705
  loadConfigFromFile,
4053
3706
  loadCoreAICommands,
4054
- loadCustomTemplates,
4055
3707
  markMessageProcessed,
4056
3708
  parseAgentYaml,
3709
+ parseSkillFile,
4057
3710
  readInboxMessages,
4058
3711
  resetGlobalRegistry,
4059
3712
  resolveAgentDefinition,