@opengsd/gsd-core 1.7.0-rc.5 → 1.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude-plugin/marketplace.json +1 -1
- package/.claude-plugin/plugin.json +1 -1
- package/agents/gsd-executor.md +2 -1
- package/agents/gsd-security-auditor.md +13 -15
- package/agents/gsd-ui-checker.md +2 -0
- package/agents/gsd-ui-researcher.md +1 -0
- package/bin/install.js +975 -196
- package/commands/gsd/mempalace-capture.md +27 -1
- package/commands/gsd/surface.md +6 -6
- package/gsd-core/bin/gsd-tools.cjs +63 -2
- package/gsd-core/bin/lib/api-coverage.cjs +3 -4
- package/gsd-core/bin/lib/audit.cjs +7 -6
- package/gsd-core/bin/lib/capability-registry.cjs +503 -87
- package/gsd-core/bin/lib/capability-validator.cjs +56 -18
- package/gsd-core/bin/lib/check-command-router.cjs +1 -1
- package/gsd-core/bin/lib/clock.cjs +19 -0
- package/gsd-core/bin/lib/commands.cjs +48 -9
- package/gsd-core/bin/lib/config-loader.cjs +6 -2
- package/gsd-core/bin/lib/config.cjs +12 -0
- package/gsd-core/bin/lib/core-utils.cjs +8 -2
- package/gsd-core/bin/lib/drift.cjs +4 -4
- package/gsd-core/bin/lib/frontmatter.cjs +22 -0
- package/gsd-core/bin/lib/gsd2-import.cjs +2 -1
- package/gsd-core/bin/lib/host-integration.cjs +33 -8
- package/gsd-core/bin/lib/init.cjs +60 -53
- package/gsd-core/bin/lib/install-engine.cjs +93 -22
- package/gsd-core/bin/lib/installer-migration-authoring.cjs +2 -1
- package/gsd-core/bin/lib/installer-migration-report.cjs +3 -0
- package/gsd-core/bin/lib/installer-migrations.cjs +1 -1
- package/gsd-core/bin/lib/markdown-sectionizer.cjs +342 -0
- package/gsd-core/bin/lib/markdown-table.cjs +698 -0
- package/gsd-core/bin/lib/mcp-server.cjs +18 -7
- package/gsd-core/bin/lib/milestone.cjs +217 -31
- package/gsd-core/bin/lib/phase-command-router.cjs +50 -2
- package/gsd-core/bin/lib/phase-lifecycle.cjs +62 -36
- package/gsd-core/bin/lib/phase-locator.cjs +23 -2
- package/gsd-core/bin/lib/phase.cjs +436 -61
- package/gsd-core/bin/lib/plan-scan.cjs +3 -0
- package/gsd-core/bin/lib/review-reviewer-selection.cjs +24 -7
- package/gsd-core/bin/lib/roadmap-parser.cjs +218 -13
- package/gsd-core/bin/lib/roadmap.cjs +100 -49
- package/gsd-core/bin/lib/runtime-artifact-conversion.cjs +242 -44
- package/gsd-core/bin/lib/runtime-artifact-install-plan.cjs +3 -2
- package/gsd-core/bin/lib/runtime-artifact-layout.cjs +24 -14
- package/gsd-core/bin/lib/runtime-config-adapter-registry.cjs +19 -5
- package/gsd-core/bin/lib/runtime-homes.cjs +22 -0
- package/gsd-core/bin/lib/runtime-hooks-surface.cjs +526 -29
- package/gsd-core/bin/lib/runtime-name-policy.cjs +63 -5
- package/gsd-core/bin/lib/schema-detect.cjs +2 -1
- package/gsd-core/bin/lib/security.cjs +7 -37
- package/gsd-core/bin/lib/shell-command-projection.cjs +176 -27
- package/gsd-core/bin/lib/smart-entry.cjs +4 -3
- package/gsd-core/bin/lib/stale-bake-guard.cjs +30 -10
- package/gsd-core/bin/lib/state-transition.cjs +100 -45
- package/gsd-core/bin/lib/state.cjs +391 -126
- package/gsd-core/bin/lib/surface.cjs +12 -8
- package/gsd-core/bin/lib/template.cjs +2 -1
- package/gsd-core/bin/lib/uat.cjs +54 -8
- package/gsd-core/bin/lib/ui-consideration-probe.cjs +249 -0
- package/gsd-core/bin/lib/ui-safety-gate.cjs +23 -1
- package/gsd-core/bin/lib/verify.cjs +4 -3
- package/gsd-core/bin/lib/workstream.cjs +3 -2
- package/gsd-core/bin/lib/worktree-safety.cjs +1 -1
- package/gsd-core/bin/lib/write-set.cjs +38 -0
- package/gsd-core/bin/shared/config-schema.manifest.json +2 -0
- package/gsd-core/bin/shared/model-catalog.json +8 -3
- package/gsd-core/references/checkpoints.md +12 -0
- package/gsd-core/references/ui-consideration-probe.md +73 -0
- package/gsd-core/templates/UI-SPEC.md +25 -0
- package/gsd-core/templates/VALIDATION.md +2 -0
- package/gsd-core/workflows/add-tests.md +1 -1
- package/gsd-core/workflows/audit-milestone.md +7 -4
- package/gsd-core/workflows/debug.md +2 -0
- package/gsd-core/workflows/execute-phase.md +5 -3
- package/gsd-core/workflows/fast.md +8 -22
- package/gsd-core/workflows/plan-phase.md +6 -0
- package/gsd-core/workflows/progress.md +2 -2
- package/gsd-core/workflows/quick.md +2 -0
- package/gsd-core/workflows/review.md +42 -3
- package/gsd-core/workflows/secure-phase.md +1 -1
- package/gsd-core/workflows/settings-advanced.md +7 -4
- package/gsd-core/workflows/ship.md +8 -2
- package/gsd-core/workflows/spec-phase.md +1 -1
- package/gsd-core/workflows/transition.md +1 -1
- package/gsd-core/workflows/ui-phase.md +146 -1
- package/gsd-core/workflows/validate-phase.md +2 -2
- package/hooks/dist/gsd-statusline.js +164 -14
- package/hooks/dist/gsd-windsurf-pre-command.js +275 -0
- package/hooks/dist/gsd-windsurf-pre-write.js +132 -0
- package/hooks/dist/managed-hooks-registry.cjs +2 -0
- package/hooks/gsd-statusline.js +164 -14
- package/hooks/gsd-windsurf-pre-command.js +275 -0
- package/hooks/gsd-windsurf-pre-write.js +132 -0
- package/hooks/managed-hooks-registry.cjs +2 -0
- package/package.json +10 -4
- package/pi/gsd.cjs +354 -0
- package/scripts/build-hooks.js +3 -0
- package/scripts/ci-test-scope.cjs +39 -1
- package/scripts/gen-golden-install-parity-zcode.cjs +35 -35
- package/scripts/gen-install-tree-fixtures.cjs +75 -0
- package/scripts/gen-registry.cjs +128 -0
- package/scripts/lint-allow-test-rule-refs.allowlist.json +0 -1
- package/scripts/lint-table-schema-drift.cjs +157 -0
- package/scripts/lint-test-file-count.allowlist.json +2 -1
- package/scripts/registry-schema.cjs +565 -0
- package/scripts/validate-registry.cjs +117 -0
- package/skills/gsd-mempalace-capture/SKILL.md +27 -1
- package/skills/gsd-surface/SKILL.md +6 -6
- package/vscode/browser.js +197 -0
- package/vscode/extension.js +383 -0
- package/vscode/host-binding.js +113 -0
- package/vscode/package.json +96 -0
|
@@ -26,6 +26,7 @@ const { readGsdCommandNames, transformContentToHyphen } = commandRoster;
|
|
|
26
26
|
const runtimeNamePolicy = require("./runtime-name-policy.cjs");
|
|
27
27
|
const { getDirName } = runtimeNamePolicy;
|
|
28
28
|
const capabilityRegistry = require("./capability-registry.cjs");
|
|
29
|
+
const shell_command_projection_cjs_1 = require("./shell-command-projection.cjs");
|
|
29
30
|
// #1383: resolve GSD's version WITHOUT a top-level
|
|
30
31
|
// `require('../../../package.json')`. That require ran at module load on every
|
|
31
32
|
// gsd-tools invocation (this module sits in the gsd-tools loader chain) and
|
|
@@ -66,6 +67,38 @@ function gsdVersion() {
|
|
|
66
67
|
cachedVersion = resolveVersionFrom(__dirname);
|
|
67
68
|
return cachedVersion;
|
|
68
69
|
}
|
|
70
|
+
/**
|
|
71
|
+
* Host-specific install behaviors declared on the runtime descriptor
|
|
72
|
+
* (capabilities/<runtime>/capability.json -> runtime.hostBehaviors). Mirrors
|
|
73
|
+
* bin/install.js's / install-engine.cts's `_hostBehaviors` (ADR-1239 / #2086
|
|
74
|
+
* / #2092). Returns {} for runtimes that declare none, so every behavior
|
|
75
|
+
* branch degrades to the generic path by default. Unlike the bin/install.js
|
|
76
|
+
* and install-engine.cts variants, this module already imports
|
|
77
|
+
* `capabilityRegistry` statically (see NON_CLAUDE_RUNTIMES below), so this
|
|
78
|
+
* reads it directly rather than re-require()-ing inside a try/catch.
|
|
79
|
+
*/
|
|
80
|
+
function _hostBehaviors(runtime) {
|
|
81
|
+
return ((capabilityRegistry &&
|
|
82
|
+
capabilityRegistry.runtimes &&
|
|
83
|
+
capabilityRegistry.runtimes[runtime] &&
|
|
84
|
+
capabilityRegistry.runtimes[runtime].runtime &&
|
|
85
|
+
capabilityRegistry.runtimes[runtime].runtime.hostBehaviors) ||
|
|
86
|
+
{});
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Public accessor for the `hostBehaviors.agentFileExtension` descriptor field
|
|
90
|
+
* (ADR-1239 / #2099 / #2103). Returns the runtime's declared agent-file
|
|
91
|
+
* destination-suffix rename target (e.g. copilot's `.agent.md`), or
|
|
92
|
+
* `undefined` when the runtime declares none (the generic no-rename
|
|
93
|
+
* default). Exported so callers outside this module (surface.cts's
|
|
94
|
+
* `_syncGsdDir`) can derive the SAME rename decision as
|
|
95
|
+
* install-engine.cts's staged-copy loop from ONE descriptor read, instead of
|
|
96
|
+
* duplicating a hardcoded `runtime === 'copilot'` check (#2103 fold).
|
|
97
|
+
*/
|
|
98
|
+
function agentFileExtensionFor(runtime) {
|
|
99
|
+
const ext = _hostBehaviors(runtime).agentFileExtension;
|
|
100
|
+
return typeof ext === 'string' ? ext : undefined;
|
|
101
|
+
}
|
|
69
102
|
const colorNameToHex = {
|
|
70
103
|
cyan: '#00FFFF',
|
|
71
104
|
red: '#FF0000',
|
|
@@ -412,10 +445,12 @@ function convertClaudeCommandToClaudeSkill(content, skillName, runtime = null, c
|
|
|
412
445
|
if (version)
|
|
413
446
|
fm += `version: ${yamlQuote(version)}\n`;
|
|
414
447
|
}
|
|
415
|
-
// #778 (b) —
|
|
416
|
-
//
|
|
417
|
-
//
|
|
418
|
-
|
|
448
|
+
// #778 (b) — numeric priority for /skills ordering, declared on the runtime
|
|
449
|
+
// descriptor (runtime.hostBehaviors.skillPriorityFrontmatter). Scoped to
|
|
450
|
+
// runtimes that declare the flag so Claude/Hermes skill frontmatter is
|
|
451
|
+
// unchanged (they ignore the field, but we keep their output byte-stable).
|
|
452
|
+
// skillName is the `gsd-<stem>` dir name. (ADR-1239 / #2092)
|
|
453
|
+
if (_hostBehaviors(runtime).skillPriorityFrontmatter) {
|
|
419
454
|
const stem = typeof skillName === 'string' && skillName.startsWith('gsd-')
|
|
420
455
|
? skillName.slice(4)
|
|
421
456
|
: skillName;
|
|
@@ -465,6 +500,14 @@ function convertGsdCommandReferencesToKimiSkillInvocations(content, cmdNames) {
|
|
|
465
500
|
.replace(colonPattern, (_, cmd) => `/skill:gsd-${cmd}`)
|
|
466
501
|
.replace(hyphenPattern, (_, cmd) => `/skill:gsd-${cmd}`);
|
|
467
502
|
}
|
|
503
|
+
// DEFECT.GENERATIVE-FIX: this body is mirrored in bin/install.js's
|
|
504
|
+
// convertClaudeCommandToKimiSkill (kept for bin/install.js's own
|
|
505
|
+
// module-level export/test surface; dead for the live skills-install path,
|
|
506
|
+
// which routes here via install-engine.cts's SKILLS_CONVERTER_REGISTRY
|
|
507
|
+
// through the kimi capability descriptor's artifactLayout
|
|
508
|
+
// `converter: "convertClaudeCommandToKimiSkill"`). Neither copy re-exports
|
|
509
|
+
// the other — mirror any behavior change into both. Guarded by the
|
|
510
|
+
// output-parity test in tests/runtime-converters.test.cjs (#2095).
|
|
468
511
|
function convertClaudeCommandToKimiSkill(content, skillName, _runtime = null, cmdNames = null) {
|
|
469
512
|
const { frontmatter, body } = extractFrontmatterAndBody(content);
|
|
470
513
|
const kimiSkillName = normalizeKimiSkillName(skillName);
|
|
@@ -592,6 +635,15 @@ function buildKimiSubagentYaml({ name, description, tools }) {
|
|
|
592
635
|
pushKimiToolsYaml(lines, 2, tools);
|
|
593
636
|
return `${lines.join('\n')}\n`;
|
|
594
637
|
}
|
|
638
|
+
// DEFECT.GENERATIVE-FIX: this body is mirrored in bin/install.js's
|
|
639
|
+
// buildKimiAgentArtifacts (kept for bin/install.js's own module-level
|
|
640
|
+
// export/test surface; dead for the live install path, which routes here via
|
|
641
|
+
// runtime-artifact-layout.cts's kimiAgentsKind through a dynamic
|
|
642
|
+
// `conversionExports['buildKimiAgentArtifacts']` lookup against this
|
|
643
|
+
// compiled module). Neither copy re-exports the other — mirror any behavior
|
|
644
|
+
// change into both, including the kimi_cli.tools.agent:Agent grant that
|
|
645
|
+
// enables background dispatch (#2095 Upgrade 2). Guarded by the
|
|
646
|
+
// output-parity test in tests/runtime-converters.test.cjs (#2095).
|
|
595
647
|
function buildKimiAgentArtifacts({ rootAgent = '', subagents = [], requestedSubagents = null, } = {}) {
|
|
596
648
|
const diagnostics = [];
|
|
597
649
|
const rootSource = parseKimiAgentSource(rootAgent) || { path: null, content: '' };
|
|
@@ -971,6 +1023,10 @@ function convertClaudeToAugmentMarkdown(content) {
|
|
|
971
1023
|
converted = converted.replace(/\bClaude Code\b/g, 'Augment');
|
|
972
1024
|
return converted;
|
|
973
1025
|
}
|
|
1026
|
+
// #2097 (ADR-1239): command-body converters selected by descriptor
|
|
1027
|
+
// (runtime.hostBehaviors.commandBodyConverter) instead of a runtime-name
|
|
1028
|
+
// branch. Degrade-closed: unknown/absent name → no conversion.
|
|
1029
|
+
const COMMAND_BODY_CONVERTERS = { convertClaudeToAugmentMarkdown };
|
|
974
1030
|
function getAugmentSkillAdapterHeader(skillName) {
|
|
975
1031
|
return `<augment_skill_adapter>
|
|
976
1032
|
## A. Skill Invocation
|
|
@@ -1045,6 +1101,12 @@ function convertClaudeToTraeMarkdown(content) {
|
|
|
1045
1101
|
converted = converted.replace(/\bClaude Code\b/g, 'Trae');
|
|
1046
1102
|
return converted;
|
|
1047
1103
|
}
|
|
1104
|
+
// DEFECT.GENERATIVE-FIX: this body is mirrored in bin/install.js's
|
|
1105
|
+
// convertClaudeCommandToTraeSkill (dead for the live skills-install path,
|
|
1106
|
+
// which routes here via install-engine.cts's SKILLS_CONVERTER_REGISTRY; kept
|
|
1107
|
+
// for bin/install.js's own module-level export/test surface). Neither copy
|
|
1108
|
+
// re-exports the other — mirror any behavior change into both. Guarded by
|
|
1109
|
+
// the output-parity test in tests/runtime-converters.test.cjs (#2094).
|
|
1048
1110
|
function convertClaudeCommandToTraeSkill(content, skillName) {
|
|
1049
1111
|
const converted = convertClaudeToTraeMarkdown(content);
|
|
1050
1112
|
const { frontmatter, body } = extractFrontmatterAndBody(converted);
|
|
@@ -1059,7 +1121,17 @@ function convertClaudeCommandToTraeSkill(content, skillName) {
|
|
|
1059
1121
|
const shortDescription = description.length > 180 ? `${description.slice(0, 177)}...` : description;
|
|
1060
1122
|
// #2876: quote so YAML flow indicators (`[BETA] …`) don't break Trae's
|
|
1061
1123
|
// frontmatter parser.
|
|
1062
|
-
|
|
1124
|
+
let fm = `---\nname: ${yamlIdentifier(skillName)}\ndescription: ${yamlQuote(shortDescription)}\n`;
|
|
1125
|
+
// #2094: emit `stage:` so Trae's SOLO agent can auto-invoke GSD skills at
|
|
1126
|
+
// the corresponding stage (docs.trae.ai/ide/agent). The field name/schema
|
|
1127
|
+
// is not formally documented (thin SPA docs) — descriptor-driven, single
|
|
1128
|
+
// fixed GSD-side value (runtime.hostBehaviors.soloStageMetadata), inferred/
|
|
1129
|
+
// best-effort.
|
|
1130
|
+
const soloStage = _hostBehaviors('trae').soloStageMetadata;
|
|
1131
|
+
if (soloStage)
|
|
1132
|
+
fm += `stage: ${soloStage}\n`;
|
|
1133
|
+
fm += '---';
|
|
1134
|
+
return `${fm}\n${body}`;
|
|
1063
1135
|
}
|
|
1064
1136
|
function convertSlashCommandsToCodebuddySkillMentions(content) {
|
|
1065
1137
|
return content.replace(/\/gsd:([a-z0-9-]+)/g, (_, commandName) => {
|
|
@@ -1520,7 +1592,12 @@ function convertClaudeToOpencodeFrontmatter(content, { isAgent = false, modelOve
|
|
|
1520
1592
|
return `---\n${newFrontmatter}\n---${body}`;
|
|
1521
1593
|
}
|
|
1522
1594
|
// Kilo CLI — same conversion logic as OpenCode, different config paths.
|
|
1523
|
-
|
|
1595
|
+
// DEFECT.GENERATIVE-FIX: this body is mirrored in bin/install.js's
|
|
1596
|
+
// convertClaudeToKiloFrontmatter (used by bin/install.js's own legacy install
|
|
1597
|
+
// path). Neither copy re-exports the other — mirror any behavior change into
|
|
1598
|
+
// both. Guarded by the output-parity test in tests/runtime-converters.test.cjs
|
|
1599
|
+
// (#2093).
|
|
1600
|
+
function convertClaudeToKiloFrontmatter(content, { isAgent = false, modelOverride = null } = {}) {
|
|
1524
1601
|
// Replace tool name references in content (applies to all files)
|
|
1525
1602
|
let convertedContent = content;
|
|
1526
1603
|
convertedContent = convertedContent.replace(/\bAskUserQuestion\b/g, 'question');
|
|
@@ -1666,6 +1743,14 @@ function convertClaudeToKiloFrontmatter(content, { isAgent = false } = {}) {
|
|
|
1666
1743
|
// For agents: add required Kilo agent fields
|
|
1667
1744
|
if (isAgent) {
|
|
1668
1745
|
newLines.push('mode: subagent');
|
|
1746
|
+
// Embed model override from ~/.gsd/defaults.json so model_overrides is
|
|
1747
|
+
// respected on Kilo (which uses static agent frontmatter, not inline
|
|
1748
|
+
// Task() model parameters) — mirrors convertClaudeToOpencodeFrontmatter's
|
|
1749
|
+
// model emission exactly (#2093 UPGRADE 2 / ADR-1239; Kilo is an OpenCode
|
|
1750
|
+
// fork with the same static-frontmatter model constraint). See #2256.
|
|
1751
|
+
if (modelOverride) {
|
|
1752
|
+
newLines.push(['model:', modelOverride].join(' '));
|
|
1753
|
+
}
|
|
1669
1754
|
newLines.push(...buildKiloAgentPermissionBlock(agentTools));
|
|
1670
1755
|
}
|
|
1671
1756
|
// For commands: add tools object if we had allowed-tools or tools
|
|
@@ -1875,6 +1960,76 @@ function convertClaudeAgentToTraeAgent(content) {
|
|
|
1875
1960
|
const cleanFrontmatter = `---\nname: ${yamlIdentifier(name)}\ndescription: ${yamlQuote(toSingleLine(description))}\n---`;
|
|
1876
1961
|
return `${cleanFrontmatter}\n${body}`;
|
|
1877
1962
|
}
|
|
1963
|
+
/**
|
|
1964
|
+
* Convert a Claude agent (.md) to a native Qwen Code subagent file
|
|
1965
|
+
* (`.qwen/agents/gsd-*.md` / `<qwenhome>/agents/gsd-*.md`, ADR-1239 / #2092
|
|
1966
|
+
* Phase B Upgrade 1). Qwen Code is a Claude-dialect host: its docs' "Claude
|
|
1967
|
+
* Code Compatibility Fields" section confirms CC agent files parse under
|
|
1968
|
+
* `.qwen/agents/` (https://qwenlm.github.io/qwen-code-docs/en/users/features/sub-agents),
|
|
1969
|
+
* so — unlike Cursor/Trae/Copilot/Antigravity — tool names pass through
|
|
1970
|
+
* UNCHANGED (no remapping table).
|
|
1971
|
+
*
|
|
1972
|
+
* Emits DETERMINISTIC frontmatter: `name:` + `description:` (mirrors
|
|
1973
|
+
* convertClaudeAgentToCursorAgent), plus `tools:` as a YAML block list when the
|
|
1974
|
+
* source declares one. Qwen's documented `tools:` schema is a YAML array
|
|
1975
|
+
* (`tools:\n- tool1\n- tool2`), not Claude's single-line comma-separated string
|
|
1976
|
+
* — passing the raw single-line string through unchanged would parse as one
|
|
1977
|
+
* malformed tool name and be silently dropped ("Optional fields with invalid
|
|
1978
|
+
* values are silently dropped at parse time" — same docs page). Reuses
|
|
1979
|
+
* `parseFrontmatterTools` (already relied on by the Kimi agent path), which
|
|
1980
|
+
* tolerates BOTH source formats Claude's own agents/*.md files use — the
|
|
1981
|
+
* single-line comma list (most agents) and the YAML block list (e.g.
|
|
1982
|
+
* agents/gsd-nyquist-auditor.md, agents/gsd-security-auditor.md) — so no tools
|
|
1983
|
+
* are lost regardless of which the source agent uses.
|
|
1984
|
+
*
|
|
1985
|
+
* `color` IS preserved: Qwen's docs list `color` under "Claude Code
|
|
1986
|
+
* Compatibility Fields" as a supported optional field, so it is passed
|
|
1987
|
+
* through as a plain scalar (unlike the cursor/trae/augment/windsurf
|
|
1988
|
+
* reduced-frontmatter converters, which drop it — those hosts have no such
|
|
1989
|
+
* compatibility field). `model:` and `approvalMode:` are intentionally NOT
|
|
1990
|
+
* emitted: both are optional per the docs and out of scope for #2092 (model:
|
|
1991
|
+
* would couple to the model catalog and introduce nondeterminism;
|
|
1992
|
+
* approvalMode is a deliberate follow-on).
|
|
1993
|
+
*
|
|
1994
|
+
* Body: preserved verbatim after the qwen branding rewrite (CLAUDE.md /
|
|
1995
|
+
* Claude Code / .claude/ literal-substring values — descriptor-driven via
|
|
1996
|
+
* runtime.hostBehaviors.brandingRewrites, mirrors the qwen case in
|
|
1997
|
+
* _applyRuntimeRewrites). The anchored `~/.claude/` / `$HOME/.claude/` forms
|
|
1998
|
+
* are already rewritten upstream by applyAgentPathRewrites (agentCtx Step 1 in
|
|
1999
|
+
* stageAgentsForRuntimeWithConverter) before this converter runs, so only the
|
|
2000
|
+
* bare/non-anchored forms are handled here — mirrors how
|
|
2001
|
+
* convertClaudeToTraeMarkdown orders its bare-form rewrites after the slash
|
|
2002
|
+
* forms to avoid double-rewriting the same substring.
|
|
2003
|
+
*/
|
|
2004
|
+
function convertClaudeAgentToQwenAgent(content) {
|
|
2005
|
+
const _b = _hostBehaviors('qwen').brandingRewrites || {};
|
|
2006
|
+
let converted = content;
|
|
2007
|
+
if (_b['CLAUDE.md'])
|
|
2008
|
+
converted = converted.replace(/CLAUDE\.md/g, _b['CLAUDE.md']);
|
|
2009
|
+
if (_b['Claude Code'])
|
|
2010
|
+
converted = converted.replace(/\bClaude Code\b/g, _b['Claude Code']);
|
|
2011
|
+
if (_b['.claude/'])
|
|
2012
|
+
converted = converted.replace(/\.claude\//g, _b['.claude/']);
|
|
2013
|
+
const { frontmatter, body } = extractFrontmatterAndBody(converted);
|
|
2014
|
+
if (!frontmatter)
|
|
2015
|
+
return converted;
|
|
2016
|
+
const name = extractFrontmatterField(frontmatter, 'name') || 'unknown';
|
|
2017
|
+
const description = extractFrontmatterField(frontmatter, 'description') || '';
|
|
2018
|
+
const tools = parseFrontmatterTools(frontmatter);
|
|
2019
|
+
const color = extractFrontmatterField(frontmatter, 'color');
|
|
2020
|
+
let fm = `---\nname: ${yamlIdentifier(name)}\ndescription: ${yamlQuote(toSingleLine(description))}\n`;
|
|
2021
|
+
if (tools.length > 0) {
|
|
2022
|
+
fm += 'tools:\n';
|
|
2023
|
+
for (const tool of tools) {
|
|
2024
|
+
fm += ` - ${yamlIdentifier(tool)}\n`;
|
|
2025
|
+
}
|
|
2026
|
+
}
|
|
2027
|
+
if (color) {
|
|
2028
|
+
fm += `color: ${yamlIdentifier(color)}\n`;
|
|
2029
|
+
}
|
|
2030
|
+
fm += '---';
|
|
2031
|
+
return `${fm}\n${body}`;
|
|
2032
|
+
}
|
|
1878
2033
|
function convertClaudeAgentToCodebuddyAgent(content) {
|
|
1879
2034
|
const converted = convertClaudeToCodebuddyMarkdown(content);
|
|
1880
2035
|
const { frontmatter, body } = extractFrontmatterAndBody(converted);
|
|
@@ -1989,8 +2144,8 @@ function computePathPrefix({ isGlobal, isOpencode, isWindowsHost: _isWindowsHost
|
|
|
1989
2144
|
// Without this, path.join on Windows produces a backslash prefix that
|
|
1990
2145
|
// leaks into markdown content and breaks cross-platform substring checks.
|
|
1991
2146
|
// See DEFECT.WINDOWS-PATH-LEAK-IN-MARKDOWN-CONTENT in CONTEXT.md.
|
|
1992
|
-
const posixTarget = String(resolvedTarget)
|
|
1993
|
-
const posixHome = homeDir ? String(homeDir)
|
|
2147
|
+
const posixTarget = (0, shell_command_projection_cjs_1.posixNormalize)(String(resolvedTarget));
|
|
2148
|
+
const posixHome = homeDir ? (0, shell_command_projection_cjs_1.posixNormalize)(String(homeDir)) : homeDir;
|
|
1994
2149
|
if (isGlobal && posixTarget.startsWith(posixHome) && !isOpencode) {
|
|
1995
2150
|
return '$HOME' + posixTarget.slice(posixHome.length) + '/';
|
|
1996
2151
|
}
|
|
@@ -2087,19 +2242,24 @@ function _applyRuntimeRewrites(content, runtime, pathPrefix, isGlobal = false, a
|
|
|
2087
2242
|
content = processAttribution(content, attribution);
|
|
2088
2243
|
break;
|
|
2089
2244
|
}
|
|
2090
|
-
case 'augment':
|
|
2245
|
+
case 'augment': {
|
|
2091
2246
|
content = content.replace(/~\/\.claude\//g, pathPrefix);
|
|
2092
2247
|
content = content.replace(/\$HOME\/\.claude\//g, pathPrefix);
|
|
2093
2248
|
content = content.replace(/\.\/\.claude\//g, `./${dirName}/`);
|
|
2094
2249
|
content = content.replace(/~\/\.claude(?![\w-])/g, normalizedPathPrefix);
|
|
2095
2250
|
content = content.replace(/\$HOME\/\.claude(?![\w-])/g, normalizedPathPrefix);
|
|
2096
2251
|
content = content.replace(/\.\/\.claude(?![\w-])/g, `./${dirName}`);
|
|
2097
|
-
|
|
2098
|
-
|
|
2099
|
-
|
|
2100
|
-
|
|
2252
|
+
// #2097: dot-dir self-references (~/.augment/…) → resolved prefix,
|
|
2253
|
+
// dirName-derived (no runtime literal). getDirName('augment') resolves
|
|
2254
|
+
// to '.augment', so this is byte-identical to the prior hardcoded regexes.
|
|
2255
|
+
const _dd = escapeRegExp(dirName);
|
|
2256
|
+
content = content.replace(new RegExp('~/' + _dd + '/', 'g'), pathPrefix);
|
|
2257
|
+
content = content.replace(new RegExp('\\$HOME/' + _dd + '/', 'g'), pathPrefix);
|
|
2258
|
+
content = content.replace(new RegExp('~/' + _dd + '(?![\\w-])', 'g'), normalizedPathPrefix);
|
|
2259
|
+
content = content.replace(new RegExp('\\$HOME/' + _dd + '(?![\\w-])', 'g'), normalizedPathPrefix);
|
|
2101
2260
|
content = processAttribution(content, attribution);
|
|
2102
2261
|
break;
|
|
2262
|
+
}
|
|
2103
2263
|
case 'trae':
|
|
2104
2264
|
content = content.replace(/~\/\.claude\//g, pathPrefix);
|
|
2105
2265
|
content = content.replace(/\$HOME\/\.claude\//g, pathPrefix);
|
|
@@ -2107,7 +2267,10 @@ function _applyRuntimeRewrites(content, runtime, pathPrefix, isGlobal = false, a
|
|
|
2107
2267
|
content = content.replace(/~\/\.claude\b/g, normalizedPathPrefix);
|
|
2108
2268
|
content = content.replace(/\$HOME\/\.claude\b/g, normalizedPathPrefix);
|
|
2109
2269
|
content = content.replace(/\.\/\.claude\b/g, `./${dirName}`);
|
|
2110
|
-
|
|
2270
|
+
// #2094: descriptor-driven — dirName resolves to '.trae' via
|
|
2271
|
+
// getDirName()/localConfigDir, so this regex is built rather than
|
|
2272
|
+
// hardcoded as `/~\/\.trae\//g` (byte-identical output for trae).
|
|
2273
|
+
content = content.replace(new RegExp('~/' + escapeRegExp(dirName) + '/', 'g'), pathPrefix);
|
|
2111
2274
|
content = processAttribution(content, attribution);
|
|
2112
2275
|
break;
|
|
2113
2276
|
case 'codebuddy':
|
|
@@ -2135,9 +2298,20 @@ function _applyRuntimeRewrites(content, runtime, pathPrefix, isGlobal = false, a
|
|
|
2135
2298
|
content = content.replace(/\.\/\.claude\//g, `./${dirName}/`);
|
|
2136
2299
|
content = processAttribution(content, attribution);
|
|
2137
2300
|
break;
|
|
2138
|
-
|
|
2139
|
-
|
|
2140
|
-
|
|
2301
|
+
// Descriptor-driven brand literals (ADR-1239 / #2092): the qwen/hermes
|
|
2302
|
+
// brand VALUES (CLAUDE.md/Claude Code/.claude/ replacements) now read from
|
|
2303
|
+
// runtime.hostBehaviors.brandingRewrites instead of hardcoded literals.
|
|
2304
|
+
// EXACT regexes/order preserved — only the replacement values changed.
|
|
2305
|
+
case 'qwen': {
|
|
2306
|
+
// Guarded (post-review #2092): brandingRewrites is undefined if the
|
|
2307
|
+
// capability registry fails to load — degrade closed (skip the
|
|
2308
|
+
// brand-literal replacements, still apply the non-branding path
|
|
2309
|
+
// rewrites below) instead of throwing on `_b['CLAUDE.md']`.
|
|
2310
|
+
const _b = _hostBehaviors(runtime).brandingRewrites;
|
|
2311
|
+
if (_b) {
|
|
2312
|
+
content = content.replace(/CLAUDE\.md/g, _b['CLAUDE.md']);
|
|
2313
|
+
content = content.replace(/\bClaude Code\b/g, _b['Claude Code']);
|
|
2314
|
+
}
|
|
2141
2315
|
content = content.replace(/~\/\.claude\//g, pathPrefix);
|
|
2142
2316
|
content = content.replace(/\$HOME\/\.claude\//g, pathPrefix);
|
|
2143
2317
|
content = content.replace(/~\/\.qwen\//g, pathPrefix);
|
|
@@ -2146,14 +2320,22 @@ function _applyRuntimeRewrites(content, runtime, pathPrefix, isGlobal = false, a
|
|
|
2146
2320
|
content = content.replace(/\$HOME\/\.claude(?![\w-])/g, normalizedPathPrefix);
|
|
2147
2321
|
content = content.replace(/~\/\.qwen(?![\w-])/g, normalizedPathPrefix);
|
|
2148
2322
|
content = content.replace(/\$HOME\/\.qwen(?![\w-])/g, normalizedPathPrefix);
|
|
2149
|
-
|
|
2323
|
+
if (_b) {
|
|
2324
|
+
content = content.replace(/\.claude\//g, _b['.claude/']);
|
|
2325
|
+
}
|
|
2150
2326
|
content = content.replace(/\.\/\.claude\//g, `./${dirName}/`);
|
|
2151
2327
|
content = content.replace(/\.\/\.qwen\//g, `./${dirName}/`);
|
|
2152
2328
|
content = processAttribution(content, attribution);
|
|
2153
2329
|
break;
|
|
2154
|
-
|
|
2155
|
-
|
|
2156
|
-
|
|
2330
|
+
}
|
|
2331
|
+
case 'hermes': {
|
|
2332
|
+
// Guarded (post-review #2092): see qwen case above — same degrade-closed
|
|
2333
|
+
// rationale.
|
|
2334
|
+
const _b = _hostBehaviors(runtime).brandingRewrites;
|
|
2335
|
+
if (_b) {
|
|
2336
|
+
content = content.replace(/CLAUDE\.md/g, _b['CLAUDE.md']);
|
|
2337
|
+
content = content.replace(/\bClaude Code\b/g, _b['Claude Code']);
|
|
2338
|
+
}
|
|
2157
2339
|
content = content.replace(/~\/\.claude\//g, pathPrefix);
|
|
2158
2340
|
content = content.replace(/\$HOME\/\.claude\//g, pathPrefix);
|
|
2159
2341
|
content = content.replace(/~\/\.hermes\//g, pathPrefix);
|
|
@@ -2162,11 +2344,14 @@ function _applyRuntimeRewrites(content, runtime, pathPrefix, isGlobal = false, a
|
|
|
2162
2344
|
content = content.replace(/\$HOME\/\.claude(?![\w-])/g, normalizedPathPrefix);
|
|
2163
2345
|
content = content.replace(/~\/\.hermes(?![\w-])/g, normalizedPathPrefix);
|
|
2164
2346
|
content = content.replace(/\$HOME\/\.hermes(?![\w-])/g, normalizedPathPrefix);
|
|
2165
|
-
|
|
2347
|
+
if (_b) {
|
|
2348
|
+
content = content.replace(/\.claude\//g, _b['.claude/']);
|
|
2349
|
+
}
|
|
2166
2350
|
content = content.replace(/\.\/\.claude\//g, `./${dirName}/`);
|
|
2167
2351
|
content = content.replace(/\.\/\.hermes\//g, `./${dirName}/`);
|
|
2168
2352
|
content = processAttribution(content, attribution);
|
|
2169
2353
|
break;
|
|
2354
|
+
}
|
|
2170
2355
|
case 'kimi':
|
|
2171
2356
|
content = content.replace(/~\/\.claude\//g, pathPrefix);
|
|
2172
2357
|
content = content.replace(/\$HOME\/\.claude\//g, pathPrefix);
|
|
@@ -2241,8 +2426,11 @@ function applyRuntimeContentRewritesForCommandsInPlace(stagedDir, runtime, pathP
|
|
|
2241
2426
|
continue;
|
|
2242
2427
|
let content = node_fs_1.default.readFileSync(node_path_1.default.join(stagedDir, entry.name), 'utf8');
|
|
2243
2428
|
content = _applyRuntimeRewrites(content, runtime, pathPrefix, isGlobal, attribution);
|
|
2244
|
-
|
|
2245
|
-
|
|
2429
|
+
// #2097 (ADR-1239): descriptor-driven — commandBodyConverter name comes
|
|
2430
|
+
// from runtime.hostBehaviors instead of a hardcoded runtime-name branch.
|
|
2431
|
+
const _cmdConv = _hostBehaviors(runtime).commandBodyConverter;
|
|
2432
|
+
if (_cmdConv && COMMAND_BODY_CONVERTERS[_cmdConv]) {
|
|
2433
|
+
content = COMMAND_BODY_CONVERTERS[_cmdConv](content);
|
|
2246
2434
|
}
|
|
2247
2435
|
node_fs_1.default.writeFileSync(node_path_1.default.join(tempDir, entry.name), content);
|
|
2248
2436
|
}
|
|
@@ -2274,8 +2462,8 @@ function rewriteStagedSkillBodies(stagedDir, opts) {
|
|
|
2274
2462
|
const { runtime, configDir, scope = 'global', homedir = () => node_os_1.default.homedir(), platform = process.platform, resolveAttribution, } = opts;
|
|
2275
2463
|
if (!node_fs_1.default.existsSync(stagedDir))
|
|
2276
2464
|
return;
|
|
2277
|
-
const resolvedTarget = node_path_1.default.resolve(configDir)
|
|
2278
|
-
const homeDir =
|
|
2465
|
+
const resolvedTarget = (0, shell_command_projection_cjs_1.posixNormalize)(node_path_1.default.resolve(configDir));
|
|
2466
|
+
const homeDir = (0, shell_command_projection_cjs_1.posixNormalize)(homedir());
|
|
2279
2467
|
const isGlobal = scope === 'global';
|
|
2280
2468
|
const isOpencode = false; // #2087: opencode installs via the combined-family engine path, never through the generic rewrite
|
|
2281
2469
|
const isWindowsHost = platform === 'win32';
|
|
@@ -2303,8 +2491,8 @@ function rewriteStagedCommandBodies(stagedDir, opts) {
|
|
|
2303
2491
|
const { runtime, configDir, scope = 'global', homedir = () => node_os_1.default.homedir(), platform = process.platform, resolveAttribution, } = opts;
|
|
2304
2492
|
if (!node_fs_1.default.existsSync(stagedDir))
|
|
2305
2493
|
return stagedDir;
|
|
2306
|
-
const resolvedTarget = node_path_1.default.resolve(configDir)
|
|
2307
|
-
const homeDir =
|
|
2494
|
+
const resolvedTarget = (0, shell_command_projection_cjs_1.posixNormalize)(node_path_1.default.resolve(configDir));
|
|
2495
|
+
const homeDir = (0, shell_command_projection_cjs_1.posixNormalize)(homedir());
|
|
2308
2496
|
const isGlobal = scope === 'global';
|
|
2309
2497
|
const isOpencode = false; // #2087: opencode installs via the combined-family engine path, never through the generic rewrite
|
|
2310
2498
|
const isWindowsHost = platform === 'win32';
|
|
@@ -2312,25 +2500,21 @@ function rewriteStagedCommandBodies(stagedDir, opts) {
|
|
|
2312
2500
|
const attribution = resolveAttribution ? resolveAttribution(runtime) : undefined;
|
|
2313
2501
|
return applyRuntimeContentRewritesForCommandsInPlace(stagedDir, runtime, pathPrefix, isGlobal, attribution);
|
|
2314
2502
|
}
|
|
2315
|
-
/**
|
|
2316
|
-
* Runtimes that use the hyphen-namespace form `/gsd-<cmd>` in agent bodies.
|
|
2317
|
-
* claude/qwen/hermes use hyphen-name:`...` frontmatter; cursor/windsurf/etc
|
|
2318
|
-
* self-convert. Mirrors the `HYPHEN_NAME_AGENT_RUNTIMES` set in bin/install.js.
|
|
2319
|
-
*
|
|
2320
|
-
* @private — export normalizeAgentBodyForRuntime for callers.
|
|
2321
|
-
*/
|
|
2322
|
-
const HYPHEN_NAME_AGENT_RUNTIMES = new Set(['claude', 'qwen', 'hermes']);
|
|
2323
2503
|
/**
|
|
2324
2504
|
* Normalize `/gsd:<cmd>` colon refs in the agent body to `/gsd-<cmd>` for
|
|
2325
|
-
*
|
|
2326
|
-
*
|
|
2505
|
+
* runtimes that declare `runtime.hostBehaviors.hyphenNameAgentBody` on their
|
|
2506
|
+
* descriptor (claude / qwen / hermes use hyphen-`name:` frontmatter;
|
|
2507
|
+
* cursor/windsurf/etc self-convert and don't declare the flag). Descriptor-
|
|
2508
|
+
* driven (ADR-1239 / #2092) — folded from the hardcoded
|
|
2509
|
+
* `HYPHEN_NAME_AGENT_RUNTIMES` allow-list set. Mirrors the per-file call in
|
|
2510
|
+
* bin/install.js line 9370 / `shouldNormalizeHyphenNamespaceInAgentBody`.
|
|
2327
2511
|
*
|
|
2328
2512
|
* @param content raw agent file content (post-converter)
|
|
2329
2513
|
* @param runtime canonical runtime ID
|
|
2330
2514
|
* @param cmdNames gsd command names from readGsdCommandNames()
|
|
2331
2515
|
*/
|
|
2332
2516
|
function normalizeAgentBodyForRuntime(content, runtime, cmdNames) {
|
|
2333
|
-
if (
|
|
2517
|
+
if (_hostBehaviors(runtime).hyphenNameAgentBody !== true)
|
|
2334
2518
|
return content;
|
|
2335
2519
|
return transformContentToHyphen(content, cmdNames);
|
|
2336
2520
|
}
|
|
@@ -2342,9 +2526,13 @@ function normalizeAgentBodyForRuntime(content, runtime, cmdNames) {
|
|
|
2342
2526
|
* ~/\.claude\b → normalizedPathPrefix
|
|
2343
2527
|
* $HOME/\.claude\b → normalizedPathPrefix
|
|
2344
2528
|
*
|
|
2345
|
-
* Skipped for
|
|
2346
|
-
*
|
|
2347
|
-
*
|
|
2529
|
+
* Skipped for any runtime that declares `hostBehaviors.noPathRewrite`
|
|
2530
|
+
* (descriptor-driven, ADR-1239 / #2096 — folds the prior hardcoded
|
|
2531
|
+
* `runtime === 'antigravity'` literal; Antigravity does NOT do path rewrites
|
|
2532
|
+
* in the inline loop / #2103 — folds the prior hardcoded
|
|
2533
|
+
* `runtime === 'copilot'` literal onto the same descriptor field, since
|
|
2534
|
+
* copilot also skips these rewrites). NO stamp
|
|
2535
|
+
* (_stampNonClaudeRuntimeDefaults) — agents are NOT stamped in the inline loop.
|
|
2348
2536
|
*
|
|
2349
2537
|
* ADR-1235 §1: pre-converter cross-cutting for descriptor-driven agent pipeline.
|
|
2350
2538
|
* Exported as `applyAgentPathRewrites` for testing and for injection into
|
|
@@ -2353,10 +2541,10 @@ function normalizeAgentBodyForRuntime(content, runtime, cmdNames) {
|
|
|
2353
2541
|
* @param content raw agent file content
|
|
2354
2542
|
* @param runtime canonical runtime ID
|
|
2355
2543
|
* @param pathPrefix trailing-slash path prefix (e.g. '$HOME/.cursor/')
|
|
2356
|
-
* @returns content with path-prefix rewrites applied (or unchanged for copilot
|
|
2544
|
+
* @returns content with path-prefix rewrites applied (or unchanged for noPathRewrite runtimes, e.g. copilot)
|
|
2357
2545
|
*/
|
|
2358
2546
|
function applyAgentPathRewrites(content, runtime, pathPrefix) {
|
|
2359
|
-
if (runtime ===
|
|
2547
|
+
if (_hostBehaviors(runtime).noPathRewrite === true)
|
|
2360
2548
|
return content;
|
|
2361
2549
|
const normalizedPathPrefix = pathPrefix.replace(/\/$/, '');
|
|
2362
2550
|
content = content.replace(/~\/\.claude\//g, pathPrefix);
|
|
@@ -2392,6 +2580,11 @@ function processAttribution(content, attribution) {
|
|
|
2392
2580
|
}
|
|
2393
2581
|
module.exports = {
|
|
2394
2582
|
processAttribution,
|
|
2583
|
+
// #2103: public accessor for hostBehaviors.agentFileExtension, exported so
|
|
2584
|
+
// surface.cts's _syncGsdDir can derive the .agent.md rename from the SAME
|
|
2585
|
+
// descriptor read as install-engine.cts (folds a duplicated hardcoded
|
|
2586
|
+
// `runtime === 'copilot'` literal).
|
|
2587
|
+
agentFileExtensionFor,
|
|
2395
2588
|
yamlIdentifier,
|
|
2396
2589
|
yamlQuote,
|
|
2397
2590
|
toSingleLine,
|
|
@@ -2451,6 +2644,11 @@ module.exports = {
|
|
|
2451
2644
|
convertClaudeAgentToCodebuddyAgent,
|
|
2452
2645
|
convertClaudeAgentToClineAgent,
|
|
2453
2646
|
convertClaudeAgentToCodexAgent,
|
|
2647
|
+
// ADR-1239 / #2092 Phase B Upgrade 1: native .qwen/agents/*.md subagent
|
|
2648
|
+
// projection — registered by name so convertedAgentsKind's
|
|
2649
|
+
// conversionExports[converterName] dispatch (runtime-artifact-layout.cts)
|
|
2650
|
+
// can resolve it from capabilities/qwen/capability.json's agents kind.
|
|
2651
|
+
convertClaudeAgentToQwenAgent,
|
|
2454
2652
|
// #1511 ADR-1508 Phase 2: rewrite engine deep seam
|
|
2455
2653
|
// Low-level walkers (pathPrefix + attribution pre-resolved by caller):
|
|
2456
2654
|
applyRuntimeContentRewritesInPlace,
|
|
@@ -67,9 +67,10 @@ function createRuntimeArtifactInstallPlan(args) {
|
|
|
67
67
|
// to kind.stage() for agents kind entries with a converter (convertedAgentsKind).
|
|
68
68
|
// NO _stampNonClaudeRuntimeDefaults — agents are NOT stamped in the inline loop.
|
|
69
69
|
const os = _require('node:os');
|
|
70
|
+
const { posixNormalize } = _require('./shell-command-projection.cjs');
|
|
70
71
|
const homedirFn = homedir ?? (() => os.homedir());
|
|
71
|
-
const resolvedTarget = path.resolve(layout.configDir)
|
|
72
|
-
const homeDir = homedirFn()
|
|
72
|
+
const resolvedTarget = posixNormalize(path.resolve(layout.configDir));
|
|
73
|
+
const homeDir = posixNormalize(homedirFn());
|
|
73
74
|
const isGlobal = scope === 'global';
|
|
74
75
|
const isOpencode = layout.runtime === 'opencode';
|
|
75
76
|
const isWindowsHost = (platform ?? process.platform) === 'win32';
|
|
@@ -23,6 +23,7 @@ const { stageSkillsForProfile, stageAgentsForProfile, stageAgentsForRuntimeWithC
|
|
|
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;
|
|
26
|
+
const shell_command_projection_cjs_1 = require("./shell-command-projection.cjs");
|
|
26
27
|
// In .cts (CommonJS output) files, `require` is available as a global.
|
|
27
28
|
const _require = require;
|
|
28
29
|
// ---------------------------------------------------------------------------
|
|
@@ -130,19 +131,27 @@ function agentsKind(destSubpath, prefix, configDir) {
|
|
|
130
131
|
* Agent filenames are preserved verbatim (the prefix is already embedded in the
|
|
131
132
|
* agent stem — e.g. `gsd-planner.md`).
|
|
132
133
|
*
|
|
133
|
-
* #1173 SCOPE — plumbing only (
|
|
134
|
-
* converter dispatch + `isGlobal` scope threading for the descriptor's
|
|
135
|
-
* kind,
|
|
136
|
-
* `
|
|
137
|
-
* (
|
|
138
|
-
*
|
|
139
|
-
*
|
|
140
|
-
*
|
|
141
|
-
*
|
|
142
|
-
*
|
|
143
|
-
*
|
|
144
|
-
* `
|
|
145
|
-
*
|
|
134
|
+
* #1173 SCOPE — plumbing only (real install still elsewhere): this provides
|
|
135
|
+
* the converter dispatch + `isGlobal` scope threading for the descriptor's
|
|
136
|
+
* `agents` kind. As of #2092, 8 non-Claude runtimes DO declare a converted
|
|
137
|
+
* `agents` kind in their `capability.json` — qwen (`convertClaudeAgentToQwenAgent`)
|
|
138
|
+
* plus the 7 that already declared one before it (antigravity, augment,
|
|
139
|
+
* codebuddy, copilot, cursor, trae, windsurf) — so the descriptor-level
|
|
140
|
+
* declaration is no longer deferred. What IS still deferred is wiring
|
|
141
|
+
* `resolveRuntimeArtifactLayout`'s `agents` kind into the REAL install:
|
|
142
|
+
* `bin/install.js`'s agent-staging loop does not consume this module's
|
|
143
|
+
* `convertedAgentsKind` resolution at all — it dispatches the very same
|
|
144
|
+
* converter functions directly via `_hostBehaviors(runtime)` checks
|
|
145
|
+
* (`frontmatterDialect`, `brandingRewrites`, `isCopilot`/`isAntigravity`/…),
|
|
146
|
+
* duplicating the mapping declared here. That duplication is deliberate until
|
|
147
|
+
* the second `layout.kinds` consumer — `applySurface` / `/gsd:surface` /
|
|
148
|
+
* `--materialize` (`src/surface.cts`) — mirrors the legacy agent pipeline
|
|
149
|
+
* (Copilot's `.agent.md` filename rename, the cross-cutting path-prefix
|
|
150
|
+
* rewrite + attribution, stale-file cleanup, config-reading steps); declaring
|
|
151
|
+
* `bin/install.js` itself against this resolver before then would risk
|
|
152
|
+
* regressing the surface path. Until that follow-up lands, `bin/install.js`
|
|
153
|
+
* remains authoritative for the real install, and this `convertedAgentsKind`
|
|
154
|
+
* is exercised only by `/gsd:surface` and synthetic-descriptor seam tests.
|
|
146
155
|
*
|
|
147
156
|
* Mirrors the `convertedCommandsKind` pattern (#785).
|
|
148
157
|
*
|
|
@@ -184,7 +193,7 @@ function kimiAgentsKind(destSubpath, prefix, configDir) {
|
|
|
184
193
|
continue;
|
|
185
194
|
const agentPath = node_path_1.default.join(stagedAgents, entry.name);
|
|
186
195
|
subagents.push({
|
|
187
|
-
path: node_path_1.default.join('agents', entry.name)
|
|
196
|
+
path: (0, shell_command_projection_cjs_1.posixNormalize)(node_path_1.default.join('agents', entry.name)),
|
|
188
197
|
content: node_fs_1.default.readFileSync(agentPath, 'utf8'),
|
|
189
198
|
});
|
|
190
199
|
}
|
|
@@ -224,6 +233,7 @@ function skillsKind(destSubpath, prefix, converterName, runtime, configDir, nest
|
|
|
224
233
|
kind: 'skills',
|
|
225
234
|
destSubpath,
|
|
226
235
|
prefix,
|
|
236
|
+
converter: converterName,
|
|
227
237
|
stage: (resolved) => {
|
|
228
238
|
const realConverter = conversionExports[converterName];
|
|
229
239
|
// Compute cmdNames once per stage call for performance (#3583).
|
|
@@ -21,17 +21,30 @@
|
|
|
21
21
|
* false for codex / copilot / kilo / cursor / windsurf / trae / cline / kimi (legacy exclusion list).
|
|
22
22
|
* true for all other runtimes.
|
|
23
23
|
* - `finishPermissionWriter` names the finishInstall-phase dedicated config writer:
|
|
24
|
-
* 'opencode'
|
|
25
|
-
* 'kilo'
|
|
26
|
-
*
|
|
24
|
+
* 'opencode' → writes BOTH shared settings AND its own permissions file.
|
|
25
|
+
* 'kilo' → writes only its own permissions file.
|
|
26
|
+
* 'antigravity' → writes BOTH shared settings.json permissions.allow AND a
|
|
27
|
+
* standalone mcp_config.json MCP companion profile (#2096
|
|
28
|
+
* Phase B Upgrades 1+2).
|
|
29
|
+
* null → no dedicated permission writer.
|
|
27
30
|
*/
|
|
28
31
|
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
29
32
|
const { runtimes } = require('./capability-registry.cjs');
|
|
30
33
|
/** Valid sandboxTier enum values — mirrors the gen-capability-registry validator vocabulary. */
|
|
31
34
|
const VALID_SANDBOX_TIERS = new Set(['none', 'codex-agent-sandbox']);
|
|
32
|
-
/**
|
|
35
|
+
/**
|
|
36
|
+
* The complete set of 16 supported runtimes for config-adapter dispatch.
|
|
37
|
+
*
|
|
38
|
+
* Excludes runtimes whose installSurface is 'none' (#2103 — e.g. VS Code): a
|
|
39
|
+
* 'none' installSurface means the runtime has NO CLI install surface at all
|
|
40
|
+
* (Marketplace/VSIX-distributed, never dispatched through
|
|
41
|
+
* install()/finishInstall()), so it is not a "config-adapter runtime" by
|
|
42
|
+
* definition. This keeps this set in lockstep with bin/install.js's
|
|
43
|
+
* `allRuntimes` (see tests/issue-57-runtime-install-no-drift.test.cjs) without
|
|
44
|
+
* needing a separate hand-kept exclusion list.
|
|
45
|
+
*/
|
|
33
46
|
const ALLOWED_CONFIG_RUNTIMES = new Set(Object.entries(runtimes)
|
|
34
|
-
.filter(([, cap]) => cap && cap.runtime && typeof cap.runtime['installSurface'] === 'string')
|
|
47
|
+
.filter(([, cap]) => cap && cap.runtime && typeof cap.runtime['installSurface'] === 'string' && cap.runtime['installSurface'] !== 'none')
|
|
35
48
|
.map(([id]) => id));
|
|
36
49
|
/** All valid installSurface values. */
|
|
37
50
|
const INSTALL_SURFACES = Object.freeze([
|
|
@@ -41,6 +54,7 @@ const INSTALL_SURFACES = Object.freeze([
|
|
|
41
54
|
'cline-rules',
|
|
42
55
|
'cursor-hooks-json',
|
|
43
56
|
'profile-marker-only',
|
|
57
|
+
'none',
|
|
44
58
|
]);
|
|
45
59
|
/**
|
|
46
60
|
* Resolve the config adapter intent for a given runtime.
|