@opengsd/gsd-core 1.5.0-rc.3 → 1.5.0-rc.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude-plugin/plugin.json +1 -1
- package/agents/gsd-advisor-researcher.md +1 -1
- package/agents/gsd-assumptions-analyzer.md +1 -1
- package/agents/gsd-code-fixer.md +1 -1
- package/agents/gsd-code-reviewer.md +1 -1
- package/agents/gsd-codebase-mapper.md +1 -1
- package/agents/gsd-debugger.md +1 -1
- package/agents/gsd-doc-writer.md +1 -1
- package/agents/gsd-eval-auditor.md +1 -1
- package/agents/gsd-executor.md +1 -1
- package/agents/gsd-integration-checker.md +1 -1
- package/agents/gsd-nyquist-auditor.md +1 -0
- package/agents/gsd-phase-researcher.md +1 -1
- package/agents/gsd-plan-checker.md +1 -1
- package/agents/gsd-planner.md +1 -1
- package/agents/gsd-project-researcher.md +1 -1
- package/agents/gsd-research-synthesizer.md +1 -1
- package/agents/gsd-roadmapper.md +55 -2
- package/agents/gsd-security-auditor.md +1 -0
- package/agents/gsd-ui-auditor.md +1 -1
- package/agents/gsd-ui-checker.md +1 -1
- package/agents/gsd-ui-researcher.md +1 -1
- package/agents/gsd-verifier.md +13 -2
- package/bin/install.js +36 -57
- package/commands/gsd/progress.md +2 -1
- package/gemini-extension.json +1 -1
- package/gsd-core/bin/gsd-tools.cjs +167 -3
- package/gsd-core/bin/lib/active-workstream-store.cjs +6 -0
- package/gsd-core/bin/lib/capability-state.cjs +97 -3
- package/gsd-core/bin/lib/capability-writer.cjs +354 -0
- package/gsd-core/bin/lib/config.cjs +80 -24
- package/gsd-core/bin/lib/edge-probe.cjs +25 -2
- package/gsd-core/bin/lib/frontmatter.cjs +53 -1
- package/gsd-core/bin/lib/git-base-branch.cjs +194 -0
- package/gsd-core/bin/lib/init.cjs +28 -6
- package/gsd-core/bin/lib/install-profiles.cjs +55 -0
- package/gsd-core/bin/lib/installer-migration-report.cjs +1 -0
- package/gsd-core/bin/lib/phase.cjs +28 -12
- package/gsd-core/bin/lib/plan-drift-guard.cjs +117 -0
- package/gsd-core/bin/lib/probe-core.cjs +117 -1
- package/gsd-core/bin/lib/roadmap-parser.cjs +13 -3
- package/gsd-core/bin/lib/runtime-artifact-conversion.cjs +246 -0
- package/gsd-core/bin/lib/runtime-artifact-layout.cjs +34 -2
- package/gsd-core/bin/lib/state.cjs +240 -59
- package/gsd-core/bin/lib/verify.cjs +73 -4
- package/gsd-core/bin/lib/worktree-safety.cjs +2 -1
- package/gsd-core/references/edge-probe.md +11 -0
- package/gsd-core/references/prohibition-probe-fixtures/01-streak-reminder/expected.json +14 -0
- package/gsd-core/references/prohibition-probe-fixtures/02-clean-utility/expected.json +4 -0
- package/gsd-core/references/prohibition-probe-fixtures/03-multi-prohibition/expected.json +32 -0
- package/gsd-core/references/prohibition-probe.md +248 -0
- package/gsd-core/templates/spec.md +14 -0
- package/gsd-core/workflows/complete-milestone.md +1 -5
- package/gsd-core/workflows/execute-phase.md +4 -3
- package/gsd-core/workflows/execute-plan.md +21 -6
- package/gsd-core/workflows/help/modes/full.md +4 -0
- package/gsd-core/workflows/next.md +50 -2
- package/gsd-core/workflows/pause-work.md +7 -1
- package/gsd-core/workflows/plan-phase.md +2 -0
- package/gsd-core/workflows/plan-review-convergence.md +14 -4
- package/gsd-core/workflows/pr-branch.md +4 -2
- package/gsd-core/workflows/quick.md +3 -2
- package/gsd-core/workflows/resume-project.md +17 -1
- package/gsd-core/workflows/settings.md +27 -1
- package/gsd-core/workflows/ship.md +1 -5
- package/gsd-core/workflows/spec-phase.md +75 -0
- package/gsd-core/workflows/verify-phase.md +14 -4
- package/hooks/dist/gsd-ensure-canonical-path.js +305 -0
- package/hooks/dist/gsd-statusline.js +1 -1
- package/hooks/dist/managed-hooks-registry.cjs +1 -0
- package/hooks/gsd-ensure-canonical-path.js +305 -0
- package/hooks/gsd-statusline.js +1 -1
- package/hooks/hooks.json +1 -0
- package/hooks/managed-hooks-registry.cjs +1 -0
- package/package.json +3 -3
- package/scripts/build-hooks.js +7 -0
- package/scripts/changeset/new.cjs +17 -3
- package/scripts/fix-slash-commands.cjs +15 -3
- package/scripts/gen-capability-registry.cjs +14 -1
- package/scripts/lint-allow-test-rule-refs.allowlist.json +2 -1
- package/scripts/lint-test-file-count.allowlist.json +6 -0
- package/scripts/mutation-matrix.cjs +108 -7
- package/scripts/pr-target-policy.cjs +63 -0
- package/scripts/research-profiles.cjs +5 -5
- package/scripts/run-tests.cjs +107 -6
|
@@ -319,8 +319,17 @@ function stripFencedLines(text) {
|
|
|
319
319
|
/**
|
|
320
320
|
* Returns a filter function that checks whether a phase directory belongs
|
|
321
321
|
* to the current milestone based on ROADMAP.md phase headings.
|
|
322
|
+
*
|
|
323
|
+
* @param cwd - Project working directory.
|
|
324
|
+
* @param versionOverride - Optional version string to scope the phase filter
|
|
325
|
+
* to a specific milestone (e.g. 'v1.2').
|
|
326
|
+
* @param phaseIdConvention - The resolved `phase_id_convention` config value.
|
|
327
|
+
* When `'milestone-prefixed'`, a deprecation warning is emitted for
|
|
328
|
+
* free-form ROADMAPs that lack versioned milestone headings. When absent or
|
|
329
|
+
* any other value, the warning is suppressed — legacy/default projects must
|
|
330
|
+
* never see spurious warnings.
|
|
322
331
|
*/
|
|
323
|
-
function getMilestonePhaseFilter(cwd, versionOverride) {
|
|
332
|
+
function getMilestonePhaseFilter(cwd, versionOverride, phaseIdConvention) {
|
|
324
333
|
const milestonePhaseNums = new Set();
|
|
325
334
|
let missingExplicitVersion = false;
|
|
326
335
|
try {
|
|
@@ -331,9 +340,10 @@ function getMilestonePhaseFilter(cwd, versionOverride) {
|
|
|
331
340
|
let roadmap = extractCurrentMilestone(roadmapContent, cwd);
|
|
332
341
|
const hasVersionedMilestonesGlobal = /^#{1,3}\s+.*v\d+\.\d+/mi.test(roadmapContent);
|
|
333
342
|
const hasPhaseHeadings = /#{2,4}\s*(?:\[[^\]]+\]\s*)?Phase\s+[\w]/i.test(roadmapContent);
|
|
334
|
-
if (!hasVersionedMilestonesGlobal && hasPhaseHeadings) {
|
|
343
|
+
if (!hasVersionedMilestonesGlobal && hasPhaseHeadings && phaseIdConvention === 'milestone-prefixed') {
|
|
335
344
|
console.warn('[gsd] Deprecated: free-form ROADMAP.md detected (no versioned milestone headings). ' +
|
|
336
|
-
'
|
|
345
|
+
'The project has phase_id_convention set to "milestone-prefixed" in config.json but the ' +
|
|
346
|
+
'ROADMAP does not use versioned milestone headings. Run `gsd-tools roadmap upgrade --convention milestone-prefixed` to migrate (dry-run by default).');
|
|
337
347
|
}
|
|
338
348
|
if (versionOverride) {
|
|
339
349
|
const escapedVersion = escapeRegex(versionOverride);
|
|
@@ -1607,6 +1607,238 @@ function convertClaudeToKiloFrontmatter(content, { isAgent = false } = {}) {
|
|
|
1607
1607
|
const newFrontmatter = newLines.join('\n').trim();
|
|
1608
1608
|
return `---\n${newFrontmatter}\n---${body}`;
|
|
1609
1609
|
}
|
|
1610
|
+
// ── Agent converters — #1182 extraction ─────────────────────────────────────
|
|
1611
|
+
// These were previously only in bin/install.js. Extracted here so the module
|
|
1612
|
+
// is self-contained and #1173 descriptor-driven dispatch can call them without
|
|
1613
|
+
// reaching through the Installer Module.
|
|
1614
|
+
// NOTE: Do NOT remove the inline copies from bin/install.js in this PR —
|
|
1615
|
+
// that is #1175. This PR only adds them to the module's export surface.
|
|
1616
|
+
// Copilot tool name mapping — Claude Code tools to GitHub Copilot tools
|
|
1617
|
+
// Tool mapping applies ONLY to agents, NOT to skills (per CONTEXT.md decision)
|
|
1618
|
+
const claudeToCopilotTools = {
|
|
1619
|
+
Read: 'read',
|
|
1620
|
+
Write: 'edit',
|
|
1621
|
+
Edit: 'edit',
|
|
1622
|
+
Bash: 'execute',
|
|
1623
|
+
Grep: 'search',
|
|
1624
|
+
Glob: 'search',
|
|
1625
|
+
Task: 'agent',
|
|
1626
|
+
WebSearch: 'web',
|
|
1627
|
+
WebFetch: 'web',
|
|
1628
|
+
TodoWrite: 'todo',
|
|
1629
|
+
AskUserQuestion: 'ask_user',
|
|
1630
|
+
SlashCommand: 'skill',
|
|
1631
|
+
};
|
|
1632
|
+
// Tool name mapping from Claude Code to Gemini CLI
|
|
1633
|
+
// Gemini CLI uses snake_case built-in tool names
|
|
1634
|
+
const claudeToGeminiTools = {
|
|
1635
|
+
Read: 'read_file',
|
|
1636
|
+
Write: 'write_file',
|
|
1637
|
+
Edit: 'replace',
|
|
1638
|
+
Bash: 'run_shell_command',
|
|
1639
|
+
Glob: 'glob',
|
|
1640
|
+
Grep: 'search_file_content',
|
|
1641
|
+
WebSearch: 'google_web_search',
|
|
1642
|
+
WebFetch: 'web_fetch',
|
|
1643
|
+
TodoWrite: 'write_todos',
|
|
1644
|
+
};
|
|
1645
|
+
/**
|
|
1646
|
+
* Convert a Claude Code tool name to Gemini CLI format
|
|
1647
|
+
* - Applies Claude→Gemini mapping (Read→read_file, Bash→run_shell_command, etc.)
|
|
1648
|
+
* - Filters out MCP tools (mcp__*) — they are auto-discovered at runtime in Gemini
|
|
1649
|
+
* - Filters out Task/Agent — agents are auto-registered as tools in Gemini
|
|
1650
|
+
* @returns {string|null} Gemini tool name, or null if tool should be excluded
|
|
1651
|
+
*/
|
|
1652
|
+
function convertGeminiToolName(claudeTool) {
|
|
1653
|
+
// MCP tools: exclude — auto-discovered from mcpServers config at runtime
|
|
1654
|
+
if (claudeTool.startsWith('mcp__')) {
|
|
1655
|
+
return null;
|
|
1656
|
+
}
|
|
1657
|
+
// Task/Agent: exclude — agents are auto-registered as callable tools.
|
|
1658
|
+
// AskUserQuestion: exclude — Gemini CLI does not expose an ask_user tool;
|
|
1659
|
+
// emitting it causes frontmatter validation errors (#3362).
|
|
1660
|
+
if (claudeTool === 'Task' ||
|
|
1661
|
+
claudeTool === 'Agent' ||
|
|
1662
|
+
claudeTool === 'AskUserQuestion' ||
|
|
1663
|
+
claudeTool === 'ask_user') {
|
|
1664
|
+
return null;
|
|
1665
|
+
}
|
|
1666
|
+
// Check for explicit mapping
|
|
1667
|
+
if (claudeToGeminiTools[claudeTool]) {
|
|
1668
|
+
return claudeToGeminiTools[claudeTool];
|
|
1669
|
+
}
|
|
1670
|
+
// Default: lowercase
|
|
1671
|
+
return claudeTool.toLowerCase();
|
|
1672
|
+
}
|
|
1673
|
+
/**
|
|
1674
|
+
* Convert a Claude Code tool name to GitHub Copilot format.
|
|
1675
|
+
* - Applies explicit mapping from claudeToCopilotTools
|
|
1676
|
+
* - Handles mcp__context7__* prefix → io.github.upstash/context7/*
|
|
1677
|
+
* - Falls back to lowercase for unknown tools
|
|
1678
|
+
*/
|
|
1679
|
+
function convertCopilotToolName(claudeTool) {
|
|
1680
|
+
// mcp__context7__* wildcard → io.github.upstash/context7/*
|
|
1681
|
+
if (claudeTool.startsWith('mcp__context7__')) {
|
|
1682
|
+
return 'io.github.upstash/context7/' + claudeTool.slice('mcp__context7__'.length);
|
|
1683
|
+
}
|
|
1684
|
+
// Check explicit mapping
|
|
1685
|
+
if (claudeToCopilotTools[claudeTool]) {
|
|
1686
|
+
return claudeToCopilotTools[claudeTool];
|
|
1687
|
+
}
|
|
1688
|
+
// mcp__{tavily,ref,jina,exa,firecrawl}__* use the generic MCP passthrough like exa/firecrawl;
|
|
1689
|
+
// add explicit Copilot registry mappings when the io.github ids are confirmed (#657 follow-up)
|
|
1690
|
+
// Default: lowercase
|
|
1691
|
+
return claudeTool.toLowerCase();
|
|
1692
|
+
}
|
|
1693
|
+
/**
|
|
1694
|
+
* Convert a Claude agent (.md) to a GitHub Copilot agent.
|
|
1695
|
+
* CONV-04: JSON array format. CONV-05: Tool name mapping.
|
|
1696
|
+
*/
|
|
1697
|
+
function convertClaudeAgentToCopilotAgent(content, isGlobal = false) {
|
|
1698
|
+
const converted = convertClaudeToCopilotContent(content, isGlobal);
|
|
1699
|
+
const { frontmatter, body } = extractFrontmatterAndBody(converted);
|
|
1700
|
+
if (!frontmatter)
|
|
1701
|
+
return converted;
|
|
1702
|
+
const name = extractFrontmatterField(frontmatter, 'name') || 'unknown';
|
|
1703
|
+
const description = extractFrontmatterField(frontmatter, 'description') || '';
|
|
1704
|
+
const color = extractFrontmatterField(frontmatter, 'color');
|
|
1705
|
+
const toolsRaw = extractFrontmatterField(frontmatter, 'tools') || '';
|
|
1706
|
+
// CONV-04 + CONV-05: Map tools, deduplicate, format as JSON array
|
|
1707
|
+
const claudeTools = toolsRaw.split(',').map(t => t.trim()).filter(Boolean);
|
|
1708
|
+
const mappedTools = claudeTools.map(t => convertCopilotToolName(t));
|
|
1709
|
+
const uniqueTools = [...new Set(mappedTools)];
|
|
1710
|
+
const toolsArray = uniqueTools.length > 0
|
|
1711
|
+
? "['" + uniqueTools.join("', '") + "']"
|
|
1712
|
+
: '[]';
|
|
1713
|
+
// Reconstruct frontmatter in Copilot format. Quote description (#2876)
|
|
1714
|
+
// so a leading YAML flow indicator (`[BETA] …`, `{ … }`, etc.) doesn't
|
|
1715
|
+
// crash the Copilot frontmatter loader.
|
|
1716
|
+
let fm = `---\nname: ${name}\ndescription: ${yamlQuote(description)}\ntools: ${toolsArray}\n`;
|
|
1717
|
+
if (color)
|
|
1718
|
+
fm += `color: ${color}\n`;
|
|
1719
|
+
fm += '---';
|
|
1720
|
+
return `${fm}\n${body}`;
|
|
1721
|
+
}
|
|
1722
|
+
/**
|
|
1723
|
+
* Convert a Claude agent (.md) to an Antigravity agent.
|
|
1724
|
+
* Uses Gemini tool names since Antigravity runs on Gemini 3 backend.
|
|
1725
|
+
*/
|
|
1726
|
+
function convertClaudeAgentToAntigravityAgent(content, isGlobal = false) {
|
|
1727
|
+
const converted = convertClaudeToAntigravityContent(content, isGlobal);
|
|
1728
|
+
const { frontmatter, body } = extractFrontmatterAndBody(converted);
|
|
1729
|
+
if (!frontmatter)
|
|
1730
|
+
return converted;
|
|
1731
|
+
const name = extractFrontmatterField(frontmatter, 'name') || 'unknown';
|
|
1732
|
+
const description = extractFrontmatterField(frontmatter, 'description') || '';
|
|
1733
|
+
const color = extractFrontmatterField(frontmatter, 'color');
|
|
1734
|
+
const toolsRaw = extractFrontmatterField(frontmatter, 'tools') || '';
|
|
1735
|
+
// Map tools to Gemini equivalents (reuse existing convertGeminiToolName)
|
|
1736
|
+
const claudeTools = toolsRaw.split(',').map(t => t.trim()).filter(Boolean);
|
|
1737
|
+
const mappedTools = claudeTools.map(t => convertGeminiToolName(t)).filter(Boolean);
|
|
1738
|
+
// #2876: quote description for the same reason as the skill variant.
|
|
1739
|
+
let fm = `---\nname: ${name}\ndescription: ${yamlQuote(description)}\ntools: ${mappedTools.join(', ')}\n`;
|
|
1740
|
+
if (color)
|
|
1741
|
+
fm += `color: ${color}\n`;
|
|
1742
|
+
fm += '---';
|
|
1743
|
+
return `${fm}\n${body}`;
|
|
1744
|
+
}
|
|
1745
|
+
/**
|
|
1746
|
+
* Convert Claude Code agent markdown to Cursor agent format.
|
|
1747
|
+
* Strips frontmatter fields Cursor doesn't support (color, skills),
|
|
1748
|
+
* converts tool references, and adds a role context header.
|
|
1749
|
+
*/
|
|
1750
|
+
function convertClaudeAgentToCursorAgent(content) {
|
|
1751
|
+
const converted = convertClaudeToCursorMarkdown(content);
|
|
1752
|
+
const { frontmatter, body } = extractFrontmatterAndBody(converted);
|
|
1753
|
+
if (!frontmatter)
|
|
1754
|
+
return converted;
|
|
1755
|
+
const name = extractFrontmatterField(frontmatter, 'name') || 'unknown';
|
|
1756
|
+
const description = extractFrontmatterField(frontmatter, 'description') || '';
|
|
1757
|
+
const cleanFrontmatter = `---\nname: ${yamlIdentifier(name)}\ndescription: ${yamlQuote(toSingleLine(description))}\n---`;
|
|
1758
|
+
return `${cleanFrontmatter}\n${body}`;
|
|
1759
|
+
}
|
|
1760
|
+
/**
|
|
1761
|
+
* Convert Claude Code agent markdown to Windsurf agent format.
|
|
1762
|
+
* Strips frontmatter fields Windsurf doesn't support (color, skills),
|
|
1763
|
+
* converts tool references, and adds a role context header.
|
|
1764
|
+
*/
|
|
1765
|
+
function convertClaudeAgentToWindsurfAgent(content) {
|
|
1766
|
+
const converted = convertClaudeToWindsurfMarkdown(content);
|
|
1767
|
+
const { frontmatter, body } = extractFrontmatterAndBody(converted);
|
|
1768
|
+
if (!frontmatter)
|
|
1769
|
+
return converted;
|
|
1770
|
+
const name = extractFrontmatterField(frontmatter, 'name') || 'unknown';
|
|
1771
|
+
const description = extractFrontmatterField(frontmatter, 'description') || '';
|
|
1772
|
+
const cleanFrontmatter = `---\nname: ${yamlIdentifier(name)}\ndescription: ${yamlQuote(toSingleLine(description))}\n---`;
|
|
1773
|
+
return `${cleanFrontmatter}\n${body}`;
|
|
1774
|
+
}
|
|
1775
|
+
/**
|
|
1776
|
+
* Convert Claude Code agent markdown to Augment agent format.
|
|
1777
|
+
* Strips frontmatter fields Augment doesn't support (color, skills),
|
|
1778
|
+
* converts tool references, and cleans up for Augment agents.
|
|
1779
|
+
*/
|
|
1780
|
+
function convertClaudeAgentToAugmentAgent(content) {
|
|
1781
|
+
const converted = convertClaudeToAugmentMarkdown(content);
|
|
1782
|
+
const { frontmatter, body } = extractFrontmatterAndBody(converted);
|
|
1783
|
+
if (!frontmatter)
|
|
1784
|
+
return converted;
|
|
1785
|
+
const name = extractFrontmatterField(frontmatter, 'name') || 'unknown';
|
|
1786
|
+
const description = extractFrontmatterField(frontmatter, 'description') || '';
|
|
1787
|
+
const cleanFrontmatter = `---\nname: ${yamlIdentifier(name)}\ndescription: ${yamlQuote(toSingleLine(description))}\n---`;
|
|
1788
|
+
return `${cleanFrontmatter}\n${body}`;
|
|
1789
|
+
}
|
|
1790
|
+
function convertClaudeAgentToTraeAgent(content) {
|
|
1791
|
+
const converted = convertClaudeToTraeMarkdown(content);
|
|
1792
|
+
const { frontmatter, body } = extractFrontmatterAndBody(converted);
|
|
1793
|
+
if (!frontmatter)
|
|
1794
|
+
return converted;
|
|
1795
|
+
const name = extractFrontmatterField(frontmatter, 'name') || 'unknown';
|
|
1796
|
+
const description = extractFrontmatterField(frontmatter, 'description') || '';
|
|
1797
|
+
const cleanFrontmatter = `---\nname: ${yamlIdentifier(name)}\ndescription: ${yamlQuote(toSingleLine(description))}\n---`;
|
|
1798
|
+
return `${cleanFrontmatter}\n${body}`;
|
|
1799
|
+
}
|
|
1800
|
+
function convertClaudeAgentToCodebuddyAgent(content) {
|
|
1801
|
+
const converted = convertClaudeToCodebuddyMarkdown(content);
|
|
1802
|
+
const { frontmatter, body } = extractFrontmatterAndBody(converted);
|
|
1803
|
+
if (!frontmatter)
|
|
1804
|
+
return converted;
|
|
1805
|
+
const name = extractFrontmatterField(frontmatter, 'name') || 'unknown';
|
|
1806
|
+
const description = extractFrontmatterField(frontmatter, 'description') || '';
|
|
1807
|
+
const cleanFrontmatter = `---\nname: ${yamlIdentifier(name)}\ndescription: ${yamlQuote(toSingleLine(description))}\n---`;
|
|
1808
|
+
return `${cleanFrontmatter}\n${body}`;
|
|
1809
|
+
}
|
|
1810
|
+
function convertClaudeAgentToClineAgent(content) {
|
|
1811
|
+
const converted = convertClaudeToCliineMarkdown(content);
|
|
1812
|
+
const { frontmatter, body } = extractFrontmatterAndBody(converted);
|
|
1813
|
+
if (!frontmatter)
|
|
1814
|
+
return converted;
|
|
1815
|
+
const name = extractFrontmatterField(frontmatter, 'name') || 'unknown';
|
|
1816
|
+
const description = extractFrontmatterField(frontmatter, 'description') || '';
|
|
1817
|
+
const cleanFrontmatter = `---\nname: ${yamlIdentifier(name)}\ndescription: ${yamlQuote(toSingleLine(description))}\n---`;
|
|
1818
|
+
return `${cleanFrontmatter}\n${body}`;
|
|
1819
|
+
}
|
|
1820
|
+
/**
|
|
1821
|
+
* Convert Claude Code agent markdown to Codex agent format.
|
|
1822
|
+
* Applies base markdown conversions, then adds a <codex_agent_role> header
|
|
1823
|
+
* and cleans up frontmatter (removes tools/color fields).
|
|
1824
|
+
*/
|
|
1825
|
+
function convertClaudeAgentToCodexAgent(content) {
|
|
1826
|
+
const converted = convertClaudeToCodexMarkdown(content);
|
|
1827
|
+
const { frontmatter, body } = extractFrontmatterAndBody(converted);
|
|
1828
|
+
if (!frontmatter)
|
|
1829
|
+
return converted;
|
|
1830
|
+
const name = extractFrontmatterField(frontmatter, 'name') || 'unknown';
|
|
1831
|
+
const description = extractFrontmatterField(frontmatter, 'description') || '';
|
|
1832
|
+
const tools = extractFrontmatterField(frontmatter, 'tools') || '';
|
|
1833
|
+
const roleHeader = `<codex_agent_role>
|
|
1834
|
+
role: ${name}
|
|
1835
|
+
tools: ${tools}
|
|
1836
|
+
purpose: ${toSingleLine(description)}
|
|
1837
|
+
</codex_agent_role>`;
|
|
1838
|
+
const cleanFrontmatter = `---\nname: ${yamlQuote(name)}\ndescription: ${yamlQuote(toSingleLine(description))}\n---`;
|
|
1839
|
+
return `${cleanFrontmatter}\n\n${roleHeader}\n${body}`;
|
|
1840
|
+
}
|
|
1841
|
+
// ── End agent converters #1182 ───────────────────────────────────────────────
|
|
1610
1842
|
/**
|
|
1611
1843
|
* Shared SKILL.md writer for the OpenCode-family runtimes (OpenCode + Kilo),
|
|
1612
1844
|
* which share a config schema (Kilo derives from OpenCode). OpenCode discovers
|
|
@@ -1697,4 +1929,18 @@ module.exports = {
|
|
|
1697
1929
|
convertClaudeCommandToKiloSkill,
|
|
1698
1930
|
readGsdCommandNames,
|
|
1699
1931
|
transformContentToHyphen,
|
|
1932
|
+
// #1182: agent converters + tool-name table dependency closure
|
|
1933
|
+
claudeToCopilotTools,
|
|
1934
|
+
convertCopilotToolName,
|
|
1935
|
+
claudeToGeminiTools,
|
|
1936
|
+
convertGeminiToolName,
|
|
1937
|
+
convertClaudeAgentToCopilotAgent,
|
|
1938
|
+
convertClaudeAgentToAntigravityAgent,
|
|
1939
|
+
convertClaudeAgentToCursorAgent,
|
|
1940
|
+
convertClaudeAgentToWindsurfAgent,
|
|
1941
|
+
convertClaudeAgentToAugmentAgent,
|
|
1942
|
+
convertClaudeAgentToTraeAgent,
|
|
1943
|
+
convertClaudeAgentToCodebuddyAgent,
|
|
1944
|
+
convertClaudeAgentToClineAgent,
|
|
1945
|
+
convertClaudeAgentToCodexAgent,
|
|
1700
1946
|
};
|
|
@@ -19,7 +19,7 @@ const node_fs_1 = __importDefault(require("node:fs"));
|
|
|
19
19
|
const node_os_1 = __importDefault(require("node:os"));
|
|
20
20
|
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
21
21
|
const installProfiles = require("./install-profiles.cjs");
|
|
22
|
-
const { stageSkillsForProfile, stageAgentsForProfile, stageSkillsForRuntimeAsSkills, stageCommandsForRuntimeFlat, } = installProfiles;
|
|
22
|
+
const { stageSkillsForProfile, stageAgentsForProfile, stageAgentsForRuntimeWithConverter, stageSkillsForRuntimeAsSkills, stageCommandsForRuntimeFlat, } = installProfiles;
|
|
23
23
|
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
24
24
|
const runtimeArtifactConversion = require("./runtime-artifact-conversion.cjs");
|
|
25
25
|
const conversionExports = runtimeArtifactConversion;
|
|
@@ -146,6 +146,35 @@ function agentsKind(destSubpath, prefix, configDir) {
|
|
|
146
146
|
stage: (resolved) => stageAgentsForProfile(findAgentsSourceRoot(configDir), resolved),
|
|
147
147
|
};
|
|
148
148
|
}
|
|
149
|
+
/**
|
|
150
|
+
* Build a converted-agents kind descriptor for runtimes whose agent `.md` files
|
|
151
|
+
* need runtime-specific frontmatter/body conversion (e.g. Copilot, Cursor, Codex).
|
|
152
|
+
*
|
|
153
|
+
* Unlike `agentsKind` (which raw-copies source files), this kind applies
|
|
154
|
+
* `converterName` from Runtime Artifact Conversion exports to each agent file
|
|
155
|
+
* during staging, writing flat `${name}.md` files to the staged directory.
|
|
156
|
+
*
|
|
157
|
+
* Agent filenames are preserved verbatim (the prefix is already embedded in the
|
|
158
|
+
* agent stem — e.g. `gsd-planner.md`).
|
|
159
|
+
*
|
|
160
|
+
* Mirrors the `convertedCommandsKind` pattern (#785).
|
|
161
|
+
*
|
|
162
|
+
* @param destSubpath destination subpath within configDir (e.g. 'agents')
|
|
163
|
+
* @param prefix filename prefix (informational; not applied here)
|
|
164
|
+
* @param converterName name of converter function in Runtime Artifact Conversion exports
|
|
165
|
+
* @param configDir runtime config dir (for .gsd-source marker resolution)
|
|
166
|
+
*/
|
|
167
|
+
function convertedAgentsKind(destSubpath, prefix, converterName, configDir) {
|
|
168
|
+
return {
|
|
169
|
+
kind: 'agents',
|
|
170
|
+
destSubpath,
|
|
171
|
+
prefix,
|
|
172
|
+
stage: (resolved) => {
|
|
173
|
+
const converter = conversionExports[converterName];
|
|
174
|
+
return stageAgentsForRuntimeWithConverter(findAgentsSourceRoot(configDir), resolved, converter);
|
|
175
|
+
},
|
|
176
|
+
};
|
|
177
|
+
}
|
|
149
178
|
function kimiAgentsKind(destSubpath, prefix, configDir) {
|
|
150
179
|
return {
|
|
151
180
|
kind: 'kimi-agents',
|
|
@@ -262,7 +291,10 @@ function dispatchKindEntry(entry, runtime, configDir, scope) {
|
|
|
262
291
|
}
|
|
263
292
|
return convertedCommandsKind(destSubpath, prefix, converter, configDir);
|
|
264
293
|
case 'agents':
|
|
265
|
-
|
|
294
|
+
if (converter == null) {
|
|
295
|
+
return agentsKind(destSubpath, prefix, configDir);
|
|
296
|
+
}
|
|
297
|
+
return convertedAgentsKind(destSubpath, prefix, converter, configDir);
|
|
266
298
|
case 'skills':
|
|
267
299
|
if (converter == null) {
|
|
268
300
|
throw new TypeError(`resolveRuntimeArtifactLayout: skills entry for '${runtime}' has converter=null (converter is required for skills)`);
|