@hegemonart/get-design-done 1.28.6 → 1.28.7
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 +2 -2
- package/.claude-plugin/plugin.json +1 -1
- package/CHANGELOG.md +46 -0
- package/README.md +2 -0
- package/package.json +1 -1
- package/scripts/install.cjs +7 -0
- package/scripts/lib/install/converters/antigravity.cjs +48 -0
- package/scripts/lib/install/converters/augment.cjs +68 -0
- package/scripts/lib/install/converters/cline.cjs +206 -0
- package/scripts/lib/install/converters/codebuddy.cjs +55 -0
- package/scripts/lib/install/converters/codex.cjs +61 -0
- package/scripts/lib/install/converters/copilot.cjs +47 -0
- package/scripts/lib/install/converters/cursor.cjs +49 -0
- package/scripts/lib/install/converters/gemini.cjs +116 -0
- package/scripts/lib/install/converters/kilo.cjs +62 -0
- package/scripts/lib/install/converters/opencode.cjs +64 -0
- package/scripts/lib/install/converters/qwen.cjs +51 -0
- package/scripts/lib/install/converters/shared.cjs +377 -0
- package/scripts/lib/install/converters/trae.cjs +47 -0
- package/scripts/lib/install/converters/windsurf.cjs +47 -0
- package/scripts/lib/install/installer.cjs +529 -47
- package/scripts/lib/install/merge.cjs +31 -1
- package/scripts/lib/install/runtime-artifact-layout.cjs +431 -0
- package/scripts/lib/install/runtime-homes.cjs +225 -0
- package/scripts/lib/install/runtime-slash.cjs +172 -0
- package/scripts/lib/install/runtimes.cjs +25 -32
|
@@ -0,0 +1,377 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* scripts/lib/install/converters/shared.cjs — Phase 28.7 (Plan 28.7-04).
|
|
5
|
+
*
|
|
6
|
+
* Shared helpers for per-runtime SKILL.md content converters. Each
|
|
7
|
+
* runtime-specific converter (cursor.cjs, codex.cjs, copilot.cjs,
|
|
8
|
+
* antigravity.cjs in Wave 1; windsurf/augment/trae/qwen in Wave 2; etc.)
|
|
9
|
+
* composes these utilities to translate Claude-source SKILL.md content
|
|
10
|
+
* into the runtime's expected shape.
|
|
11
|
+
*
|
|
12
|
+
* Architecture ported from gsd-build/get-shit-done (MIT) — per Phase
|
|
13
|
+
* 28.7 D-02 (port architecture, not source). See NOTICE for upstream
|
|
14
|
+
* attribution. gsd-build's `convertClaudeCommandTo<Runtime>Skill` family
|
|
15
|
+
* bundled all per-runtime conversion logic into a single bin/install.js
|
|
16
|
+
* monolith; our modular re-implementation factors the shared rewrites
|
|
17
|
+
* here and leaves runtime-specific composition to per-runtime files.
|
|
18
|
+
*
|
|
19
|
+
* Exports (D-05):
|
|
20
|
+
* - extractFrontmatterAndBody(content)
|
|
21
|
+
* → { frontmatter: string|null, body: string }
|
|
22
|
+
* - rewriteSlashRefs(body, targetRuntime) → string
|
|
23
|
+
* Rewrites in-prose `/gdd-name`, `gdd-name`, `/gdd:name`, `$gdd-name`
|
|
24
|
+
* references to the runtime-canonical form via
|
|
25
|
+
* `../runtime-slash.cjs#formatGddSlash`. Only operates on prose;
|
|
26
|
+
* fenced code blocks are passed through untouched.
|
|
27
|
+
* - rewriteCodeFenceTools(body, toolMap) → string
|
|
28
|
+
* The inverse: ONLY rewrites inside fenced code blocks. Replaces
|
|
29
|
+
* `OldName(` with `NewName(` for every `{ OldName: NewName }` in
|
|
30
|
+
* `toolMap`. Used by the codex converter to apply CODEX_TOOL_MAP.
|
|
31
|
+
* - ensureAdapterHeader(body, runtimeDisplay) → string
|
|
32
|
+
* Prepends a 2-3 line HTML comment ("Auto-generated from Claude
|
|
33
|
+
* SKILL.md") before the first non-blank body line. Idempotent —
|
|
34
|
+
* running it twice does not duplicate the header.
|
|
35
|
+
* - buildFrontmatter(originalFrontmatter, skillName, runtimePrefix) → string
|
|
36
|
+
* Re-emits a YAML frontmatter block. `name:` is normalized to
|
|
37
|
+
* `<runtimePrefix><skillName>` (stripping the prefix if it was
|
|
38
|
+
* already present in the source). Other fields (description,
|
|
39
|
+
* tools, etc.) round-trip verbatim. Returns a string ending in
|
|
40
|
+
* `\n---\n`.
|
|
41
|
+
* - CODEX_TOOL_MAP
|
|
42
|
+
* Frozen constant — Phase 21 `reference/codex-tools.md` mapping
|
|
43
|
+
* (Read→read_file, Write/Edit→apply_patch, Bash/Grep/Glob→shell,
|
|
44
|
+
* WebSearch→web_search, WebFetch→shell).
|
|
45
|
+
*
|
|
46
|
+
* Pure / side-effect-free at module load and at every export call:
|
|
47
|
+
* - No fs / path top-level requires (all transforms operate on the
|
|
48
|
+
* `content` string argument).
|
|
49
|
+
* - No env mutation.
|
|
50
|
+
* - No globals.
|
|
51
|
+
* The only external runtime require is `../runtime-slash.cjs`, lazy-
|
|
52
|
+
* loaded inside `rewriteSlashRefs` to keep the static dependency graph
|
|
53
|
+
* thin (this file is also imported by Wave 2/3/4 plans which may not
|
|
54
|
+
* need slash rewrites if their target runtime is Claude-shape).
|
|
55
|
+
*
|
|
56
|
+
* Per Phase 28.7 D-08 the converter cluster is intentionally modular
|
|
57
|
+
* (one file per runtime, none re-export each other). shared.cjs is the
|
|
58
|
+
* sole cross-runtime module — used by all 13 converters.
|
|
59
|
+
*
|
|
60
|
+
* Per Phase 28.7 D-06 only the codex converter applies CODEX_TOOL_MAP;
|
|
61
|
+
* the other 12 runtimes accept Claude-compatible tool names verbatim.
|
|
62
|
+
*
|
|
63
|
+
* Conventions:
|
|
64
|
+
* - "frontmatter" = YAML between leading `---` delimiters; matches
|
|
65
|
+
* `^---\r?\n([\s\S]*?)\r?\n---\r?\n` (CRLF tolerant — Phase 28.6
|
|
66
|
+
* Windows-line-ending lesson).
|
|
67
|
+
* - "body" = everything after the closing `---`.
|
|
68
|
+
* - "code fence" = ```...``` block (3+ backticks, language tag optional).
|
|
69
|
+
* We use a coarse fence-aware splitter — backtick variants and
|
|
70
|
+
* tilde fences are not currently supported (out of scope; the
|
|
71
|
+
* plugin's SKILL.md sources use triple-backtick exclusively).
|
|
72
|
+
*/
|
|
73
|
+
|
|
74
|
+
// ---------------------------------------------------------------------------
|
|
75
|
+
// CODEX_TOOL_MAP — Phase 21 reference (D-06)
|
|
76
|
+
// ---------------------------------------------------------------------------
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Claude tool name → Codex tool name. Locked by Phase 21
|
|
80
|
+
* `reference/codex-tools.md`. Skills referenced as `Read(...)`,
|
|
81
|
+
* `Write(...)`, etc. in Claude-source code fences are rewritten to
|
|
82
|
+
* Codex's vocabulary at install time.
|
|
83
|
+
*
|
|
84
|
+
* Note: `Task` is intentionally absent. Per Phase 21 codex-tools.md
|
|
85
|
+
* "Known gaps", Codex does not expose nested-session as a tool call;
|
|
86
|
+
* skills that rely on Task call the gdd-sdk CLI via `shell(...)`. The
|
|
87
|
+
* codex converter leaves `Task(...)` references untouched so prose
|
|
88
|
+
* fallback prose ("on Codex this becomes shell('npx gdd-sdk ...')") is
|
|
89
|
+
* still readable.
|
|
90
|
+
*
|
|
91
|
+
* Frozen to prevent accidental mutation by downstream converters.
|
|
92
|
+
*/
|
|
93
|
+
const CODEX_TOOL_MAP = Object.freeze({
|
|
94
|
+
Read: 'read_file',
|
|
95
|
+
Write: 'apply_patch',
|
|
96
|
+
Edit: 'apply_patch',
|
|
97
|
+
Bash: 'shell',
|
|
98
|
+
Grep: 'shell',
|
|
99
|
+
Glob: 'shell',
|
|
100
|
+
WebSearch: 'web_search',
|
|
101
|
+
WebFetch: 'shell',
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
// ---------------------------------------------------------------------------
|
|
105
|
+
// extractFrontmatterAndBody — YAML frontmatter parser
|
|
106
|
+
// ---------------------------------------------------------------------------
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* Split a SKILL.md content string into its YAML frontmatter and body.
|
|
110
|
+
*
|
|
111
|
+
* Matches the leading `---\n...\n---\n` block (CRLF tolerant). If no
|
|
112
|
+
* frontmatter is present, returns `{ frontmatter: null, body: content }`.
|
|
113
|
+
*
|
|
114
|
+
* @param {string} content
|
|
115
|
+
* @returns {{ frontmatter: string|null, body: string }}
|
|
116
|
+
*/
|
|
117
|
+
function extractFrontmatterAndBody(content) {
|
|
118
|
+
if (typeof content !== 'string' || content === '') {
|
|
119
|
+
return { frontmatter: null, body: content || '' };
|
|
120
|
+
}
|
|
121
|
+
const m = content.match(/^---\r?\n([\s\S]*?)\r?\n---\r?\n([\s\S]*)$/);
|
|
122
|
+
if (!m) return { frontmatter: null, body: content };
|
|
123
|
+
return { frontmatter: m[1], body: m[2] };
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
// ---------------------------------------------------------------------------
|
|
127
|
+
// Code-fence-aware splitter (internal)
|
|
128
|
+
// ---------------------------------------------------------------------------
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* Split `body` into alternating segments of [prose, fence, prose, fence, ...].
|
|
132
|
+
* Index 0 (and every even index) is prose; every odd index is a complete
|
|
133
|
+
* fenced code block (including the opening/closing ``` lines).
|
|
134
|
+
*
|
|
135
|
+
* This lets `rewriteSlashRefs` operate ONLY on even indices and
|
|
136
|
+
* `rewriteCodeFenceTools` operate ONLY on odd indices, without either
|
|
137
|
+
* leaking into the other's domain.
|
|
138
|
+
*
|
|
139
|
+
* Coarse: a fence is any line beginning with three backticks (with or
|
|
140
|
+
* without a language tag) up to the next such line. Nested fences are
|
|
141
|
+
* not supported (irrelevant for our SKILL.md sources).
|
|
142
|
+
*
|
|
143
|
+
* @param {string} body
|
|
144
|
+
* @returns {string[]} alternating prose / fence segments
|
|
145
|
+
*/
|
|
146
|
+
function splitByCodeFence(body) {
|
|
147
|
+
// Match a complete fenced block: opening ```[lang]\n ... \n``` (closing
|
|
148
|
+
// fence on its own line). The opening fence's backticks must be at the
|
|
149
|
+
// start of a line to avoid matching inline triple-backticks in prose.
|
|
150
|
+
// The pattern is non-greedy so consecutive fences each form one segment.
|
|
151
|
+
const fenceRe = /(^```[^\n]*\n[\s\S]*?\n```)/gm;
|
|
152
|
+
return body.split(fenceRe);
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
// ---------------------------------------------------------------------------
|
|
156
|
+
// rewriteSlashRefs — prose-only slash rewrite
|
|
157
|
+
// ---------------------------------------------------------------------------
|
|
158
|
+
|
|
159
|
+
/**
|
|
160
|
+
* Rewrite every in-prose `/gdd-name`, `gdd-name`, `/gdd:name`, `gdd:name`,
|
|
161
|
+
* `$gdd-name`, `$gdd:name` reference to the canonical slash form for
|
|
162
|
+
* `targetRuntime` (via `runtime-slash.cjs#formatGddSlash`).
|
|
163
|
+
*
|
|
164
|
+
* Operates on prose only — fenced code blocks pass through unchanged.
|
|
165
|
+
* (For codex, that means tool calls like `Bash(command="/gdd-x")` keep
|
|
166
|
+
* the slash form in shell strings — those are runtime-evaluated by the
|
|
167
|
+
* codex shell, not the Codex tool surface, so they must remain unchanged.)
|
|
168
|
+
*
|
|
169
|
+
* Inline code spans (`` `...` ``) are also passed through — they're prose
|
|
170
|
+
* to the markdown renderer but Claude's literal-form quoting (`` `/gdd-x` ``)
|
|
171
|
+
* appears in user-facing text and should usually be rewritten too. We
|
|
172
|
+
* therefore DO rewrite inside inline code spans (the regex doesn't
|
|
173
|
+
* special-case them). This matches gsd-build's behavior — converters
|
|
174
|
+
* rewrite slash references everywhere except fenced blocks.
|
|
175
|
+
*
|
|
176
|
+
* Pattern: `\b[/$]?gdd[-:][a-z0-9-]+\b` (case-insensitive on prefix; the
|
|
177
|
+
* skill-name portion `[a-z0-9-]+` matches the actual skill-name
|
|
178
|
+
* convention — lowercase + dashes + digits).
|
|
179
|
+
*
|
|
180
|
+
* Defensive: if `targetRuntime` is omitted, defaults to `'claude'` (i.e.
|
|
181
|
+
* `/gdd-<name>` shape).
|
|
182
|
+
*
|
|
183
|
+
* @param {string} body
|
|
184
|
+
* @param {string} [targetRuntime]
|
|
185
|
+
* @returns {string}
|
|
186
|
+
*/
|
|
187
|
+
function rewriteSlashRefs(body, targetRuntime) {
|
|
188
|
+
if (typeof body !== 'string' || body === '') return body || '';
|
|
189
|
+
const { formatGddSlash } = require('../runtime-slash.cjs');
|
|
190
|
+
const rt = targetRuntime || 'claude';
|
|
191
|
+
|
|
192
|
+
const segments = splitByCodeFence(body);
|
|
193
|
+
// Pattern: optional `/` or `$` prefix, `gdd-` or `gdd:`, then the
|
|
194
|
+
// skill-name token. Skill names are lowercase + dashes + digits per
|
|
195
|
+
// GDD convention; the regex is case-insensitive on the `gdd` letters
|
|
196
|
+
// to accept malformed inputs.
|
|
197
|
+
const slashRe = /[/$]?gdd[-:][a-z][a-z0-9-]*/gi;
|
|
198
|
+
|
|
199
|
+
for (let i = 0; i < segments.length; i++) {
|
|
200
|
+
// Even indices are prose; odd are fenced code blocks (passthrough).
|
|
201
|
+
if (i % 2 === 1) continue;
|
|
202
|
+
segments[i] = segments[i].replace(slashRe, (match) =>
|
|
203
|
+
formatGddSlash(match, rt)
|
|
204
|
+
);
|
|
205
|
+
}
|
|
206
|
+
return segments.join('');
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
// ---------------------------------------------------------------------------
|
|
210
|
+
// rewriteCodeFenceTools — fence-only tool-name rewrite
|
|
211
|
+
// ---------------------------------------------------------------------------
|
|
212
|
+
|
|
213
|
+
/**
|
|
214
|
+
* Rewrite Claude tool names to runtime-equivalent names INSIDE fenced
|
|
215
|
+
* code blocks only. For every `{ OldName: NewName }` in `toolMap`,
|
|
216
|
+
* replace `\bOldName(` with `NewName(` in every fenced block.
|
|
217
|
+
*
|
|
218
|
+
* Prose mentions of tool names (e.g. "Use the Bash tool to ...") are
|
|
219
|
+
* left untouched — they're documentation about the Claude vocabulary
|
|
220
|
+
* and the converter's adapter header tells the user we've adapted the
|
|
221
|
+
* underlying calls. Only the actual code-fenced invocation form gets
|
|
222
|
+
* rewritten.
|
|
223
|
+
*
|
|
224
|
+
* Used by the codex converter with CODEX_TOOL_MAP. Other converters
|
|
225
|
+
* pass an empty map (and the function is a no-op).
|
|
226
|
+
*
|
|
227
|
+
* @param {string} body
|
|
228
|
+
* @param {Record<string,string>} toolMap
|
|
229
|
+
* @returns {string}
|
|
230
|
+
*/
|
|
231
|
+
function rewriteCodeFenceTools(body, toolMap) {
|
|
232
|
+
if (typeof body !== 'string' || body === '') return body || '';
|
|
233
|
+
if (!toolMap || typeof toolMap !== 'object') return body;
|
|
234
|
+
const keys = Object.keys(toolMap);
|
|
235
|
+
if (keys.length === 0) return body;
|
|
236
|
+
|
|
237
|
+
const segments = splitByCodeFence(body);
|
|
238
|
+
for (let i = 0; i < segments.length; i++) {
|
|
239
|
+
// Even indices are prose (skip); odd are fenced code blocks.
|
|
240
|
+
if (i % 2 === 0) continue;
|
|
241
|
+
let fence = segments[i];
|
|
242
|
+
for (const oldName of keys) {
|
|
243
|
+
const newName = toolMap[oldName];
|
|
244
|
+
// \b<OldName>\( — word boundary then literal `(`.
|
|
245
|
+
// Escape the old name even though tool names are alphanumeric;
|
|
246
|
+
// future map entries may include `_` or `.` (still safe under \b).
|
|
247
|
+
const re = new RegExp(
|
|
248
|
+
'\\b' + oldName.replace(/[.*+?^${}()|[\]\\]/g, '\\$&') + '\\(',
|
|
249
|
+
'g'
|
|
250
|
+
);
|
|
251
|
+
fence = fence.replace(re, newName + '(');
|
|
252
|
+
}
|
|
253
|
+
segments[i] = fence;
|
|
254
|
+
}
|
|
255
|
+
return segments.join('');
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
// ---------------------------------------------------------------------------
|
|
259
|
+
// ensureAdapterHeader — idempotent header injection
|
|
260
|
+
// ---------------------------------------------------------------------------
|
|
261
|
+
|
|
262
|
+
/**
|
|
263
|
+
* Prepend a 2-line HTML comment "Auto-generated from Claude SKILL.md"
|
|
264
|
+
* before the first non-blank line of `body`. Idempotent — running it
|
|
265
|
+
* twice produces a single header.
|
|
266
|
+
*
|
|
267
|
+
* Format:
|
|
268
|
+
* `<!-- gdd: auto-generated from Claude SKILL.md. <runtimeDisplay> adapter -->\n\n`
|
|
269
|
+
*
|
|
270
|
+
* Detection: if `body` already contains a `<runtimeDisplay> adapter`
|
|
271
|
+
* marker (anywhere in the first 500 chars — fast scan), the header is
|
|
272
|
+
* NOT re-prepended. This is the idempotency guarantee.
|
|
273
|
+
*
|
|
274
|
+
* @param {string} body
|
|
275
|
+
* @param {string} runtimeDisplay e.g. `'Cursor'`, `'Codex'`, `'Copilot'`,
|
|
276
|
+
* `'Antigravity'`. Used inside the comment text verbatim.
|
|
277
|
+
* @returns {string}
|
|
278
|
+
*/
|
|
279
|
+
function ensureAdapterHeader(body, runtimeDisplay) {
|
|
280
|
+
if (typeof body !== 'string') return body;
|
|
281
|
+
const display = String(runtimeDisplay || 'Adapter');
|
|
282
|
+
|
|
283
|
+
const marker = display + ' adapter';
|
|
284
|
+
// Fast scan first ~500 chars — header is always at the very top if
|
|
285
|
+
// present; we don't need to scan the whole body.
|
|
286
|
+
const head = body.slice(0, 500);
|
|
287
|
+
if (head.indexOf(marker) !== -1) {
|
|
288
|
+
return body;
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
const header =
|
|
292
|
+
'<!-- gdd: auto-generated from Claude SKILL.md. ' +
|
|
293
|
+
display +
|
|
294
|
+
' adapter -->\n\n';
|
|
295
|
+
|
|
296
|
+
// Preserve any leading blank lines — insert the header before the
|
|
297
|
+
// first non-blank line. (If body starts with blank lines, those are
|
|
298
|
+
// retained between header and first real content.)
|
|
299
|
+
const m = body.match(/^(\s*)([\s\S]*)$/);
|
|
300
|
+
/* istanbul ignore next — regex always matches non-null body. */
|
|
301
|
+
if (!m) return header + body;
|
|
302
|
+
return header + m[2];
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
// ---------------------------------------------------------------------------
|
|
306
|
+
// buildFrontmatter — name-prefix normalization + frontmatter re-emit
|
|
307
|
+
// ---------------------------------------------------------------------------
|
|
308
|
+
|
|
309
|
+
/**
|
|
310
|
+
* Re-emit a YAML frontmatter block. Behavior:
|
|
311
|
+
*
|
|
312
|
+
* - If `originalFrontmatter` is `null` or empty, emit a minimal block
|
|
313
|
+
* containing only `name: <runtimePrefix><skillName>`.
|
|
314
|
+
* - If `originalFrontmatter` is non-empty, rewrite its `name:` field
|
|
315
|
+
* to `<runtimePrefix><skillName>` (stripping any prior `gdd-` or
|
|
316
|
+
* `gsd-` prefix on the existing name to avoid `gdd-gdd-`-style
|
|
317
|
+
* duplication). All other fields round-trip verbatim — we do NOT
|
|
318
|
+
* parse YAML; we operate on the raw text with a line-by-line scan.
|
|
319
|
+
* - If the original has no `name:` field, prepend one.
|
|
320
|
+
*
|
|
321
|
+
* Returns a complete frontmatter string with leading/trailing `---`
|
|
322
|
+
* delimiters and a trailing newline (ready to concatenate with body).
|
|
323
|
+
*
|
|
324
|
+
* @param {string|null} originalFrontmatter
|
|
325
|
+
* @param {string} skillName the bare skill name (e.g. `'sample'`,
|
|
326
|
+
* `'explore'`) WITHOUT runtime prefix.
|
|
327
|
+
* @param {string} runtimePrefix e.g. `'gdd-'`.
|
|
328
|
+
* @returns {string}
|
|
329
|
+
*/
|
|
330
|
+
function buildFrontmatter(originalFrontmatter, skillName, runtimePrefix) {
|
|
331
|
+
const prefix = String(runtimePrefix || '');
|
|
332
|
+
// Normalize input name: strip any prior gdd-/gsd- prefix (case-insensitive)
|
|
333
|
+
// so we never emit gdd-gdd-foo.
|
|
334
|
+
const bareName = String(skillName || '').replace(/^(gdd-|gsd-)/i, '');
|
|
335
|
+
const finalName = prefix + bareName;
|
|
336
|
+
|
|
337
|
+
if (!originalFrontmatter || originalFrontmatter.trim() === '') {
|
|
338
|
+
return '---\nname: ' + finalName + '\n---\n';
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
// Line-by-line rewrite of the `name:` field. We never touch description,
|
|
342
|
+
// tools, or any other field — they round-trip verbatim.
|
|
343
|
+
const lines = originalFrontmatter.split(/\r?\n/);
|
|
344
|
+
let nameSeen = false;
|
|
345
|
+
for (let i = 0; i < lines.length; i++) {
|
|
346
|
+
const m = lines[i].match(/^(\s*name\s*:\s*)(.*)$/);
|
|
347
|
+
if (m) {
|
|
348
|
+
nameSeen = true;
|
|
349
|
+
// Replace the value with `finalName`. Preserve surrounding quotes
|
|
350
|
+
// if the original value had them (very common in SKILL.md sources
|
|
351
|
+
// — `name: "gdd-help"`).
|
|
352
|
+
const quoted = m[2].match(/^["'](.*)["']\s*$/);
|
|
353
|
+
const replacement = quoted ? '"' + finalName + '"' : finalName;
|
|
354
|
+
lines[i] = m[1] + replacement;
|
|
355
|
+
break; // only rewrite the first `name:` occurrence
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
if (!nameSeen) {
|
|
359
|
+
// Prepend a `name:` line if the original had none.
|
|
360
|
+
lines.unshift('name: ' + finalName);
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
return '---\n' + lines.join('\n') + '\n---\n';
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
// ---------------------------------------------------------------------------
|
|
367
|
+
// Exports
|
|
368
|
+
// ---------------------------------------------------------------------------
|
|
369
|
+
|
|
370
|
+
module.exports = {
|
|
371
|
+
extractFrontmatterAndBody,
|
|
372
|
+
rewriteSlashRefs,
|
|
373
|
+
rewriteCodeFenceTools,
|
|
374
|
+
ensureAdapterHeader,
|
|
375
|
+
buildFrontmatter,
|
|
376
|
+
CODEX_TOOL_MAP,
|
|
377
|
+
};
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* scripts/lib/install/converters/trae.cjs — Phase 28.7 (Plan 28.7-05).
|
|
5
|
+
*
|
|
6
|
+
* Trae SKILL.md converter. Translates Claude-shape source into Trae's
|
|
7
|
+
* expected shape:
|
|
8
|
+
*
|
|
9
|
+
* - Frontmatter `name:` normalized to `gdd-<skill>` (no double-prefix).
|
|
10
|
+
* - Slash references in prose pass through as `/gdd-<name>` —
|
|
11
|
+
* Trae accepts the Claude shape. Mixed-shape inputs are normalized
|
|
12
|
+
* via the runtime-slash module.
|
|
13
|
+
* - Tool names in code fences pass through unchanged — Trae accepts
|
|
14
|
+
* the Claude vocabulary (Read/Write/Bash/Edit/Grep/Glob).
|
|
15
|
+
* - A 1-line HTML adapter header is injected at the top of the body
|
|
16
|
+
* to record that this file was auto-generated from Claude source.
|
|
17
|
+
*
|
|
18
|
+
* Architecture ported from gsd-build/get-shit-done (MIT) — per Phase
|
|
19
|
+
* 28.7 D-02 (port architecture, not source). See NOTICE for upstream
|
|
20
|
+
* attribution. gsd-build's equivalent function is
|
|
21
|
+
* `convertClaudeCommandToTraeSkill` in bin/install.js; our modular
|
|
22
|
+
* factor delegates the actual rewrites to ./shared.cjs.
|
|
23
|
+
*
|
|
24
|
+
* Pure / side-effect-free: no fs, no env, no path. `convert` is a
|
|
25
|
+
* deterministic string → string transform.
|
|
26
|
+
*/
|
|
27
|
+
|
|
28
|
+
const shared = require('./shared.cjs');
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Convert Claude-source SKILL.md content for the Trae runtime.
|
|
32
|
+
*
|
|
33
|
+
* @param {string} content Full source SKILL.md content (frontmatter + body).
|
|
34
|
+
* @param {string} skillName The bare skill name (e.g. `'help'`, `'explore'`).
|
|
35
|
+
* @param {{ runtime?: string }} [opts] Optional context — `runtime` defaults
|
|
36
|
+
* to `'trae'`. Currently informational only.
|
|
37
|
+
* @returns {string}
|
|
38
|
+
*/
|
|
39
|
+
function convert(content, skillName, opts) {
|
|
40
|
+
const { frontmatter, body } = shared.extractFrontmatterAndBody(content);
|
|
41
|
+
const fm = shared.buildFrontmatter(frontmatter, skillName, 'gdd-');
|
|
42
|
+
let out = shared.rewriteSlashRefs(body, 'trae');
|
|
43
|
+
out = shared.ensureAdapterHeader(out, 'Trae');
|
|
44
|
+
return fm + out;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
module.exports = { convert };
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* scripts/lib/install/converters/windsurf.cjs — Phase 28.7 (Plan 28.7-05).
|
|
5
|
+
*
|
|
6
|
+
* Windsurf SKILL.md converter. Translates Claude-shape source into
|
|
7
|
+
* Windsurf's expected shape:
|
|
8
|
+
*
|
|
9
|
+
* - Frontmatter `name:` normalized to `gdd-<skill>` (no double-prefix).
|
|
10
|
+
* - Slash references in prose pass through as `/gdd-<name>` —
|
|
11
|
+
* Windsurf accepts the Claude shape. Mixed-shape inputs are
|
|
12
|
+
* normalized via the runtime-slash module.
|
|
13
|
+
* - Tool names in code fences pass through unchanged — Windsurf
|
|
14
|
+
* accepts the Claude vocabulary (Read/Write/Bash/Edit/Grep/Glob).
|
|
15
|
+
* - A 1-line HTML adapter header is injected at the top of the body
|
|
16
|
+
* to record that this file was auto-generated from Claude source.
|
|
17
|
+
*
|
|
18
|
+
* Architecture ported from gsd-build/get-shit-done (MIT) — per Phase
|
|
19
|
+
* 28.7 D-02 (port architecture, not source). See NOTICE for upstream
|
|
20
|
+
* attribution. gsd-build's equivalent function is
|
|
21
|
+
* `convertClaudeCommandToWindsurfSkill` in bin/install.js; our modular
|
|
22
|
+
* factor delegates the actual rewrites to ./shared.cjs.
|
|
23
|
+
*
|
|
24
|
+
* Pure / side-effect-free: no fs, no env, no path. `convert` is a
|
|
25
|
+
* deterministic string → string transform.
|
|
26
|
+
*/
|
|
27
|
+
|
|
28
|
+
const shared = require('./shared.cjs');
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Convert Claude-source SKILL.md content for the Windsurf runtime.
|
|
32
|
+
*
|
|
33
|
+
* @param {string} content Full source SKILL.md content (frontmatter + body).
|
|
34
|
+
* @param {string} skillName The bare skill name (e.g. `'help'`, `'explore'`).
|
|
35
|
+
* @param {{ runtime?: string }} [opts] Optional context — `runtime` defaults
|
|
36
|
+
* to `'windsurf'`. Currently informational only.
|
|
37
|
+
* @returns {string}
|
|
38
|
+
*/
|
|
39
|
+
function convert(content, skillName, opts) {
|
|
40
|
+
const { frontmatter, body } = shared.extractFrontmatterAndBody(content);
|
|
41
|
+
const fm = shared.buildFrontmatter(frontmatter, skillName, 'gdd-');
|
|
42
|
+
let out = shared.rewriteSlashRefs(body, 'windsurf');
|
|
43
|
+
out = shared.ensureAdapterHeader(out, 'Windsurf');
|
|
44
|
+
return fm + out;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
module.exports = { convert };
|