@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.
- package/agents/_templates/master-context.md +76 -0
- package/agents/_templates/master-protocols.md +39 -0
- package/agents/android-engineer.md +177 -0
- package/agents/backend-engineer.md +175 -0
- package/agents/database-administrator.md +177 -0
- package/agents/devops-engineer.md +211 -0
- package/agents/{examples/engineering-manager.md → engineering-manager.md} +208 -171
- package/agents/frontend-engineer.md +175 -0
- package/agents/product-manager.md +371 -0
- package/agents/react-engineer.md +177 -0
- package/agents/react-native-engineer.md +177 -0
- package/agents/software-security-engineer.md +339 -0
- package/agents/software-solutions-architect.md +469 -0
- package/agents/sre-huawei-cloud-architect.md +177 -0
- package/agents/sre-iac-specialist.md +177 -0
- package/agents/sre-kubernetes-specialist.md +177 -0
- package/agents/sre-network-specialist.md +177 -0
- package/agents/wearos-engineer.md +177 -0
- package/dist/cli/index.js +494 -826
- package/dist/cli/index.js.map +1 -1
- package/dist/index.d.ts +75 -84
- package/dist/index.js +437 -784
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/agents/android-engineer.yaml +0 -108
- package/agents/backend-engineer.yaml +0 -106
- package/agents/database-administrator.yaml +0 -108
- package/agents/devops-engineer.yaml +0 -106
- package/agents/engineering-manager.yaml +0 -104
- package/agents/examples/android-engineer.md +0 -302
- package/agents/examples/backend-engineer.md +0 -320
- package/agents/examples/devops-engineer.md +0 -742
- package/agents/examples/frontend-engineer.md +0 -58
- package/agents/examples/product-manager.md +0 -315
- package/agents/examples/qa-engineer.md +0 -371
- package/agents/examples/security-engineer.md +0 -525
- package/agents/examples/solutions-architect.md +0 -351
- package/agents/examples/wearos-engineer.md +0 -359
- package/agents/frontend-engineer.yaml +0 -106
- package/agents/product-manager.yaml +0 -109
- package/agents/react-engineer.yaml +0 -108
- package/agents/react-native-engineer.yaml +0 -108
- package/agents/software-security-engineer.yaml +0 -108
- package/agents/software-solutions-architect.yaml +0 -107
- package/agents/sre-huawei-cloud-architect.yaml +0 -108
- package/agents/sre-iac-specialist.yaml +0 -108
- package/agents/sre-kubernetes-specialist.yaml +0 -108
- package/agents/sre-network-specialist.yaml +0 -108
- package/agents/wearos-engineer.yaml +0 -108
package/dist/cli/index.js
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
3
|
// src/cli/index.ts
|
|
4
|
-
import { join as join14, dirname as
|
|
4
|
+
import { join as join14, dirname as dirname8 } from "path";
|
|
5
5
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
6
6
|
import { Command } from "commander";
|
|
7
7
|
|
|
8
8
|
// src/index.ts
|
|
9
|
-
import { readFileSync as
|
|
10
|
-
import { dirname as
|
|
9
|
+
import { readFileSync as readFileSync7 } from "fs";
|
|
10
|
+
import { dirname as dirname6, join as join8 } from "path";
|
|
11
11
|
import { fileURLToPath } from "url";
|
|
12
12
|
|
|
13
13
|
// src/config/loader.ts
|
|
@@ -153,6 +153,61 @@ var AgentError = class extends Error {
|
|
|
153
153
|
this.name = "AgentError";
|
|
154
154
|
}
|
|
155
155
|
};
|
|
156
|
+
function extractFrontmatter(content) {
|
|
157
|
+
const match = content.match(/^---\n([\s\S]*?)\n---\n?([\s\S]*)$/);
|
|
158
|
+
if (!match) {
|
|
159
|
+
throw new AgentError(
|
|
160
|
+
"No YAML frontmatter found. Agent MD files must start with YAML frontmatter (---)",
|
|
161
|
+
"PARSE_ERROR"
|
|
162
|
+
);
|
|
163
|
+
}
|
|
164
|
+
const frontmatterYaml = match[1];
|
|
165
|
+
const body = match[2] ?? "";
|
|
166
|
+
let frontmatter;
|
|
167
|
+
try {
|
|
168
|
+
frontmatter = parseYaml2(frontmatterYaml);
|
|
169
|
+
} catch (error) {
|
|
170
|
+
const message = error instanceof Error ? error.message : "Unknown parse error";
|
|
171
|
+
throw new AgentError(`Failed to parse YAML frontmatter: ${message}`, "PARSE_ERROR", error);
|
|
172
|
+
}
|
|
173
|
+
if (!frontmatter || typeof frontmatter !== "object") {
|
|
174
|
+
throw new AgentError("Invalid frontmatter: expected an object", "PARSE_ERROR");
|
|
175
|
+
}
|
|
176
|
+
return { frontmatter, body };
|
|
177
|
+
}
|
|
178
|
+
function loadAgentFromMdFile(filePath) {
|
|
179
|
+
if (!existsSync2(filePath)) {
|
|
180
|
+
throw new AgentError(`Agent file not found: ${filePath}`, "NOT_FOUND");
|
|
181
|
+
}
|
|
182
|
+
let content;
|
|
183
|
+
try {
|
|
184
|
+
content = readFileSync2(filePath, "utf-8");
|
|
185
|
+
} catch (error) {
|
|
186
|
+
const message = error instanceof Error ? error.message : "Unknown read error";
|
|
187
|
+
throw new AgentError(`Failed to read agent file ${filePath}: ${message}`, "READ_ERROR", error);
|
|
188
|
+
}
|
|
189
|
+
const { frontmatter } = extractFrontmatter(content);
|
|
190
|
+
const role = frontmatter.name || getRoleFromFilename(filePath);
|
|
191
|
+
if (!role) {
|
|
192
|
+
throw new AgentError(
|
|
193
|
+
`Agent MD file must have a 'name' field in frontmatter or a valid filename: ${filePath}`,
|
|
194
|
+
"VALIDATION_ERROR"
|
|
195
|
+
);
|
|
196
|
+
}
|
|
197
|
+
const description = frontmatter.description || "";
|
|
198
|
+
const tools = typeof frontmatter.tools === "string" ? frontmatter.tools.split(",").map((t) => t.trim()).filter(Boolean) : void 0;
|
|
199
|
+
const definition = {
|
|
200
|
+
role,
|
|
201
|
+
type: "ic-engineer",
|
|
202
|
+
// Default, actual identity is in the MD content
|
|
203
|
+
display_name: role.split("-").map((w) => w.charAt(0).toUpperCase() + w.slice(1)).join(" "),
|
|
204
|
+
description
|
|
205
|
+
};
|
|
206
|
+
if (tools) {
|
|
207
|
+
definition.tools = tools;
|
|
208
|
+
}
|
|
209
|
+
return definition;
|
|
210
|
+
}
|
|
156
211
|
function parseAgentYaml(content, filePath) {
|
|
157
212
|
try {
|
|
158
213
|
return parseYaml2(content);
|
|
@@ -184,7 +239,7 @@ function validateAgentDefinition(agent) {
|
|
|
184
239
|
}
|
|
185
240
|
return agent;
|
|
186
241
|
}
|
|
187
|
-
function
|
|
242
|
+
function loadAgentFromYamlFile(filePath) {
|
|
188
243
|
if (!existsSync2(filePath)) {
|
|
189
244
|
throw new AgentError(`Agent file not found: ${filePath}`, "NOT_FOUND");
|
|
190
245
|
}
|
|
@@ -198,18 +253,36 @@ function loadAgentFromFile(filePath) {
|
|
|
198
253
|
const parsed = parseAgentYaml(content, filePath);
|
|
199
254
|
return validateAgentDefinition(parsed);
|
|
200
255
|
}
|
|
201
|
-
function
|
|
256
|
+
function loadAgentFromFile(filePath) {
|
|
257
|
+
const ext = extname(filePath).toLowerCase();
|
|
258
|
+
if (ext === ".md") {
|
|
259
|
+
return loadAgentFromMdFile(filePath);
|
|
260
|
+
}
|
|
261
|
+
if (ext === ".yaml" || ext === ".yml") {
|
|
262
|
+
console.warn(
|
|
263
|
+
`Warning: YAML agent definitions are deprecated and will be removed in a future version.
|
|
264
|
+
Please migrate ${basename(filePath)} to Markdown format.`
|
|
265
|
+
);
|
|
266
|
+
return loadAgentFromYamlFile(filePath);
|
|
267
|
+
}
|
|
268
|
+
throw new AgentError(
|
|
269
|
+
`Unsupported agent file format: ${ext}. Use .md (recommended) or .yaml/.yml (deprecated)`,
|
|
270
|
+
"PARSE_ERROR"
|
|
271
|
+
);
|
|
272
|
+
}
|
|
273
|
+
function listAgentFiles(dir) {
|
|
202
274
|
if (!existsSync2(dir)) {
|
|
203
275
|
return [];
|
|
204
276
|
}
|
|
205
277
|
return readdirSync(dir).filter((file) => {
|
|
278
|
+
if (file.startsWith("_")) return false;
|
|
206
279
|
const ext = extname(file).toLowerCase();
|
|
207
|
-
return ext === ".yaml" || ext === ".yml";
|
|
280
|
+
return ext === ".md" || ext === ".yaml" || ext === ".yml";
|
|
208
281
|
}).map((file) => join2(dir, file));
|
|
209
282
|
}
|
|
210
283
|
function loadAgentsFromDirectory(dir, source) {
|
|
211
284
|
const agents2 = /* @__PURE__ */ new Map();
|
|
212
|
-
const files =
|
|
285
|
+
const files = listAgentFiles(dir);
|
|
213
286
|
for (const filePath of files) {
|
|
214
287
|
try {
|
|
215
288
|
const definition = loadAgentFromFile(filePath);
|
|
@@ -225,6 +298,11 @@ function loadAgentsFromDirectory(dir, source) {
|
|
|
225
298
|
}
|
|
226
299
|
return agents2;
|
|
227
300
|
}
|
|
301
|
+
function getRoleFromFilename(filePath) {
|
|
302
|
+
const fileName = basename(filePath);
|
|
303
|
+
const ext = extname(fileName);
|
|
304
|
+
return fileName.slice(0, -ext.length);
|
|
305
|
+
}
|
|
228
306
|
|
|
229
307
|
// src/agents/resolver.ts
|
|
230
308
|
var ResolutionError = class extends Error {
|
|
@@ -363,193 +441,73 @@ function resolveAgentDefinition(agent, config, options = {}) {
|
|
|
363
441
|
}
|
|
364
442
|
|
|
365
443
|
// src/agents/compiler.ts
|
|
366
|
-
import { existsSync as existsSync3, mkdirSync, writeFileSync } from "fs";
|
|
367
|
-
import { join as join3, dirname as dirname2 } from "path";
|
|
444
|
+
import { existsSync as existsSync3, mkdirSync, readFileSync as readFileSync3, writeFileSync } from "fs";
|
|
445
|
+
import { join as join3, dirname as dirname2, extname as extname2, isAbsolute } from "path";
|
|
446
|
+
import { parse as parseYaml3, stringify as stringifyYaml } from "yaml";
|
|
368
447
|
function buildAgentTools(agent, mcpServers) {
|
|
369
448
|
const tools = agent.tools ? [...agent.tools] : [...DEFAULT_AGENT_TOOLS];
|
|
370
449
|
if (mcpServers && mcpServers.length > 0) {
|
|
371
450
|
for (const server of mcpServers) {
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
return tools.join(", ");
|
|
376
|
-
}
|
|
377
|
-
function generateKnowledgeLibrarySection(agent, lines) {
|
|
378
|
-
const kl = agent.knowledge_library;
|
|
379
|
-
if (!kl) return;
|
|
380
|
-
lines.push("## Knowledge Library Structure");
|
|
381
|
-
lines.push("");
|
|
382
|
-
if (kl.shared) {
|
|
383
|
-
lines.push("### Shared Context (Root - All Agents)");
|
|
384
|
-
lines.push("```");
|
|
385
|
-
lines.push("/KnowledgeLibrary/");
|
|
386
|
-
if (kl.shared.context) {
|
|
387
|
-
const filename = kl.shared.context.split("/").pop() ?? "context.txt";
|
|
388
|
-
lines.push(`\u251C\u2500\u2500 ${filename}`);
|
|
389
|
-
}
|
|
390
|
-
if (kl.shared.architecture) {
|
|
391
|
-
const filename = kl.shared.architecture.split("/").pop() ?? "architecture.txt";
|
|
392
|
-
lines.push(`\u251C\u2500\u2500 ${filename}`);
|
|
393
|
-
}
|
|
394
|
-
if (kl.shared.prd) {
|
|
395
|
-
const filename = kl.shared.prd.split("/").pop() ?? "prd.txt";
|
|
396
|
-
lines.push(`\u2514\u2500\u2500 ${filename}`);
|
|
397
|
-
}
|
|
398
|
-
lines.push("```");
|
|
399
|
-
if (kl.shared.remote && kl.shared.remote.length > 0) {
|
|
400
|
-
lines.push("");
|
|
401
|
-
lines.push("**Remote Documentation:**");
|
|
402
|
-
for (const remote of kl.shared.remote) {
|
|
403
|
-
lines.push(`- ${remote}`);
|
|
404
|
-
}
|
|
405
|
-
}
|
|
406
|
-
lines.push("");
|
|
407
|
-
}
|
|
408
|
-
if (kl.personal) {
|
|
409
|
-
lines.push(`### Personal Context (${agent.role})`);
|
|
410
|
-
lines.push("```");
|
|
411
|
-
lines.push(`/KnowledgeLibrary/${agent.role}/`);
|
|
412
|
-
if (kl.personal.context) {
|
|
413
|
-
lines.push("\u251C\u2500\u2500 context/");
|
|
414
|
-
lines.push("\u2502 \u2514\u2500\u2500 current.txt # Your current state, priorities, decisions, issues");
|
|
415
|
-
}
|
|
416
|
-
if (kl.personal.history) {
|
|
417
|
-
lines.push("\u251C\u2500\u2500 history/");
|
|
418
|
-
lines.push("\u2502 \u2514\u2500\u2500 [archived context files, timestamped]");
|
|
419
|
-
}
|
|
420
|
-
if (kl.personal.inbox) {
|
|
421
|
-
lines.push("\u251C\u2500\u2500 inbox/");
|
|
422
|
-
lines.push("\u2502 \u2514\u2500\u2500 YYYYMMDD_HHMM-[agent-name]-[topic].txt # Messages from other agents");
|
|
423
|
-
}
|
|
424
|
-
if (kl.personal.outbox) {
|
|
425
|
-
lines.push("\u251C\u2500\u2500 outbox/");
|
|
426
|
-
lines.push("\u2502 \u2514\u2500\u2500 YYYYMMDD_HHMM-to-[agent-name]-[topic].txt # Copies of sent messages");
|
|
427
|
-
}
|
|
428
|
-
if (kl.personal.tech) {
|
|
429
|
-
lines.push("\u251C\u2500\u2500 tech/");
|
|
430
|
-
lines.push("\u2502 \u2514\u2500\u2500 [Technical docs, implementation details, working drafts]");
|
|
431
|
-
}
|
|
432
|
-
if (kl.personal.control) {
|
|
433
|
-
lines.push("\u2514\u2500\u2500 control/");
|
|
434
|
-
if (kl.personal.control.objectives) {
|
|
435
|
-
lines.push(" \u251C\u2500\u2500 objectives.txt # Current job objectives and goals");
|
|
436
|
-
}
|
|
437
|
-
if (kl.personal.control.decisions) {
|
|
438
|
-
lines.push(" \u251C\u2500\u2500 decisions.txt # Log of key decisions with rationale");
|
|
439
|
-
}
|
|
440
|
-
if (kl.personal.control.dependencies) {
|
|
441
|
-
lines.push(" \u251C\u2500\u2500 dependencies.txt # Dependencies on other jobs");
|
|
442
|
-
}
|
|
443
|
-
if (kl.personal.control.index) {
|
|
444
|
-
lines.push(" \u2514\u2500\u2500 index.txt # Optional index of files/folders");
|
|
451
|
+
const mcpTool = `mcp__${server}`;
|
|
452
|
+
if (!tools.includes(mcpTool)) {
|
|
453
|
+
tools.push(mcpTool);
|
|
445
454
|
}
|
|
446
455
|
}
|
|
447
|
-
lines.push("```");
|
|
448
|
-
lines.push("");
|
|
449
|
-
}
|
|
450
|
-
lines.push("---");
|
|
451
|
-
lines.push("");
|
|
452
|
-
}
|
|
453
|
-
function generateCommunicationSection(agent, lines) {
|
|
454
|
-
const comm = agent.communication;
|
|
455
|
-
if (!comm) return;
|
|
456
|
-
lines.push("## Communication");
|
|
457
|
-
lines.push("");
|
|
458
|
-
if (comm.inbox) {
|
|
459
|
-
lines.push(`**Inbox:** \`${comm.inbox}\``);
|
|
460
|
-
}
|
|
461
|
-
if (comm.outbox) {
|
|
462
|
-
lines.push(`**Outbox:** \`${comm.outbox}\``);
|
|
463
|
-
}
|
|
464
|
-
lines.push("");
|
|
465
|
-
if (comm.message_format || comm.outbox_format || comm.processed_dir) {
|
|
466
|
-
lines.push("### Message Conventions");
|
|
467
|
-
lines.push("");
|
|
468
|
-
if (comm.message_format) {
|
|
469
|
-
lines.push(`- **Inbox message naming:** \`${comm.message_format}\``);
|
|
470
|
-
}
|
|
471
|
-
if (comm.outbox_format) {
|
|
472
|
-
lines.push(`- **Outbox message naming:** \`${comm.outbox_format}\``);
|
|
473
|
-
}
|
|
474
|
-
if (comm.processed_dir) {
|
|
475
|
-
lines.push(`- **Processed messages:** Move handled inbox messages to \`${comm.processed_dir}\``);
|
|
476
|
-
}
|
|
477
|
-
lines.push("");
|
|
478
456
|
}
|
|
457
|
+
return tools.join(", ");
|
|
479
458
|
}
|
|
480
|
-
function
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
lines.push("");
|
|
494
|
-
for (const step of protocols.startup.first_session) {
|
|
495
|
-
lines.push(`- [ ] ${step}`);
|
|
496
|
-
}
|
|
497
|
-
lines.push("");
|
|
498
|
-
lines.push('Acknowledge: "Startup protocol complete. Full context loaded."');
|
|
499
|
-
lines.push("");
|
|
500
|
-
}
|
|
501
|
-
if (protocols.startup.subsequent && protocols.startup.subsequent.length > 0) {
|
|
502
|
-
lines.push("**If you have ALREADY loaded context in this session** (subsequent invocation):");
|
|
503
|
-
lines.push("");
|
|
504
|
-
for (const step of protocols.startup.subsequent) {
|
|
505
|
-
lines.push(`- [ ] ${step}`);
|
|
506
|
-
}
|
|
507
|
-
lines.push("");
|
|
508
|
-
lines.push('Acknowledge: "Context already loaded. Checked inbox for new messages."');
|
|
509
|
-
lines.push("");
|
|
510
|
-
}
|
|
511
|
-
lines.push("Then proceed with the task.");
|
|
512
|
-
lines.push("");
|
|
513
|
-
lines.push("---");
|
|
514
|
-
lines.push("");
|
|
459
|
+
function processIncludes(template, templateDir, depth = 0, maxDepth = 3) {
|
|
460
|
+
if (depth > maxDepth) {
|
|
461
|
+
throw new Error(`Include depth exceeded maximum of ${maxDepth}`);
|
|
462
|
+
}
|
|
463
|
+
const includePattern = /<!--\s*include:\s*(\S+)\s*-->/g;
|
|
464
|
+
return template.replace(includePattern, (_match, includePath) => {
|
|
465
|
+
const resolvedPath = isAbsolute(includePath) ? includePath : join3(templateDir, includePath);
|
|
466
|
+
if (!existsSync3(resolvedPath)) {
|
|
467
|
+
throw new Error(`Include file not found: ${includePath} (resolved to ${resolvedPath})`);
|
|
468
|
+
}
|
|
469
|
+
const includedContent = readFileSync3(resolvedPath, "utf-8");
|
|
470
|
+
return processIncludes(includedContent, dirname2(resolvedPath), depth + 1, maxDepth);
|
|
471
|
+
});
|
|
515
472
|
}
|
|
516
|
-
function
|
|
517
|
-
const
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
473
|
+
function processAgentTemplate(templatePath, agent, config, mcpServers) {
|
|
474
|
+
const template = readFileSync3(templatePath, "utf-8");
|
|
475
|
+
const templateDir = dirname2(templatePath);
|
|
476
|
+
const expandedTemplate = processIncludes(template, templateDir);
|
|
477
|
+
const earlyMatch = expandedTemplate.match(/^---\n([\s\S]*?)\n---\n?([\s\S]*)$/);
|
|
478
|
+
if (!earlyMatch) {
|
|
479
|
+
throw new Error(`Invalid markdown format in ${templatePath}: no frontmatter found`);
|
|
480
|
+
}
|
|
481
|
+
const earlyFrontmatter = parseYaml3(earlyMatch[1]);
|
|
482
|
+
const reservedKeys = /* @__PURE__ */ new Set(["name", "description", "tools"]);
|
|
483
|
+
const extendedAgent = { ...agent };
|
|
484
|
+
for (const [key, value] of Object.entries(earlyFrontmatter)) {
|
|
485
|
+
if (!reservedKeys.has(key) && !(key in extendedAgent)) {
|
|
486
|
+
extendedAgent[key] = value;
|
|
487
|
+
}
|
|
488
|
+
}
|
|
489
|
+
const context = { agent: extendedAgent };
|
|
490
|
+
if (config) {
|
|
491
|
+
context.config = config;
|
|
526
492
|
}
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
}
|
|
532
|
-
function generateLegacyContextSourcesSection(agent, lines) {
|
|
533
|
-
if (!agent.context_sources) return;
|
|
534
|
-
if (agent.knowledge_library) return;
|
|
535
|
-
lines.push("## Context Sources");
|
|
536
|
-
lines.push("");
|
|
537
|
-
if (agent.context_sources.shared && agent.context_sources.shared.length > 0) {
|
|
538
|
-
lines.push("### Shared");
|
|
539
|
-
lines.push("");
|
|
540
|
-
for (const source of agent.context_sources.shared) {
|
|
541
|
-
lines.push(`- ${source}`);
|
|
542
|
-
}
|
|
543
|
-
lines.push("");
|
|
493
|
+
const resolved = resolveString(expandedTemplate, context);
|
|
494
|
+
const frontmatterMatch = resolved.match(/^---\n([\s\S]*?)\n---\n?([\s\S]*)$/);
|
|
495
|
+
if (!frontmatterMatch) {
|
|
496
|
+
throw new Error(`Invalid markdown format after resolution in ${templatePath}`);
|
|
544
497
|
}
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
498
|
+
const frontmatterYaml = frontmatterMatch[1];
|
|
499
|
+
const body = frontmatterMatch[2] ?? "";
|
|
500
|
+
const frontmatter = parseYaml3(frontmatterYaml);
|
|
501
|
+
const tools = buildAgentTools(agent, mcpServers);
|
|
502
|
+
frontmatter.tools = tools;
|
|
503
|
+
if (typeof frontmatter.description === "string") {
|
|
504
|
+
frontmatter.description = frontmatter.description.replace(/\n/g, " ").trim();
|
|
552
505
|
}
|
|
506
|
+
const updatedFrontmatter = stringifyYaml(frontmatter, { lineWidth: 0 }).trim();
|
|
507
|
+
return `---
|
|
508
|
+
${updatedFrontmatter}
|
|
509
|
+
---
|
|
510
|
+
${body}`;
|
|
553
511
|
}
|
|
554
512
|
function generateAgentMarkdown(agent, mcpServers) {
|
|
555
513
|
const lines = [];
|
|
@@ -572,8 +530,8 @@ function generateAgentMarkdown(agent, mcpServers) {
|
|
|
572
530
|
if (agent.responsibilities && agent.responsibilities.length > 0) {
|
|
573
531
|
lines.push("## Responsibilities");
|
|
574
532
|
lines.push("");
|
|
575
|
-
for (const
|
|
576
|
-
lines.push(`- ${
|
|
533
|
+
for (const r of agent.responsibilities) {
|
|
534
|
+
lines.push(`- ${r}`);
|
|
577
535
|
}
|
|
578
536
|
lines.push("");
|
|
579
537
|
}
|
|
@@ -591,12 +549,12 @@ function generateAgentMarkdown(agent, mcpServers) {
|
|
|
591
549
|
if (agent.expertise.tech_stack) {
|
|
592
550
|
lines.push("### Tech Stack");
|
|
593
551
|
lines.push("");
|
|
594
|
-
const
|
|
595
|
-
if (typeof
|
|
596
|
-
lines.push(
|
|
597
|
-
} else if (typeof
|
|
552
|
+
const ts = agent.expertise.tech_stack;
|
|
553
|
+
if (typeof ts === "string") {
|
|
554
|
+
lines.push(ts);
|
|
555
|
+
} else if (typeof ts === "object") {
|
|
598
556
|
lines.push("```json");
|
|
599
|
-
lines.push(JSON.stringify(
|
|
557
|
+
lines.push(JSON.stringify(ts, null, 2));
|
|
600
558
|
lines.push("```");
|
|
601
559
|
}
|
|
602
560
|
lines.push("");
|
|
@@ -615,7 +573,7 @@ function generateAgentMarkdown(agent, mcpServers) {
|
|
|
615
573
|
lines.push("");
|
|
616
574
|
for (const [category, items] of Object.entries(agent.principles)) {
|
|
617
575
|
if (items && Array.isArray(items) && items.length > 0) {
|
|
618
|
-
const title =
|
|
576
|
+
const title = category.replace(/[_-]/g, " ").replace(/\b\w/g, (c) => c.toUpperCase());
|
|
619
577
|
lines.push(`### ${title}`);
|
|
620
578
|
lines.push("");
|
|
621
579
|
for (const item of items) {
|
|
@@ -646,21 +604,161 @@ function generateAgentMarkdown(agent, mcpServers) {
|
|
|
646
604
|
lines.push("");
|
|
647
605
|
}
|
|
648
606
|
}
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
607
|
+
if (agent.knowledge_library) {
|
|
608
|
+
generateKnowledgeLibrarySection(agent, lines);
|
|
609
|
+
}
|
|
610
|
+
if (agent.communication) {
|
|
611
|
+
generateCommunicationSection(agent, lines);
|
|
612
|
+
}
|
|
613
|
+
if (agent.protocols?.startup) {
|
|
614
|
+
generateStartupProtocolSection(agent, lines);
|
|
615
|
+
}
|
|
616
|
+
if (agent.protocols?.completion) {
|
|
617
|
+
generateCompletionProtocolSection(agent, lines);
|
|
618
|
+
}
|
|
619
|
+
if (agent.context_sources && !agent.knowledge_library) {
|
|
620
|
+
lines.push("## Context Sources");
|
|
621
|
+
lines.push("");
|
|
622
|
+
if (agent.context_sources.shared?.length) {
|
|
623
|
+
lines.push("### Shared");
|
|
624
|
+
lines.push("");
|
|
625
|
+
for (const s of agent.context_sources.shared) lines.push(`- ${s}`);
|
|
626
|
+
lines.push("");
|
|
627
|
+
}
|
|
628
|
+
if (agent.context_sources.personal?.length) {
|
|
629
|
+
lines.push("### Personal");
|
|
630
|
+
lines.push("");
|
|
631
|
+
for (const p of agent.context_sources.personal) lines.push(`- ${p}`);
|
|
632
|
+
lines.push("");
|
|
633
|
+
}
|
|
634
|
+
}
|
|
654
635
|
lines.push("---");
|
|
655
636
|
lines.push("");
|
|
656
637
|
lines.push("*Generated by CoreAI*");
|
|
657
638
|
lines.push("");
|
|
658
639
|
return lines.join("\n");
|
|
659
640
|
}
|
|
660
|
-
function
|
|
661
|
-
|
|
641
|
+
function generateKnowledgeLibrarySection(agent, lines) {
|
|
642
|
+
const kl = agent.knowledge_library;
|
|
643
|
+
if (!kl) return;
|
|
644
|
+
lines.push("## Knowledge Library Structure");
|
|
645
|
+
lines.push("");
|
|
646
|
+
if (kl.shared) {
|
|
647
|
+
lines.push("### Shared Context (Root - All Agents)");
|
|
648
|
+
lines.push("```");
|
|
649
|
+
lines.push("/KnowledgeLibrary/");
|
|
650
|
+
if (kl.shared.context) lines.push(`\u251C\u2500\u2500 ${kl.shared.context.split("/").pop()}`);
|
|
651
|
+
if (kl.shared.architecture) lines.push(`\u251C\u2500\u2500 ${kl.shared.architecture.split("/").pop()}`);
|
|
652
|
+
if (kl.shared.prd) lines.push(`\u2514\u2500\u2500 ${kl.shared.prd.split("/").pop()}`);
|
|
653
|
+
lines.push("```");
|
|
654
|
+
if (kl.shared.remote?.length) {
|
|
655
|
+
lines.push("");
|
|
656
|
+
lines.push("**Remote Documentation:**");
|
|
657
|
+
for (const r of kl.shared.remote) lines.push(`- ${r}`);
|
|
658
|
+
}
|
|
659
|
+
lines.push("");
|
|
660
|
+
}
|
|
661
|
+
if (kl.personal) {
|
|
662
|
+
lines.push(`### Personal Context (${agent.role})`);
|
|
663
|
+
lines.push("```");
|
|
664
|
+
lines.push(`/KnowledgeLibrary/${agent.role}/`);
|
|
665
|
+
if (kl.personal.context) {
|
|
666
|
+
lines.push("\u251C\u2500\u2500 context/");
|
|
667
|
+
lines.push("\u2502 \u2514\u2500\u2500 current.txt");
|
|
668
|
+
}
|
|
669
|
+
if (kl.personal.history) {
|
|
670
|
+
lines.push("\u251C\u2500\u2500 history/");
|
|
671
|
+
}
|
|
672
|
+
if (kl.personal.inbox) {
|
|
673
|
+
lines.push("\u251C\u2500\u2500 inbox/");
|
|
674
|
+
}
|
|
675
|
+
if (kl.personal.outbox) {
|
|
676
|
+
lines.push("\u251C\u2500\u2500 outbox/");
|
|
677
|
+
}
|
|
678
|
+
if (kl.personal.tech) {
|
|
679
|
+
lines.push("\u251C\u2500\u2500 tech/");
|
|
680
|
+
}
|
|
681
|
+
if (kl.personal.control) {
|
|
682
|
+
lines.push("\u2514\u2500\u2500 control/");
|
|
683
|
+
if (kl.personal.control.objectives) lines.push(" \u251C\u2500\u2500 objectives.txt");
|
|
684
|
+
if (kl.personal.control.decisions) lines.push(" \u251C\u2500\u2500 decisions.txt");
|
|
685
|
+
if (kl.personal.control.dependencies) lines.push(" \u251C\u2500\u2500 dependencies.txt");
|
|
686
|
+
if (kl.personal.control.index) lines.push(" \u2514\u2500\u2500 index.txt");
|
|
687
|
+
}
|
|
688
|
+
lines.push("```");
|
|
689
|
+
lines.push("");
|
|
690
|
+
}
|
|
691
|
+
lines.push("---");
|
|
692
|
+
lines.push("");
|
|
693
|
+
}
|
|
694
|
+
function generateCommunicationSection(agent, lines) {
|
|
695
|
+
const comm = agent.communication;
|
|
696
|
+
if (!comm) return;
|
|
697
|
+
lines.push("## Communication");
|
|
698
|
+
lines.push("");
|
|
699
|
+
if (comm.inbox) lines.push(`**Inbox:** \`${comm.inbox}\``);
|
|
700
|
+
if (comm.outbox) lines.push(`**Outbox:** \`${comm.outbox}\``);
|
|
701
|
+
lines.push("");
|
|
702
|
+
if (comm.message_format || comm.outbox_format || comm.processed_dir) {
|
|
703
|
+
lines.push("### Message Conventions");
|
|
704
|
+
lines.push("");
|
|
705
|
+
if (comm.message_format) lines.push(`- **Inbox message naming:** \`${comm.message_format}\``);
|
|
706
|
+
if (comm.outbox_format) lines.push(`- **Outbox message naming:** \`${comm.outbox_format}\``);
|
|
707
|
+
if (comm.processed_dir) lines.push(`- **Processed messages:** Move handled inbox messages to \`${comm.processed_dir}\``);
|
|
708
|
+
lines.push("");
|
|
709
|
+
}
|
|
710
|
+
}
|
|
711
|
+
function generateStartupProtocolSection(agent, lines) {
|
|
712
|
+
const p = agent.protocols;
|
|
713
|
+
if (!p?.startup) return;
|
|
714
|
+
lines.push("## When Invoked");
|
|
715
|
+
lines.push("");
|
|
716
|
+
lines.push("> **MANDATORY STARTUP PROTOCOL** - Execute before proceeding with any task.");
|
|
717
|
+
lines.push("");
|
|
718
|
+
lines.push("### Session Context Check");
|
|
719
|
+
lines.push("");
|
|
720
|
+
if (p.startup.first_session?.length) {
|
|
721
|
+
lines.push("**If this is your FIRST invocation in this session:**");
|
|
722
|
+
lines.push("");
|
|
723
|
+
for (const s of p.startup.first_session) lines.push(`- [ ] ${s}`);
|
|
724
|
+
lines.push("");
|
|
725
|
+
lines.push('Acknowledge: "Startup protocol complete. Full context loaded."');
|
|
726
|
+
lines.push("");
|
|
727
|
+
}
|
|
728
|
+
if (p.startup.subsequent?.length) {
|
|
729
|
+
lines.push("**If you have ALREADY loaded context in this session:**");
|
|
730
|
+
lines.push("");
|
|
731
|
+
for (const s of p.startup.subsequent) lines.push(`- [ ] ${s}`);
|
|
732
|
+
lines.push("");
|
|
733
|
+
lines.push('Acknowledge: "Context already loaded. Checked inbox for new messages."');
|
|
734
|
+
lines.push("");
|
|
735
|
+
}
|
|
736
|
+
lines.push("Then proceed with the task.");
|
|
737
|
+
lines.push("");
|
|
738
|
+
lines.push("---");
|
|
739
|
+
lines.push("");
|
|
740
|
+
}
|
|
741
|
+
function generateCompletionProtocolSection(agent, lines) {
|
|
742
|
+
const p = agent.protocols;
|
|
743
|
+
if (!p?.completion?.length) return;
|
|
744
|
+
lines.push("## Before Finishing");
|
|
745
|
+
lines.push("");
|
|
746
|
+
lines.push("> **MANDATORY COMPLETION PROTOCOL** - Execute ALL steps before ending any task.");
|
|
747
|
+
lines.push("");
|
|
748
|
+
for (let i = 0; i < p.completion.length; i++) {
|
|
749
|
+
lines.push(`### ${i + 1}. ${p.completion[i]}`);
|
|
750
|
+
lines.push("");
|
|
751
|
+
}
|
|
752
|
+
lines.push('Acknowledge: "Completion protocol finished. Context updated."');
|
|
753
|
+
lines.push("");
|
|
754
|
+
lines.push("---");
|
|
755
|
+
lines.push("");
|
|
662
756
|
}
|
|
663
|
-
function compileAgent(agent, config, mcpServers) {
|
|
757
|
+
function compileAgent(agent, filePath, config, mcpServers) {
|
|
758
|
+
const ext = extname2(filePath).toLowerCase();
|
|
759
|
+
if (ext === ".md") {
|
|
760
|
+
return processAgentTemplate(filePath, agent, config, mcpServers);
|
|
761
|
+
}
|
|
664
762
|
const resolved = resolveAgentDefinition(agent, config);
|
|
665
763
|
return generateAgentMarkdown(resolved, mcpServers);
|
|
666
764
|
}
|
|
@@ -720,7 +818,12 @@ function compileAgents(config, options = {}) {
|
|
|
720
818
|
continue;
|
|
721
819
|
}
|
|
722
820
|
try {
|
|
723
|
-
const markdown = compileAgent(
|
|
821
|
+
const markdown = compileAgent(
|
|
822
|
+
metadata.definition,
|
|
823
|
+
metadata.filePath,
|
|
824
|
+
config,
|
|
825
|
+
options.mcpServers
|
|
826
|
+
);
|
|
724
827
|
const outputPath = join3(outputDir, `${role}.md`);
|
|
725
828
|
writeFileSync(outputPath, markdown, "utf-8");
|
|
726
829
|
result.compiled.push({
|
|
@@ -764,7 +867,7 @@ import { Client } from "@modelcontextprotocol/sdk/client/index.js";
|
|
|
764
867
|
import { StdioClientTransport } from "@modelcontextprotocol/sdk/client/stdio.js";
|
|
765
868
|
|
|
766
869
|
// src/adapters/mcp/discovery.ts
|
|
767
|
-
import { existsSync as existsSync4, readFileSync as
|
|
870
|
+
import { existsSync as existsSync4, readFileSync as readFileSync4 } from "fs";
|
|
768
871
|
import { join as join4, dirname as dirname3 } from "path";
|
|
769
872
|
import { homedir } from "os";
|
|
770
873
|
var CONFIG_FILENAMES = ["mcp.json", ".mcp.json", "claude_desktop_config.json"];
|
|
@@ -813,7 +916,7 @@ function loadServersFromFile(filePath) {
|
|
|
813
916
|
if (!existsSync4(filePath)) {
|
|
814
917
|
throw new McpError(`Config file not found: ${filePath}`, "invalid_config");
|
|
815
918
|
}
|
|
816
|
-
const content =
|
|
919
|
+
const content = readFileSync4(filePath, "utf-8");
|
|
817
920
|
let config;
|
|
818
921
|
try {
|
|
819
922
|
config = JSON.parse(content);
|
|
@@ -1800,470 +1903,124 @@ var CacheManager = class {
|
|
|
1800
1903
|
};
|
|
1801
1904
|
|
|
1802
1905
|
// src/skills/generator.ts
|
|
1803
|
-
import { existsSync as existsSync5, mkdirSync as mkdirSync2, writeFileSync as writeFileSync2, readFileSync as
|
|
1804
|
-
import { join as join6,
|
|
1805
|
-
|
|
1806
|
-
|
|
1807
|
-
|
|
1808
|
-
|
|
1809
|
-
|
|
1810
|
-
|
|
1811
|
-
|
|
1812
|
-
|
|
1813
|
-
|
|
1814
|
-
|
|
1815
|
-
|
|
1816
|
-
|
|
1817
|
-
|
|
1818
|
-
|
|
1819
|
-
|
|
1820
|
-
|
|
1821
|
-
|
|
1822
|
-
|
|
1823
|
-
|
|
1824
|
-
|
|
1825
|
-
|
|
1826
|
-
|
|
1827
|
-
|
|
1828
|
-
|
|
1829
|
-
|
|
1830
|
-
|
|
1831
|
-
|
|
1832
|
-
|
|
1833
|
-
|
|
1834
|
-
|
|
1835
|
-
|
|
1836
|
-
|
|
1837
|
-
|
|
1838
|
-
|
|
1839
|
-
|
|
1840
|
-
}
|
|
1841
|
-
|
|
1842
|
-
|
|
1843
|
-
|
|
1844
|
-
|
|
1845
|
-
|
|
1846
|
-
|
|
1847
|
-
|
|
1848
|
-
|
|
1849
|
-
|
|
1850
|
-
|
|
1851
|
-
|
|
1852
|
-
|
|
1853
|
-
|
|
1854
|
-
|
|
1855
|
-
|
|
1856
|
-
|
|
1857
|
-
|
|
1858
|
-
|
|
1859
|
-
|
|
1860
|
-
|
|
1861
|
-
|
|
1862
|
-
|
|
1863
|
-
|
|
1864
|
-
|
|
1865
|
-
|
|
1866
|
-
|
|
1867
|
-
|
|
1868
|
-
|
|
1869
|
-
|
|
1870
|
-
|
|
1871
|
-
|
|
1872
|
-
|
|
1873
|
-
|
|
1874
|
-
|
|
1875
|
-
|
|
1876
|
-
|
|
1877
|
-
|
|
1878
|
-
|
|
1879
|
-
|
|
1880
|
-
|
|
1881
|
-
|
|
1882
|
-
|
|
1883
|
-
|
|
1884
|
-
|
|
1885
|
-
|
|
1886
|
-
|
|
1887
|
-
|
|
1888
|
-
|
|
1889
|
-
|
|
1890
|
-
|
|
1891
|
-
|
|
1892
|
-
|
|
1893
|
-
|
|
1894
|
-
|
|
1895
|
-
|
|
1896
|
-
|
|
1897
|
-
|
|
1898
|
-
|
|
1899
|
-
|
|
1900
|
-
|
|
1901
|
-
|
|
1902
|
-
|
|
1903
|
-
|
|
1904
|
-
|
|
1905
|
-
|
|
1906
|
-
|
|
1907
|
-
|
|
1908
|
-
|
|
1909
|
-
|
|
1910
|
-
|
|
1911
|
-
|
|
1912
|
-
|
|
1913
|
-
|
|
1914
|
-
|
|
1915
|
-
|
|
1916
|
-
|
|
1917
|
-
|
|
1918
|
-
|
|
1919
|
-
|
|
1920
|
-
|
|
1921
|
-
## Quality Gates
|
|
1922
|
-
|
|
1923
|
-
Run these checks before committing:
|
|
1924
|
-
|
|
1925
|
-
1. **Lint**: \`{{LINT_CMD}}\`
|
|
1926
|
-
2. **Tests**: \`{{TEST_CMD}}\`
|
|
1927
|
-
3. **Build**: \`{{BUILD_CMD}}\`
|
|
1928
|
-
|
|
1929
|
-
## Instructions
|
|
1930
|
-
|
|
1931
|
-
1. Stage the relevant files with \`git add\`
|
|
1932
|
-
2. Run all quality gate commands
|
|
1933
|
-
3. If any gate fails:
|
|
1934
|
-
- Fix the issues
|
|
1935
|
-
- Re-run the failed gate
|
|
1936
|
-
- Continue only when all pass
|
|
1937
|
-
4. Create the commit with the provided message
|
|
1938
|
-
5. Format: Include ticket reference if applicable
|
|
1939
|
-
|
|
1940
|
-
## Commit Message Format
|
|
1941
|
-
|
|
1942
|
-
\`\`\`
|
|
1943
|
-
<type>(<scope>): <description>
|
|
1944
|
-
|
|
1945
|
-
[optional body]
|
|
1946
|
-
|
|
1947
|
-
[optional footer]
|
|
1948
|
-
\`\`\`
|
|
1949
|
-
|
|
1950
|
-
Types: feat, fix, docs, style, refactor, test, chore
|
|
1951
|
-
|
|
1952
|
-
## Fallbacks
|
|
1953
|
-
|
|
1954
|
-
If quality gate commands are not configured:
|
|
1955
|
-
- Ask the user what commands to run
|
|
1956
|
-
- Or skip gates with user confirmation
|
|
1957
|
-
`
|
|
1958
|
-
};
|
|
1959
|
-
var prCreateSkill = {
|
|
1960
|
-
name: "pr-create",
|
|
1961
|
-
description: "Create a pull request with proper format",
|
|
1962
|
-
argumentHint: "[branch-name]",
|
|
1963
|
-
category: "core",
|
|
1964
|
-
dependencies: [{ type: "git", required: true, description: "For PR creation" }],
|
|
1965
|
-
content: `---
|
|
1966
|
-
description: Create a pull request with proper format
|
|
1967
|
-
argument-hint: [branch-name]
|
|
1968
|
-
requires: [git]
|
|
1969
|
-
---
|
|
1970
|
-
|
|
1971
|
-
# Create Pull Request
|
|
1972
|
-
|
|
1973
|
-
Create a well-formatted pull request for the current branch.
|
|
1974
|
-
|
|
1975
|
-
## Instructions
|
|
1976
|
-
|
|
1977
|
-
1. Ensure all changes are committed
|
|
1978
|
-
2. Push the branch to remote
|
|
1979
|
-
3. Create PR with proper format:
|
|
1980
|
-
|
|
1981
|
-
\`\`\`markdown
|
|
1982
|
-
## Summary
|
|
1983
|
-
<Brief description of changes>
|
|
1984
|
-
|
|
1985
|
-
## Changes
|
|
1986
|
-
- <Change 1>
|
|
1987
|
-
- <Change 2>
|
|
1988
|
-
|
|
1989
|
-
## Test Plan
|
|
1990
|
-
- [ ] <Test case 1>
|
|
1991
|
-
- [ ] <Test case 2>
|
|
1992
|
-
|
|
1993
|
-
## Related Issues
|
|
1994
|
-
Closes {{JIRA_PROJECT}}-XXX
|
|
1995
|
-
\`\`\`
|
|
1996
|
-
|
|
1997
|
-
4. Request reviewers if specified
|
|
1998
|
-
|
|
1999
|
-
## Using GitHub CLI
|
|
2000
|
-
|
|
2001
|
-
\`\`\`bash
|
|
2002
|
-
gh pr create --title "<title>" --body "<body>"
|
|
2003
|
-
\`\`\`
|
|
2004
|
-
|
|
2005
|
-
## Output
|
|
2006
|
-
|
|
2007
|
-
Provide the PR URL and summary of what was created.
|
|
2008
|
-
`
|
|
2009
|
-
};
|
|
2010
|
-
var reviewSkill = {
|
|
2011
|
-
name: "review",
|
|
2012
|
-
description: "Request or perform a code review",
|
|
2013
|
-
argumentHint: "<pr-number-or-url>",
|
|
2014
|
-
category: "core",
|
|
2015
|
-
dependencies: [{ type: "git", required: true, description: "For PR review" }],
|
|
2016
|
-
content: `---
|
|
2017
|
-
description: Request or perform a code review
|
|
2018
|
-
argument-hint: <pr-number-or-url>
|
|
2019
|
-
requires: [git]
|
|
2020
|
-
---
|
|
2021
|
-
|
|
2022
|
-
# Code Review
|
|
2023
|
-
|
|
2024
|
-
Review a pull request or delegate review to a specialist.
|
|
2025
|
-
|
|
2026
|
-
## Instructions
|
|
2027
|
-
|
|
2028
|
-
### If you are reviewing:
|
|
2029
|
-
|
|
2030
|
-
1. Fetch the PR details and diff
|
|
2031
|
-
2. Review for:
|
|
2032
|
-
- Code quality and style
|
|
2033
|
-
- Logic errors or bugs
|
|
2034
|
-
- Security concerns
|
|
2035
|
-
- Test coverage
|
|
2036
|
-
- Documentation
|
|
2037
|
-
3. Provide feedback with specific line references
|
|
2038
|
-
4. Approve, request changes, or comment
|
|
2039
|
-
|
|
2040
|
-
### If delegating to a reviewer:
|
|
2041
|
-
|
|
2042
|
-
1. Identify the appropriate reviewer based on the changes
|
|
2043
|
-
2. Create a review request message in their inbox
|
|
2044
|
-
3. Include PR link and context
|
|
2045
|
-
|
|
2046
|
-
## Review Checklist
|
|
2047
|
-
|
|
2048
|
-
- [ ] Code follows project conventions
|
|
2049
|
-
- [ ] No obvious bugs or edge cases
|
|
2050
|
-
- [ ] Tests cover the changes
|
|
2051
|
-
- [ ] Documentation updated if needed
|
|
2052
|
-
- [ ] No security vulnerabilities
|
|
2053
|
-
|
|
2054
|
-
## Output
|
|
2055
|
-
|
|
2056
|
-
Provide review summary with actionable feedback.
|
|
2057
|
-
`
|
|
2058
|
-
};
|
|
2059
|
-
var sprintStatusSkill = {
|
|
2060
|
-
name: "sprint-status",
|
|
2061
|
-
description: "Get current sprint status and progress",
|
|
2062
|
-
category: "optional",
|
|
2063
|
-
dependencies: [{ type: "issue_tracker", required: true, description: "For sprint data" }],
|
|
2064
|
-
content: `---
|
|
2065
|
-
description: Get current sprint status and progress
|
|
2066
|
-
requires: [issue_tracker]
|
|
2067
|
-
---
|
|
2068
|
-
|
|
2069
|
-
# Sprint Status
|
|
2070
|
-
|
|
2071
|
-
Get the current sprint status and team progress.
|
|
2072
|
-
|
|
2073
|
-
## Instructions
|
|
2074
|
-
|
|
2075
|
-
1. Query the active sprint for project {{JIRA_PROJECT}}
|
|
2076
|
-
2. Gather metrics:
|
|
2077
|
-
- Total story points committed
|
|
2078
|
-
- Points completed
|
|
2079
|
-
- Points in progress
|
|
2080
|
-
- Points remaining
|
|
2081
|
-
3. List tickets by status
|
|
2082
|
-
4. Identify blockers or at-risk items
|
|
2083
|
-
|
|
2084
|
-
## Output Format
|
|
2085
|
-
|
|
2086
|
-
\`\`\`
|
|
2087
|
-
Sprint: <sprint-name>
|
|
2088
|
-
Progress: XX/YY points (ZZ%)
|
|
2089
|
-
|
|
2090
|
-
## Completed
|
|
2091
|
-
- [{{JIRA_PROJECT}}-123] Task name (3 pts)
|
|
2092
|
-
|
|
2093
|
-
## In Progress
|
|
2094
|
-
- [{{JIRA_PROJECT}}-124] Task name (5 pts) - @assignee
|
|
2095
|
-
|
|
2096
|
-
## To Do
|
|
2097
|
-
- [{{JIRA_PROJECT}}-125] Task name (2 pts)
|
|
2098
|
-
|
|
2099
|
-
## Blocked
|
|
2100
|
-
- [{{JIRA_PROJECT}}-126] Task name - Reason
|
|
2101
|
-
\`\`\`
|
|
2102
|
-
|
|
2103
|
-
## Fallbacks
|
|
2104
|
-
|
|
2105
|
-
If issue tracker is unavailable:
|
|
2106
|
-
- Report that sprint data cannot be fetched
|
|
2107
|
-
- Suggest checking the issue tracker directly at {{JIRA_URL}}
|
|
2108
|
-
`
|
|
2109
|
-
};
|
|
2110
|
-
var jiraCreateSkill = {
|
|
2111
|
-
name: "jira-create",
|
|
2112
|
-
description: "Create a new Jira ticket",
|
|
2113
|
-
argumentHint: "<ticket-type> <summary>",
|
|
2114
|
-
category: "optional",
|
|
2115
|
-
dependencies: [{ type: "issue_tracker", required: true, description: "For ticket creation" }],
|
|
2116
|
-
content: `---
|
|
2117
|
-
description: Create a new Jira ticket
|
|
2118
|
-
argument-hint: <ticket-type> <summary>
|
|
2119
|
-
requires: [issue_tracker]
|
|
2120
|
-
---
|
|
2121
|
-
|
|
2122
|
-
# Create Jira Ticket
|
|
2123
|
-
|
|
2124
|
-
Create a new ticket in project {{JIRA_PROJECT}}.
|
|
2125
|
-
|
|
2126
|
-
## Instructions
|
|
2127
|
-
|
|
2128
|
-
1. Parse the ticket type and summary from arguments
|
|
2129
|
-
2. Gather additional details:
|
|
2130
|
-
- Description
|
|
2131
|
-
- Priority
|
|
2132
|
-
- Labels
|
|
2133
|
-
- Components (if applicable)
|
|
2134
|
-
3. Create the ticket via the issue tracker integration
|
|
2135
|
-
4. Return the ticket key and URL
|
|
2136
|
-
|
|
2137
|
-
## Ticket Types
|
|
2138
|
-
|
|
2139
|
-
- **Story**: User-facing feature
|
|
2140
|
-
- **Bug**: Defect to fix
|
|
2141
|
-
- **Task**: Technical work
|
|
2142
|
-
- **Spike**: Research/investigation
|
|
2143
|
-
|
|
2144
|
-
## Output
|
|
2145
|
-
|
|
2146
|
-
\`\`\`
|
|
2147
|
-
Created: {{JIRA_PROJECT}}-XXX
|
|
2148
|
-
URL: {{JIRA_URL}}/browse/{{JIRA_PROJECT}}-XXX
|
|
2149
|
-
Summary: <summary>
|
|
2150
|
-
Type: <type>
|
|
2151
|
-
\`\`\`
|
|
2152
|
-
|
|
2153
|
-
## Fallbacks
|
|
2154
|
-
|
|
2155
|
-
If issue tracker is unavailable:
|
|
2156
|
-
- Provide the user with manual creation instructions
|
|
2157
|
-
- Include all details they should enter
|
|
2158
|
-
`
|
|
2159
|
-
};
|
|
2160
|
-
var jiraTransitionSkill = {
|
|
2161
|
-
name: "jira-transition",
|
|
2162
|
-
description: "Transition a Jira ticket to a new status",
|
|
2163
|
-
argumentHint: "<ticket-key> to <status>",
|
|
2164
|
-
category: "optional",
|
|
2165
|
-
dependencies: [{ type: "issue_tracker", required: true, description: "For ticket transitions" }],
|
|
2166
|
-
content: `---
|
|
2167
|
-
description: Transition a Jira ticket to a new status
|
|
2168
|
-
argument-hint: <ticket-key> to <status>
|
|
2169
|
-
requires: [issue_tracker]
|
|
2170
|
-
---
|
|
2171
|
-
|
|
2172
|
-
# Transition Jira Ticket
|
|
2173
|
-
|
|
2174
|
-
Update the status of a ticket in {{JIRA_PROJECT}}.
|
|
2175
|
-
|
|
2176
|
-
## Status Mapping
|
|
2177
|
-
|
|
2178
|
-
| Workflow Status | Jira Status |
|
|
2179
|
-
|-----------------|-------------|
|
|
2180
|
-
| BACKLOG | Backlog |
|
|
2181
|
-
| IN_PROGRESS | In Progress |
|
|
2182
|
-
| PR_CREATED | In Review |
|
|
2183
|
-
| IN_REVIEW | In Review |
|
|
2184
|
-
| APPROVED | Ready to Merge |
|
|
2185
|
-
| MERGED | Done |
|
|
2186
|
-
| DONE | Done |
|
|
2187
|
-
|
|
2188
|
-
## Instructions
|
|
2189
|
-
|
|
2190
|
-
1. Parse ticket key and target status
|
|
2191
|
-
2. Validate the transition is allowed
|
|
2192
|
-
3. Add a comment explaining the transition
|
|
2193
|
-
4. Execute the transition
|
|
2194
|
-
|
|
2195
|
-
## Transition Comment Format
|
|
2196
|
-
|
|
2197
|
-
\`\`\`
|
|
2198
|
-
Status updated to <status>.
|
|
2199
|
-
<optional context about why>
|
|
2200
|
-
\`\`\`
|
|
2201
|
-
|
|
2202
|
-
## Fallbacks
|
|
2203
|
-
|
|
2204
|
-
If issue tracker is unavailable:
|
|
2205
|
-
- Instruct user to manually transition at {{JIRA_URL}}
|
|
2206
|
-
- Provide the target status name
|
|
2207
|
-
`
|
|
2208
|
-
};
|
|
2209
|
-
var docsUpdateSkill = {
|
|
2210
|
-
name: "docs-update",
|
|
2211
|
-
description: "Update project documentation",
|
|
2212
|
-
argumentHint: "<doc-path-or-topic>",
|
|
2213
|
-
category: "optional",
|
|
2214
|
-
dependencies: [{ type: "documentation", required: false, description: "For remote docs" }],
|
|
2215
|
-
content: `---
|
|
2216
|
-
description: Update project documentation
|
|
2217
|
-
argument-hint: <doc-path-or-topic>
|
|
2218
|
-
optional: [documentation]
|
|
2219
|
-
---
|
|
2220
|
-
|
|
2221
|
-
# Update Documentation
|
|
2222
|
-
|
|
2223
|
-
Update project documentation for a specific topic or file.
|
|
2224
|
-
|
|
2225
|
-
## Instructions
|
|
2226
|
-
|
|
2227
|
-
1. Identify the documentation to update:
|
|
2228
|
-
- Local: \`{{DOCS_PATH}}/\`
|
|
2229
|
-
- Remote: {{CONFLUENCE_SPACE}} (if configured)
|
|
2230
|
-
|
|
2231
|
-
2. Make the necessary updates:
|
|
2232
|
-
- Keep formatting consistent
|
|
2233
|
-
- Update examples if code changed
|
|
2234
|
-
- Add/update version information
|
|
2235
|
-
|
|
2236
|
-
3. For remote documentation:
|
|
2237
|
-
- Use the documentation integration
|
|
2238
|
-
- Or provide content for manual update
|
|
2239
|
-
|
|
2240
|
-
## Documentation Types
|
|
2241
|
-
|
|
2242
|
-
- **README**: Project overview and setup
|
|
2243
|
-
- **API Docs**: Endpoint documentation
|
|
2244
|
-
- **Architecture**: Design decisions
|
|
2245
|
-
- **Runbooks**: Operational procedures
|
|
2246
|
-
|
|
2247
|
-
## Fallbacks
|
|
2248
|
-
|
|
2249
|
-
If documentation integration is unavailable:
|
|
2250
|
-
- Create/update local markdown files
|
|
2251
|
-
- Provide instructions for manual remote update
|
|
2252
|
-
`
|
|
2253
|
-
};
|
|
2254
|
-
var builtInSkills = [
|
|
2255
|
-
checkInboxSkill,
|
|
2256
|
-
delegateSkill,
|
|
2257
|
-
gitCommitSkill,
|
|
2258
|
-
prCreateSkill,
|
|
2259
|
-
reviewSkill,
|
|
2260
|
-
sprintStatusSkill,
|
|
2261
|
-
jiraCreateSkill,
|
|
2262
|
-
jiraTransitionSkill,
|
|
2263
|
-
docsUpdateSkill
|
|
2264
|
-
];
|
|
2265
|
-
|
|
2266
|
-
// src/skills/generator.ts
|
|
1906
|
+
import { existsSync as existsSync5, mkdirSync as mkdirSync2, writeFileSync as writeFileSync2, readFileSync as readFileSync5, readdirSync as readdirSync2, statSync } from "fs";
|
|
1907
|
+
import { join as join6, dirname as dirname5 } from "path";
|
|
1908
|
+
function getCoreSkillsDir() {
|
|
1909
|
+
let currentDir = dirname5(import.meta.url.replace("file://", ""));
|
|
1910
|
+
for (let i = 0; i < 5; i++) {
|
|
1911
|
+
if (existsSync5(join6(currentDir, "package.json"))) {
|
|
1912
|
+
return join6(currentDir, "skills");
|
|
1913
|
+
}
|
|
1914
|
+
currentDir = dirname5(currentDir);
|
|
1915
|
+
}
|
|
1916
|
+
return join6(dirname5(dirname5(dirname5(import.meta.url.replace("file://", "")))), "skills");
|
|
1917
|
+
}
|
|
1918
|
+
function discoverSkills(skillsDir) {
|
|
1919
|
+
const templates = [];
|
|
1920
|
+
if (!existsSync5(skillsDir)) {
|
|
1921
|
+
return templates;
|
|
1922
|
+
}
|
|
1923
|
+
const categories = readdirSync2(skillsDir);
|
|
1924
|
+
for (const category of categories) {
|
|
1925
|
+
const categoryPath = join6(skillsDir, category);
|
|
1926
|
+
const stat = statSync(categoryPath);
|
|
1927
|
+
if (!stat.isDirectory()) continue;
|
|
1928
|
+
if (category.startsWith(".") || category.startsWith("_")) continue;
|
|
1929
|
+
const skillDirs = readdirSync2(categoryPath);
|
|
1930
|
+
for (const skillName of skillDirs) {
|
|
1931
|
+
const skillDir = join6(categoryPath, skillName);
|
|
1932
|
+
const skillStat = statSync(skillDir);
|
|
1933
|
+
if (!skillStat.isDirectory()) continue;
|
|
1934
|
+
const skillFile = join6(skillDir, "SKILL.md");
|
|
1935
|
+
if (!existsSync5(skillFile)) continue;
|
|
1936
|
+
try {
|
|
1937
|
+
const content = readFileSync5(skillFile, "utf-8");
|
|
1938
|
+
const template = parseSkillFile(skillName, category, content);
|
|
1939
|
+
templates.push(template);
|
|
1940
|
+
} catch {
|
|
1941
|
+
}
|
|
1942
|
+
}
|
|
1943
|
+
}
|
|
1944
|
+
return templates;
|
|
1945
|
+
}
|
|
1946
|
+
function parseSkillFile(name, category, content) {
|
|
1947
|
+
const template = {
|
|
1948
|
+
name,
|
|
1949
|
+
description: name,
|
|
1950
|
+
category,
|
|
1951
|
+
content
|
|
1952
|
+
};
|
|
1953
|
+
const frontmatterMatch = content.match(/^---\r?\n([\s\S]*?)\r?\n---\r?\n/);
|
|
1954
|
+
if (!frontmatterMatch) {
|
|
1955
|
+
return template;
|
|
1956
|
+
}
|
|
1957
|
+
const frontmatter = frontmatterMatch[1];
|
|
1958
|
+
const lines = frontmatter.split(/\r?\n/);
|
|
1959
|
+
const dependencies = [];
|
|
1960
|
+
for (const line of lines) {
|
|
1961
|
+
const colonIndex = line.indexOf(":");
|
|
1962
|
+
if (colonIndex === -1) continue;
|
|
1963
|
+
const key = line.slice(0, colonIndex).trim();
|
|
1964
|
+
let value = line.slice(colonIndex + 1).trim();
|
|
1965
|
+
if (value.startsWith('"') && value.endsWith('"') || value.startsWith("'") && value.endsWith("'")) {
|
|
1966
|
+
value = value.slice(1, -1);
|
|
1967
|
+
}
|
|
1968
|
+
switch (key) {
|
|
1969
|
+
case "name":
|
|
1970
|
+
template.name = value;
|
|
1971
|
+
break;
|
|
1972
|
+
case "description":
|
|
1973
|
+
template.description = value;
|
|
1974
|
+
break;
|
|
1975
|
+
case "argument-hint":
|
|
1976
|
+
template.argumentHint = value;
|
|
1977
|
+
break;
|
|
1978
|
+
case "requires":
|
|
1979
|
+
if (value.startsWith("[") && value.endsWith("]")) {
|
|
1980
|
+
const items = value.slice(1, -1).split(",").map((s) => s.trim().replace(/['"]/g, ""));
|
|
1981
|
+
for (const item of items) {
|
|
1982
|
+
if (item) {
|
|
1983
|
+
dependencies.push({
|
|
1984
|
+
type: mapIntegrationName(item),
|
|
1985
|
+
required: true
|
|
1986
|
+
});
|
|
1987
|
+
}
|
|
1988
|
+
}
|
|
1989
|
+
}
|
|
1990
|
+
break;
|
|
1991
|
+
case "optional":
|
|
1992
|
+
if (value.startsWith("[") && value.endsWith("]")) {
|
|
1993
|
+
const items = value.slice(1, -1).split(",").map((s) => s.trim().replace(/['"]/g, ""));
|
|
1994
|
+
for (const item of items) {
|
|
1995
|
+
if (item) {
|
|
1996
|
+
dependencies.push({
|
|
1997
|
+
type: mapIntegrationName(item),
|
|
1998
|
+
required: false
|
|
1999
|
+
});
|
|
2000
|
+
}
|
|
2001
|
+
}
|
|
2002
|
+
}
|
|
2003
|
+
break;
|
|
2004
|
+
}
|
|
2005
|
+
}
|
|
2006
|
+
if (dependencies.length > 0) {
|
|
2007
|
+
template.dependencies = dependencies;
|
|
2008
|
+
}
|
|
2009
|
+
return template;
|
|
2010
|
+
}
|
|
2011
|
+
function mapIntegrationName(name) {
|
|
2012
|
+
const lower = name.toLowerCase();
|
|
2013
|
+
if (["jira", "linear", "issue_tracker", "issues", "github-issues"].includes(lower)) {
|
|
2014
|
+
return "issue_tracker";
|
|
2015
|
+
}
|
|
2016
|
+
if (["git", "github", "gitlab", "bitbucket"].includes(lower)) {
|
|
2017
|
+
return "git";
|
|
2018
|
+
}
|
|
2019
|
+
if (["docs", "documentation", "confluence", "notion", "wiki"].includes(lower)) {
|
|
2020
|
+
return "documentation";
|
|
2021
|
+
}
|
|
2022
|
+
return "state";
|
|
2023
|
+
}
|
|
2267
2024
|
function extractVariables2(config) {
|
|
2268
2025
|
const vars = {};
|
|
2269
2026
|
if (!config) {
|
|
@@ -2373,112 +2130,12 @@ function checkDependencies(skill, config) {
|
|
|
2373
2130
|
missing
|
|
2374
2131
|
};
|
|
2375
2132
|
}
|
|
2376
|
-
function loadCustomTemplates(templatesDir) {
|
|
2377
|
-
const templates = [];
|
|
2378
|
-
if (!existsSync5(templatesDir)) {
|
|
2379
|
-
return templates;
|
|
2380
|
-
}
|
|
2381
|
-
const files = readdirSync2(templatesDir);
|
|
2382
|
-
for (const file of files) {
|
|
2383
|
-
if (!file.endsWith(".md")) continue;
|
|
2384
|
-
const filePath = join6(templatesDir, file);
|
|
2385
|
-
const stat = statSync(filePath);
|
|
2386
|
-
if (!stat.isFile()) continue;
|
|
2387
|
-
try {
|
|
2388
|
-
const content = readFileSync4(filePath, "utf-8");
|
|
2389
|
-
const template = parseSkillTemplate(file, content);
|
|
2390
|
-
templates.push(template);
|
|
2391
|
-
} catch {
|
|
2392
|
-
}
|
|
2393
|
-
}
|
|
2394
|
-
return templates;
|
|
2395
|
-
}
|
|
2396
|
-
function parseSkillTemplate(filename, content) {
|
|
2397
|
-
const name = basename2(filename, ".md");
|
|
2398
|
-
const frontmatterMatch = content.match(/^---\r?\n([\s\S]*?)\r?\n---\r?\n([\s\S]*)$/);
|
|
2399
|
-
let description = name;
|
|
2400
|
-
let argumentHint;
|
|
2401
|
-
const dependencies = [];
|
|
2402
|
-
if (frontmatterMatch) {
|
|
2403
|
-
const frontmatter = frontmatterMatch[1] ?? "";
|
|
2404
|
-
const lines = frontmatter.split(/\r?\n/);
|
|
2405
|
-
for (const line of lines) {
|
|
2406
|
-
const colonIndex = line.indexOf(":");
|
|
2407
|
-
if (colonIndex === -1) continue;
|
|
2408
|
-
const key = line.slice(0, colonIndex).trim();
|
|
2409
|
-
let value = line.slice(colonIndex + 1).trim();
|
|
2410
|
-
if (value.startsWith('"') && value.endsWith('"') || value.startsWith("'") && value.endsWith("'")) {
|
|
2411
|
-
value = value.slice(1, -1);
|
|
2412
|
-
}
|
|
2413
|
-
switch (key) {
|
|
2414
|
-
case "description":
|
|
2415
|
-
description = value;
|
|
2416
|
-
break;
|
|
2417
|
-
case "argument-hint":
|
|
2418
|
-
argumentHint = value;
|
|
2419
|
-
break;
|
|
2420
|
-
case "requires":
|
|
2421
|
-
if (value.startsWith("[") && value.endsWith("]")) {
|
|
2422
|
-
const items = value.slice(1, -1).split(",").map((s) => s.trim().replace(/['"]/g, ""));
|
|
2423
|
-
for (const item of items) {
|
|
2424
|
-
if (item) {
|
|
2425
|
-
dependencies.push({
|
|
2426
|
-
type: mapIntegrationName(item),
|
|
2427
|
-
required: true
|
|
2428
|
-
});
|
|
2429
|
-
}
|
|
2430
|
-
}
|
|
2431
|
-
}
|
|
2432
|
-
break;
|
|
2433
|
-
case "optional":
|
|
2434
|
-
if (value.startsWith("[") && value.endsWith("]")) {
|
|
2435
|
-
const items = value.slice(1, -1).split(",").map((s) => s.trim().replace(/['"]/g, ""));
|
|
2436
|
-
for (const item of items) {
|
|
2437
|
-
if (item) {
|
|
2438
|
-
dependencies.push({
|
|
2439
|
-
type: mapIntegrationName(item),
|
|
2440
|
-
required: false
|
|
2441
|
-
});
|
|
2442
|
-
}
|
|
2443
|
-
}
|
|
2444
|
-
}
|
|
2445
|
-
break;
|
|
2446
|
-
}
|
|
2447
|
-
}
|
|
2448
|
-
}
|
|
2449
|
-
const template = {
|
|
2450
|
-
name,
|
|
2451
|
-
description,
|
|
2452
|
-
category: "custom",
|
|
2453
|
-
content
|
|
2454
|
-
};
|
|
2455
|
-
if (argumentHint) {
|
|
2456
|
-
template.argumentHint = argumentHint;
|
|
2457
|
-
}
|
|
2458
|
-
if (dependencies.length > 0) {
|
|
2459
|
-
template.dependencies = dependencies;
|
|
2460
|
-
}
|
|
2461
|
-
return template;
|
|
2462
|
-
}
|
|
2463
|
-
function mapIntegrationName(name) {
|
|
2464
|
-
const lower = name.toLowerCase();
|
|
2465
|
-
if (["jira", "linear", "issue_tracker", "issues", "github-issues"].includes(lower)) {
|
|
2466
|
-
return "issue_tracker";
|
|
2467
|
-
}
|
|
2468
|
-
if (["git", "github", "gitlab", "bitbucket"].includes(lower)) {
|
|
2469
|
-
return "git";
|
|
2470
|
-
}
|
|
2471
|
-
if (["docs", "documentation", "confluence", "notion", "wiki"].includes(lower)) {
|
|
2472
|
-
return "documentation";
|
|
2473
|
-
}
|
|
2474
|
-
return "state";
|
|
2475
|
-
}
|
|
2476
2133
|
function generateSkills(config, options = {}) {
|
|
2477
2134
|
const projectRoot = options.projectRoot ?? process.cwd();
|
|
2478
|
-
const
|
|
2135
|
+
const coreSkillsDir = options.coreSkillsDir ?? getCoreSkillsDir();
|
|
2136
|
+
const outputDir = options.outputDir ?? join6(projectRoot, ".claude", "skills");
|
|
2479
2137
|
const includeCoreSkills = options.includeCoreSkills ?? true;
|
|
2480
|
-
const
|
|
2481
|
-
const overwrite = options.overwrite ?? false;
|
|
2138
|
+
const overwrite = options.overwrite ?? true;
|
|
2482
2139
|
const result = {
|
|
2483
2140
|
generated: [],
|
|
2484
2141
|
errors: [],
|
|
@@ -2491,21 +2148,17 @@ function generateSkills(config, options = {}) {
|
|
|
2491
2148
|
result.variables = variables;
|
|
2492
2149
|
let templates = [];
|
|
2493
2150
|
if (includeCoreSkills) {
|
|
2494
|
-
|
|
2495
|
-
|
|
2496
|
-
if (includeOptionalSkills) {
|
|
2497
|
-
templates.push(...builtInSkills.filter((s) => s.category === "optional"));
|
|
2151
|
+
const discovered = discoverSkills(coreSkillsDir);
|
|
2152
|
+
templates.push(...discovered);
|
|
2498
2153
|
}
|
|
2499
2154
|
if (options.customTemplatesDir && existsSync5(options.customTemplatesDir)) {
|
|
2500
|
-
|
|
2155
|
+
const custom = discoverSkills(options.customTemplatesDir);
|
|
2156
|
+
templates.push(...custom);
|
|
2501
2157
|
}
|
|
2502
2158
|
if (options.skills && options.skills.length > 0) {
|
|
2503
2159
|
const skillsToInclude = options.skills;
|
|
2504
2160
|
templates = templates.filter((t) => skillsToInclude.includes(t.name));
|
|
2505
2161
|
}
|
|
2506
|
-
if (!existsSync5(outputDir)) {
|
|
2507
|
-
mkdirSync2(outputDir, { recursive: true });
|
|
2508
|
-
}
|
|
2509
2162
|
for (const template of templates) {
|
|
2510
2163
|
try {
|
|
2511
2164
|
const generated = generateSkill(template, variables, config, outputDir, overwrite);
|
|
@@ -2520,7 +2173,8 @@ function generateSkills(config, options = {}) {
|
|
|
2520
2173
|
return result;
|
|
2521
2174
|
}
|
|
2522
2175
|
function generateSkill(template, variables, config, outputDir, overwrite) {
|
|
2523
|
-
const
|
|
2176
|
+
const skillDir = join6(outputDir, template.name);
|
|
2177
|
+
const outputPath = join6(skillDir, "SKILL.md");
|
|
2524
2178
|
if (existsSync5(outputPath) && !overwrite) {
|
|
2525
2179
|
return {
|
|
2526
2180
|
name: template.name,
|
|
@@ -2543,6 +2197,9 @@ function generateSkill(template, variables, config, outputDir, overwrite) {
|
|
|
2543
2197
|
}
|
|
2544
2198
|
const content = substituteVariables(template.content, variables);
|
|
2545
2199
|
const isUpdate = existsSync5(outputPath);
|
|
2200
|
+
if (!existsSync5(skillDir)) {
|
|
2201
|
+
mkdirSync2(skillDir, { recursive: true });
|
|
2202
|
+
}
|
|
2546
2203
|
writeFileSync2(outputPath, content, "utf-8");
|
|
2547
2204
|
return {
|
|
2548
2205
|
name: template.name,
|
|
@@ -2586,7 +2243,7 @@ function formatGenerateResult(result) {
|
|
|
2586
2243
|
}
|
|
2587
2244
|
const total = created.length + updated.length;
|
|
2588
2245
|
if (total > 0) {
|
|
2589
|
-
lines.push(`Generated ${total} skill(s) to .claude/
|
|
2246
|
+
lines.push(`Generated ${total} skill(s) to .claude/skills/`);
|
|
2590
2247
|
} else if (result.generated.length === 0 && result.errors.length === 0) {
|
|
2591
2248
|
lines.push("No skills to generate.");
|
|
2592
2249
|
}
|
|
@@ -2598,12 +2255,12 @@ import {
|
|
|
2598
2255
|
existsSync as existsSync6,
|
|
2599
2256
|
mkdirSync as mkdirSync3,
|
|
2600
2257
|
writeFileSync as writeFileSync3,
|
|
2601
|
-
readFileSync as
|
|
2258
|
+
readFileSync as readFileSync6,
|
|
2602
2259
|
readdirSync as readdirSync3,
|
|
2603
2260
|
renameSync,
|
|
2604
2261
|
statSync as statSync2
|
|
2605
2262
|
} from "fs";
|
|
2606
|
-
import { join as join7, basename as
|
|
2263
|
+
import { join as join7, basename as basename2 } from "path";
|
|
2607
2264
|
var DEFAULT_KNOWLEDGE_LIBRARY_PATH = "KnowledgeLibrary";
|
|
2608
2265
|
var STANDARD_FILES = {
|
|
2609
2266
|
context: "context.txt",
|
|
@@ -2853,7 +2510,7 @@ function getAgentKnowledgeState(agentName, options = {}) {
|
|
|
2853
2510
|
let context;
|
|
2854
2511
|
const currentContextPath = join7(dirs.context, "current.txt");
|
|
2855
2512
|
if (existsSync6(currentContextPath)) {
|
|
2856
|
-
const content =
|
|
2513
|
+
const content = readFileSync6(currentContextPath, "utf-8");
|
|
2857
2514
|
context = parseContextFile(content);
|
|
2858
2515
|
}
|
|
2859
2516
|
const state = {
|
|
@@ -2947,7 +2604,7 @@ function readInboxMessages(agentName, options = {}) {
|
|
|
2947
2604
|
);
|
|
2948
2605
|
for (const file of files) {
|
|
2949
2606
|
const filePath = join7(dirs.inbox, file);
|
|
2950
|
-
const rawContent =
|
|
2607
|
+
const rawContent = readFileSync6(filePath, "utf-8");
|
|
2951
2608
|
const { metadata, body } = parseMessageFrontmatter(rawContent);
|
|
2952
2609
|
if (options.type && metadata.type !== options.type) continue;
|
|
2953
2610
|
if (options.from && metadata.from !== options.from) continue;
|
|
@@ -2967,7 +2624,7 @@ function readInboxMessages(agentName, options = {}) {
|
|
|
2967
2624
|
);
|
|
2968
2625
|
for (const file of files) {
|
|
2969
2626
|
const filePath = join7(dirs.inboxProcessed, file);
|
|
2970
|
-
const rawContent =
|
|
2627
|
+
const rawContent = readFileSync6(filePath, "utf-8");
|
|
2971
2628
|
const { metadata, body } = parseMessageFrontmatter(rawContent);
|
|
2972
2629
|
if (options.type && metadata.type !== options.type) continue;
|
|
2973
2630
|
if (options.from && metadata.from !== options.from) continue;
|
|
@@ -3016,18 +2673,18 @@ function getKnowledgeLibraryState(options = {}) {
|
|
|
3016
2673
|
|
|
3017
2674
|
// src/index.ts
|
|
3018
2675
|
function findPackageJson() {
|
|
3019
|
-
let dir =
|
|
3020
|
-
while (dir !==
|
|
2676
|
+
let dir = dirname6(fileURLToPath(import.meta.url));
|
|
2677
|
+
while (dir !== dirname6(dir)) {
|
|
3021
2678
|
const pkgPath = join8(dir, "package.json");
|
|
3022
2679
|
try {
|
|
3023
|
-
const content =
|
|
2680
|
+
const content = readFileSync7(pkgPath, "utf-8");
|
|
3024
2681
|
const pkg = JSON.parse(content);
|
|
3025
2682
|
if (pkg.name === "@deimoscloud/coreai") {
|
|
3026
2683
|
return content;
|
|
3027
2684
|
}
|
|
3028
2685
|
} catch {
|
|
3029
2686
|
}
|
|
3030
|
-
dir =
|
|
2687
|
+
dir = dirname6(dir);
|
|
3031
2688
|
}
|
|
3032
2689
|
return '{"version": "unknown"}';
|
|
3033
2690
|
}
|
|
@@ -3304,8 +2961,8 @@ function formatSyncResult(result) {
|
|
|
3304
2961
|
}
|
|
3305
2962
|
|
|
3306
2963
|
// src/cli/commands/init.ts
|
|
3307
|
-
import { existsSync as existsSync7, writeFileSync as writeFileSync4, mkdirSync as mkdirSync4, readFileSync as
|
|
3308
|
-
import { join as join11, basename as
|
|
2964
|
+
import { existsSync as existsSync7, writeFileSync as writeFileSync4, mkdirSync as mkdirSync4, readFileSync as readFileSync8 } from "fs";
|
|
2965
|
+
import { join as join11, basename as basename3 } from "path";
|
|
3309
2966
|
import { execSync } from "child_process";
|
|
3310
2967
|
function detectGitInfo() {
|
|
3311
2968
|
try {
|
|
@@ -3335,14 +2992,14 @@ function detectProjectName(projectRoot) {
|
|
|
3335
2992
|
const packageJsonPath = join11(projectRoot, "package.json");
|
|
3336
2993
|
if (existsSync7(packageJsonPath)) {
|
|
3337
2994
|
try {
|
|
3338
|
-
const content = JSON.parse(
|
|
2995
|
+
const content = JSON.parse(readFileSync8(packageJsonPath, "utf-8"));
|
|
3339
2996
|
if (content.name) {
|
|
3340
2997
|
return content.name;
|
|
3341
2998
|
}
|
|
3342
2999
|
} catch {
|
|
3343
3000
|
}
|
|
3344
3001
|
}
|
|
3345
|
-
return
|
|
3002
|
+
return basename3(projectRoot);
|
|
3346
3003
|
}
|
|
3347
3004
|
function generateConfigYaml(options) {
|
|
3348
3005
|
let yaml = `# CoreAI Configuration
|
|
@@ -3539,6 +3196,14 @@ function build(options = {}) {
|
|
|
3539
3196
|
warnings
|
|
3540
3197
|
};
|
|
3541
3198
|
}
|
|
3199
|
+
let skillsResult;
|
|
3200
|
+
if (!options.skipSkills) {
|
|
3201
|
+
skillsResult = generateSkills(config, {
|
|
3202
|
+
projectRoot,
|
|
3203
|
+
skills: options.skills,
|
|
3204
|
+
overwrite: true
|
|
3205
|
+
});
|
|
3206
|
+
}
|
|
3542
3207
|
let knowledgeLibraryInitialized;
|
|
3543
3208
|
if (options.initKnowledgeLibrary) {
|
|
3544
3209
|
knowledgeLibraryInitialized = [];
|
|
@@ -3555,6 +3220,7 @@ function build(options = {}) {
|
|
|
3555
3220
|
return {
|
|
3556
3221
|
success: true,
|
|
3557
3222
|
result,
|
|
3223
|
+
skillsResult,
|
|
3558
3224
|
config,
|
|
3559
3225
|
warnings: warnings.length > 0 ? warnings : void 0,
|
|
3560
3226
|
knowledgeLibraryInitialized,
|
|
@@ -3624,6 +3290,24 @@ function formatBuildResult(result) {
|
|
|
3624
3290
|
}
|
|
3625
3291
|
lines.push("");
|
|
3626
3292
|
}
|
|
3293
|
+
if (result.skillsResult) {
|
|
3294
|
+
const created = result.skillsResult.generated.filter((g) => g.action === "created");
|
|
3295
|
+
const updated = result.skillsResult.generated.filter((g) => g.action === "updated");
|
|
3296
|
+
const total = created.length + updated.length;
|
|
3297
|
+
if (total > 0) {
|
|
3298
|
+
lines.push(`Generated ${total} skill(s):`);
|
|
3299
|
+
for (const skill of [...created, ...updated]) {
|
|
3300
|
+
lines.push(` \u2713 ${skill.name} \u2192 ${skill.outputPath}`);
|
|
3301
|
+
}
|
|
3302
|
+
lines.push("");
|
|
3303
|
+
}
|
|
3304
|
+
if (result.skillsResult.errors.length > 0) {
|
|
3305
|
+
for (const error of result.skillsResult.errors) {
|
|
3306
|
+
lines.push(` \u2717 skill ${error.name}: ${error.error}`);
|
|
3307
|
+
}
|
|
3308
|
+
lines.push("");
|
|
3309
|
+
}
|
|
3310
|
+
}
|
|
3627
3311
|
if (result.mcpServers && result.mcpServers.length > 0) {
|
|
3628
3312
|
lines.push(`MCP tools included: ${result.mcpServers.map((s) => `mcp__${s}`).join(", ")}`);
|
|
3629
3313
|
lines.push("");
|
|
@@ -3868,8 +3552,7 @@ function skillsGenerate(options = {}) {
|
|
|
3868
3552
|
const generateOptions = {
|
|
3869
3553
|
projectRoot,
|
|
3870
3554
|
includeCoreSkills: options.includeCoreSkills ?? true,
|
|
3871
|
-
|
|
3872
|
-
overwrite: options.overwrite ?? false
|
|
3555
|
+
overwrite: options.overwrite ?? true
|
|
3873
3556
|
};
|
|
3874
3557
|
if (options.outputDir) {
|
|
3875
3558
|
generateOptions.outputDir = options.outputDir;
|
|
@@ -3935,11 +3618,11 @@ function formatSkillsGenerateResult(result) {
|
|
|
3935
3618
|
function skillsList(options = {}) {
|
|
3936
3619
|
try {
|
|
3937
3620
|
const skills = [];
|
|
3621
|
+
const coreSkillsDir = getCoreSkillsDir();
|
|
3622
|
+
const discovered = discoverSkills(coreSkillsDir);
|
|
3938
3623
|
const includeCoreSkills = options.includeCoreSkills ?? true;
|
|
3939
|
-
const
|
|
3940
|
-
for (const skill of builtInSkills) {
|
|
3624
|
+
for (const skill of discovered) {
|
|
3941
3625
|
if (skill.category === "core" && !includeCoreSkills) continue;
|
|
3942
|
-
if (skill.category === "optional" && !includeOptionalSkills) continue;
|
|
3943
3626
|
skills.push({
|
|
3944
3627
|
name: skill.name,
|
|
3945
3628
|
description: skill.description,
|
|
@@ -3949,7 +3632,7 @@ function skillsList(options = {}) {
|
|
|
3949
3632
|
});
|
|
3950
3633
|
}
|
|
3951
3634
|
if (options.customTemplatesDir) {
|
|
3952
|
-
const customSkills =
|
|
3635
|
+
const customSkills = discoverSkills(options.customTemplatesDir);
|
|
3953
3636
|
for (const skill of customSkills) {
|
|
3954
3637
|
skills.push({
|
|
3955
3638
|
name: skill.name,
|
|
@@ -3981,7 +3664,6 @@ function formatSkillsListResult(result) {
|
|
|
3981
3664
|
const lines = [];
|
|
3982
3665
|
lines.push("Available skills:\n");
|
|
3983
3666
|
const coreSkills = result.skills.filter((s) => s.category === "core");
|
|
3984
|
-
const optionalSkills = result.skills.filter((s) => s.category === "optional");
|
|
3985
3667
|
const customSkills = result.skills.filter((s) => s.category === "custom");
|
|
3986
3668
|
if (coreSkills.length > 0) {
|
|
3987
3669
|
lines.push("Core skills:");
|
|
@@ -3994,18 +3676,6 @@ function formatSkillsListResult(result) {
|
|
|
3994
3676
|
}
|
|
3995
3677
|
lines.push("");
|
|
3996
3678
|
}
|
|
3997
|
-
if (optionalSkills.length > 0) {
|
|
3998
|
-
lines.push("Optional skills:");
|
|
3999
|
-
for (const skill of optionalSkills) {
|
|
4000
|
-
const deps = skill.dependencies?.length ? ` (requires: ${skill.dependencies.join(", ")})` : "";
|
|
4001
|
-
lines.push(` ${skill.name}${deps}`);
|
|
4002
|
-
lines.push(` ${skill.description}`);
|
|
4003
|
-
if (skill.argumentHint) {
|
|
4004
|
-
lines.push(` Argument: ${skill.argumentHint}`);
|
|
4005
|
-
}
|
|
4006
|
-
}
|
|
4007
|
-
lines.push("");
|
|
4008
|
-
}
|
|
4009
3679
|
if (customSkills.length > 0) {
|
|
4010
3680
|
lines.push("Custom skills:");
|
|
4011
3681
|
for (const skill of customSkills) {
|
|
@@ -4181,22 +3851,22 @@ function formatStatusResult(result) {
|
|
|
4181
3851
|
}
|
|
4182
3852
|
|
|
4183
3853
|
// src/cli/commands/agents.ts
|
|
4184
|
-
import { readFileSync as
|
|
4185
|
-
import { join as join13, dirname as
|
|
4186
|
-
import { parse as
|
|
3854
|
+
import { readFileSync as readFileSync9, writeFileSync as writeFileSync5 } from "fs";
|
|
3855
|
+
import { join as join13, dirname as dirname7 } from "path";
|
|
3856
|
+
import { parse as parseYaml4, stringify as stringifyYaml2 } from "yaml";
|
|
4187
3857
|
function readConfigFile(configPath) {
|
|
4188
|
-
const content =
|
|
4189
|
-
const parsed =
|
|
3858
|
+
const content = readFileSync9(configPath, "utf-8");
|
|
3859
|
+
const parsed = parseYaml4(content);
|
|
4190
3860
|
return { content, parsed };
|
|
4191
3861
|
}
|
|
4192
3862
|
function updateConfigAgents(configPath, agents2) {
|
|
4193
|
-
const content =
|
|
4194
|
-
const parsed =
|
|
3863
|
+
const content = readFileSync9(configPath, "utf-8");
|
|
3864
|
+
const parsed = parseYaml4(content);
|
|
4195
3865
|
if (!parsed.team) {
|
|
4196
3866
|
parsed.team = {};
|
|
4197
3867
|
}
|
|
4198
3868
|
parsed.team.agents = agents2;
|
|
4199
|
-
const newContent =
|
|
3869
|
+
const newContent = stringifyYaml2(parsed, {
|
|
4200
3870
|
indent: 2,
|
|
4201
3871
|
lineWidth: 0,
|
|
4202
3872
|
singleQuote: false
|
|
@@ -4216,7 +3886,7 @@ function getAvailableAgents(coreAgentsDir, customAgentsDir) {
|
|
|
4216
3886
|
}
|
|
4217
3887
|
function agentsAdd(agents2, options = {}) {
|
|
4218
3888
|
const projectRoot = options.projectRoot ?? process.cwd();
|
|
4219
|
-
const coreAgentsDir = options.coreAgentsDir ?? join13(
|
|
3889
|
+
const coreAgentsDir = options.coreAgentsDir ?? join13(dirname7(dirname7(dirname7(__dirname))), "agents");
|
|
4220
3890
|
const customAgentsDir = join13(projectRoot, "coreai", "agents");
|
|
4221
3891
|
const configPath = findConfigFile(projectRoot);
|
|
4222
3892
|
if (!configPath) {
|
|
@@ -4398,7 +4068,7 @@ function formatAgentsRemoveResult(result) {
|
|
|
4398
4068
|
|
|
4399
4069
|
// src/cli/index.ts
|
|
4400
4070
|
var __filename = fileURLToPath2(import.meta.url);
|
|
4401
|
-
var __dirname2 =
|
|
4071
|
+
var __dirname2 = dirname8(__filename);
|
|
4402
4072
|
function getCoreAgentsPath() {
|
|
4403
4073
|
return join14(__dirname2, "..", "..", "agents");
|
|
4404
4074
|
}
|
|
@@ -4708,7 +4378,7 @@ program.command("status").description("Show agent states and pending messages").
|
|
|
4708
4378
|
}
|
|
4709
4379
|
});
|
|
4710
4380
|
var skillsCmd = program.command("skills").description("Manage Claude skills");
|
|
4711
|
-
skillsCmd.command("generate").description("Generate Claude skills from
|
|
4381
|
+
skillsCmd.command("generate").description("Generate Claude skills from source files").option("-o, --output <dir>", "output directory (default: .claude/skills)").option("--skills <skills>", "comma-separated list of skills to generate").option("--no-core", "exclude core skills").option("--no-overwrite", "do not overwrite existing skill files").option("--json", "output as JSON").action(
|
|
4712
4382
|
(options) => {
|
|
4713
4383
|
console.log("Generating skills...\n");
|
|
4714
4384
|
const result = skillsGenerate({
|
|
@@ -4716,8 +4386,7 @@ skillsCmd.command("generate").description("Generate Claude skills from templates
|
|
|
4716
4386
|
outputDir: options.output,
|
|
4717
4387
|
skills: options.skills?.split(",").map((s) => s.trim()),
|
|
4718
4388
|
includeCoreSkills: options.core !== false,
|
|
4719
|
-
|
|
4720
|
-
overwrite: options.overwrite
|
|
4389
|
+
overwrite: options.overwrite !== false
|
|
4721
4390
|
});
|
|
4722
4391
|
if (options.json) {
|
|
4723
4392
|
console.log(JSON.stringify(result, null, 2));
|
|
@@ -4729,11 +4398,10 @@ skillsCmd.command("generate").description("Generate Claude skills from templates
|
|
|
4729
4398
|
}
|
|
4730
4399
|
}
|
|
4731
4400
|
);
|
|
4732
|
-
skillsCmd.command("list").description("List available skills").option("--no-core", "exclude core skills").option("--
|
|
4401
|
+
skillsCmd.command("list").description("List available skills").option("--no-core", "exclude core skills").option("--json", "output as JSON").action((options) => {
|
|
4733
4402
|
const result = skillsList({
|
|
4734
4403
|
projectRoot: process.cwd(),
|
|
4735
|
-
includeCoreSkills: options.core !== false
|
|
4736
|
-
includeOptionalSkills: options.optional !== false
|
|
4404
|
+
includeCoreSkills: options.core !== false
|
|
4737
4405
|
});
|
|
4738
4406
|
if (options.json) {
|
|
4739
4407
|
console.log(JSON.stringify(result, null, 2));
|