@hegemonart/get-design-done 1.28.6 → 1.28.8
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 +81 -0
- package/README.de.md +14 -0
- package/README.fr.md +14 -0
- package/README.it.md +14 -0
- package/README.ja.md +14 -0
- package/README.ko.md +14 -0
- package/README.md +18 -0
- package/README.zh-CN.md +14 -0
- package/SKILL.md +10 -10
- package/package.json +3 -1
- package/scripts/build-distribution-bundles.cjs +549 -0
- package/scripts/install.cjs +68 -0
- package/scripts/lib/install/config-dir.cjs +26 -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-plugin.cjs +407 -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-marketplace.cjs +309 -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/doctor-codex-plugin.cjs +388 -0
- package/scripts/lib/install/doctor-cursor-marketplace.cjs +366 -0
- package/scripts/lib/install/doctor-tier2.cjs +586 -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 +73 -32
- package/scripts/lint-agentskills-spec.cjs +457 -0
- package/skills/compare/SKILL.md +2 -2
- package/skills/compare/compare-rubric.md +1 -1
- package/skills/darkmode/SKILL.md +2 -2
- package/skills/darkmode/darkmode-audit-procedure.md +1 -1
- package/skills/figma-write/SKILL.md +2 -2
- package/skills/graphify/SKILL.md +2 -2
- package/skills/style/SKILL.md +2 -2
- package/skills/style/style-doc-procedure.md +1 -1
|
@@ -0,0 +1,225 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* scripts/lib/install/runtime-homes.cjs — Phase 28.7 (Plan 28.7-01).
|
|
5
|
+
*
|
|
6
|
+
* Pure config-dir + skills-base resolver per runtime. Returns absolute paths
|
|
7
|
+
* to each runtime's global config directory and global skills directory,
|
|
8
|
+
* respecting env-var overrides + XDG conventions.
|
|
9
|
+
*
|
|
10
|
+
* Architecture ported from gsd-build/get-shit-done (MIT) — per Phase 28.7 D-02
|
|
11
|
+
* (port architecture, not source). See NOTICE for upstream attribution.
|
|
12
|
+
*
|
|
13
|
+
* Scope: the 14 GDD runtimes locked by Phase 24 D-02. Phase 28.7 D-03 + D-10
|
|
14
|
+
* keep `hermes` OUT of scope; the upstream `hermes` and `grok` branches are
|
|
15
|
+
* deliberately NOT ported.
|
|
16
|
+
*
|
|
17
|
+
* Pure / side-effect-free: no `fs.*` calls at any time, no `process.env`
|
|
18
|
+
* writes, no top-level work beyond `require('os')` + `require('path')`.
|
|
19
|
+
* Safe to require() at module-load time.
|
|
20
|
+
*
|
|
21
|
+
* Runtime-specific notes:
|
|
22
|
+
* opencode + kilo — XDG: honor `XDG_CONFIG_HOME` when the runtime's own
|
|
23
|
+
* env var is unset. Default: `~/.config/<runtime>`.
|
|
24
|
+
* antigravity — Nested under Gemini's home (`~/.gemini/antigravity`).
|
|
25
|
+
* windsurf — Nested under Codeium's home (`~/.codeium/windsurf`).
|
|
26
|
+
* cline — Rules-based runtime (D-09). `getGlobalSkillsBase('cline')`
|
|
27
|
+
* returns `null` so callers can route to the `.clinerules`
|
|
28
|
+
* embedding path instead of a skills/ tree.
|
|
29
|
+
*/
|
|
30
|
+
|
|
31
|
+
const os = require('os');
|
|
32
|
+
const path = require('path');
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Expand a leading `~` to `os.homedir()`. Returns the input unchanged if no
|
|
36
|
+
* leading tilde is present (including `null`/`undefined`/empty).
|
|
37
|
+
*
|
|
38
|
+
* @param {string} p
|
|
39
|
+
* @returns {string}
|
|
40
|
+
*/
|
|
41
|
+
function expandTilde(p) {
|
|
42
|
+
if (!p) return p;
|
|
43
|
+
if (p === '~') return os.homedir();
|
|
44
|
+
if (p.startsWith('~/') || p.startsWith('~\\')) {
|
|
45
|
+
return path.join(os.homedir(), p.slice(2));
|
|
46
|
+
}
|
|
47
|
+
return p;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Return the global config base directory for the given runtime.
|
|
52
|
+
*
|
|
53
|
+
* Precedence per branch:
|
|
54
|
+
* 1. Runtime's dedicated env var (e.g. `CLAUDE_CONFIG_DIR`, `CODEX_HOME`),
|
|
55
|
+
* tilde-expanded if present.
|
|
56
|
+
* 2. XDG path for opencode + kilo (when `XDG_CONFIG_HOME` is set).
|
|
57
|
+
* 3. Home-relative default (`~/.claude`, `~/.codex`, etc.).
|
|
58
|
+
*
|
|
59
|
+
* Throws `RangeError` on unknown runtime IDs (loud-fail — typos in caller
|
|
60
|
+
* code should fail at the resolver, not silently fall back to Claude paths).
|
|
61
|
+
*
|
|
62
|
+
* @param {string} runtime
|
|
63
|
+
* @returns {string} Absolute path to the runtime's global config directory.
|
|
64
|
+
*/
|
|
65
|
+
function getGlobalConfigDir(runtime) {
|
|
66
|
+
const home = os.homedir();
|
|
67
|
+
const env = process.env;
|
|
68
|
+
|
|
69
|
+
switch (runtime) {
|
|
70
|
+
// ── Claude Code ──────────────────────────────────────────────────────────
|
|
71
|
+
case 'claude':
|
|
72
|
+
return env.CLAUDE_CONFIG_DIR
|
|
73
|
+
? expandTilde(env.CLAUDE_CONFIG_DIR)
|
|
74
|
+
: path.join(home, '.claude');
|
|
75
|
+
|
|
76
|
+
// ── OpenCode (XDG) ───────────────────────────────────────────────────────
|
|
77
|
+
case 'opencode': {
|
|
78
|
+
if (env.OPENCODE_CONFIG_DIR) return expandTilde(env.OPENCODE_CONFIG_DIR);
|
|
79
|
+
if (env.XDG_CONFIG_HOME) return path.join(expandTilde(env.XDG_CONFIG_HOME), 'opencode');
|
|
80
|
+
return path.join(home, '.config', 'opencode');
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
// ── Gemini CLI ───────────────────────────────────────────────────────────
|
|
84
|
+
case 'gemini':
|
|
85
|
+
return env.GEMINI_CONFIG_DIR
|
|
86
|
+
? expandTilde(env.GEMINI_CONFIG_DIR)
|
|
87
|
+
: path.join(home, '.gemini');
|
|
88
|
+
|
|
89
|
+
// ── Kilo Code (XDG) ──────────────────────────────────────────────────────
|
|
90
|
+
case 'kilo': {
|
|
91
|
+
if (env.KILO_CONFIG_DIR) return expandTilde(env.KILO_CONFIG_DIR);
|
|
92
|
+
if (env.XDG_CONFIG_HOME) return path.join(expandTilde(env.XDG_CONFIG_HOME), 'kilo');
|
|
93
|
+
return path.join(home, '.config', 'kilo');
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
// ── Codex ────────────────────────────────────────────────────────────────
|
|
97
|
+
case 'codex':
|
|
98
|
+
return env.CODEX_HOME
|
|
99
|
+
? expandTilde(env.CODEX_HOME)
|
|
100
|
+
: path.join(home, '.codex');
|
|
101
|
+
|
|
102
|
+
// ── Copilot (VS Code / CLI) ──────────────────────────────────────────────
|
|
103
|
+
case 'copilot':
|
|
104
|
+
return env.COPILOT_CONFIG_DIR
|
|
105
|
+
? expandTilde(env.COPILOT_CONFIG_DIR)
|
|
106
|
+
: path.join(home, '.copilot');
|
|
107
|
+
|
|
108
|
+
// ── Cursor ───────────────────────────────────────────────────────────────
|
|
109
|
+
case 'cursor':
|
|
110
|
+
return env.CURSOR_CONFIG_DIR
|
|
111
|
+
? expandTilde(env.CURSOR_CONFIG_DIR)
|
|
112
|
+
: path.join(home, '.cursor');
|
|
113
|
+
|
|
114
|
+
// ── Windsurf (nested under Codeium home) ─────────────────────────────────
|
|
115
|
+
case 'windsurf':
|
|
116
|
+
return env.WINDSURF_CONFIG_DIR
|
|
117
|
+
? expandTilde(env.WINDSURF_CONFIG_DIR)
|
|
118
|
+
: path.join(home, '.codeium', 'windsurf');
|
|
119
|
+
|
|
120
|
+
// ── Antigravity (nested under Gemini home) ───────────────────────────────
|
|
121
|
+
case 'antigravity':
|
|
122
|
+
return env.ANTIGRAVITY_CONFIG_DIR
|
|
123
|
+
? expandTilde(env.ANTIGRAVITY_CONFIG_DIR)
|
|
124
|
+
: path.join(home, '.gemini', 'antigravity');
|
|
125
|
+
|
|
126
|
+
// ── Augment ──────────────────────────────────────────────────────────────
|
|
127
|
+
case 'augment':
|
|
128
|
+
return env.AUGMENT_CONFIG_DIR
|
|
129
|
+
? expandTilde(env.AUGMENT_CONFIG_DIR)
|
|
130
|
+
: path.join(home, '.augment');
|
|
131
|
+
|
|
132
|
+
// ── Trae ─────────────────────────────────────────────────────────────────
|
|
133
|
+
case 'trae':
|
|
134
|
+
return env.TRAE_CONFIG_DIR
|
|
135
|
+
? expandTilde(env.TRAE_CONFIG_DIR)
|
|
136
|
+
: path.join(home, '.trae');
|
|
137
|
+
|
|
138
|
+
// ── Qwen Code ────────────────────────────────────────────────────────────
|
|
139
|
+
case 'qwen':
|
|
140
|
+
return env.QWEN_CONFIG_DIR
|
|
141
|
+
? expandTilde(env.QWEN_CONFIG_DIR)
|
|
142
|
+
: path.join(home, '.qwen');
|
|
143
|
+
|
|
144
|
+
// ── CodeBuddy ────────────────────────────────────────────────────────────
|
|
145
|
+
case 'codebuddy':
|
|
146
|
+
return env.CODEBUDDY_CONFIG_DIR
|
|
147
|
+
? expandTilde(env.CODEBUDDY_CONFIG_DIR)
|
|
148
|
+
: path.join(home, '.codebuddy');
|
|
149
|
+
|
|
150
|
+
// ── Cline (rules-based — see getGlobalSkillsBase) ────────────────────────
|
|
151
|
+
case 'cline':
|
|
152
|
+
return env.CLINE_CONFIG_DIR
|
|
153
|
+
? expandTilde(env.CLINE_CONFIG_DIR)
|
|
154
|
+
: path.join(home, '.cline');
|
|
155
|
+
|
|
156
|
+
// ── Unknown ──────────────────────────────────────────────────────────────
|
|
157
|
+
default:
|
|
158
|
+
throw new RangeError(
|
|
159
|
+
`Unknown runtime "${runtime}". Known: claude, opencode, gemini, kilo, ` +
|
|
160
|
+
'codex, copilot, cursor, windsurf, antigravity, augment, trae, qwen, ' +
|
|
161
|
+
'codebuddy, cline.'
|
|
162
|
+
);
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
/**
|
|
167
|
+
* Return the global skills base directory for the given runtime.
|
|
168
|
+
*
|
|
169
|
+
* - `cline` → `null` (Phase 28.7 D-09: rules-based, no skills dir; caller
|
|
170
|
+
* routes to the `.clinerules` embedding path).
|
|
171
|
+
* - All other 13 runtimes → `<configDir>/skills`.
|
|
172
|
+
*
|
|
173
|
+
* Note: gsd-build's upstream nests Hermes skills under `skills/gsd/<name>/`
|
|
174
|
+
* (their #2841). Hermes is NOT in our 14-runtime set (D-03 + D-10), so the
|
|
175
|
+
* nested layout is NOT ported.
|
|
176
|
+
*
|
|
177
|
+
* @param {string} runtime
|
|
178
|
+
* @returns {string|null} Absolute path to skills base, or `null` for cline.
|
|
179
|
+
*/
|
|
180
|
+
function getGlobalSkillsBase(runtime) {
|
|
181
|
+
if (runtime === 'cline') return null;
|
|
182
|
+
const configDir = getGlobalConfigDir(runtime);
|
|
183
|
+
return path.join(configDir, 'skills');
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
/**
|
|
187
|
+
* Return the full path to a specific skill's directory for the given runtime.
|
|
188
|
+
* Returns `null` for runtimes that don't use a skills directory (cline).
|
|
189
|
+
*
|
|
190
|
+
* @param {string} runtime
|
|
191
|
+
* @param {string} skillName e.g. `'gdd-executor'`.
|
|
192
|
+
* @returns {string|null}
|
|
193
|
+
*/
|
|
194
|
+
function getGlobalSkillDir(runtime, skillName) {
|
|
195
|
+
const base = getGlobalSkillsBase(runtime);
|
|
196
|
+
if (base === null) return null;
|
|
197
|
+
return path.join(base, skillName);
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
/**
|
|
201
|
+
* Return a human-readable display path for a global skill (for log messages).
|
|
202
|
+
* Replaces the home-directory prefix with `~` for readability.
|
|
203
|
+
*
|
|
204
|
+
* @param {string} runtime
|
|
205
|
+
* @param {string} skillName
|
|
206
|
+
* @returns {string}
|
|
207
|
+
*/
|
|
208
|
+
function getGlobalSkillDisplayPath(runtime, skillName) {
|
|
209
|
+
const dir = getGlobalSkillDir(runtime, skillName);
|
|
210
|
+
if (!dir) return `(${runtime} does not use a skills directory)`;
|
|
211
|
+
const home = os.homedir();
|
|
212
|
+
if (dir === home) return '~';
|
|
213
|
+
if (dir.startsWith(home + path.sep)) {
|
|
214
|
+
return '~' + dir.slice(home.length);
|
|
215
|
+
}
|
|
216
|
+
return dir;
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
module.exports = {
|
|
220
|
+
expandTilde,
|
|
221
|
+
getGlobalConfigDir,
|
|
222
|
+
getGlobalSkillsBase,
|
|
223
|
+
getGlobalSkillDir,
|
|
224
|
+
getGlobalSkillDisplayPath,
|
|
225
|
+
};
|
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* scripts/lib/install/runtime-slash.cjs — Phase 28.7 (Plan 28.7-03).
|
|
5
|
+
*
|
|
6
|
+
* Per-runtime slash-command surface emitter. Maps a bare command name
|
|
7
|
+
* (e.g. `'explore'`) to the runtime's expected slash-command shape:
|
|
8
|
+
* codex → `$gdd-explore` (shell-variable form)
|
|
9
|
+
* all other 13 runtimes → `/gdd-explore`
|
|
10
|
+
*
|
|
11
|
+
* The legacy colon form `/gdd:explore` is NEVER emitted — Phase 28.7
|
|
12
|
+
* standardizes on the dash form across the GDD brand. Inputs in legacy
|
|
13
|
+
* colon shape are accepted (and normalized) for backward compatibility.
|
|
14
|
+
*
|
|
15
|
+
* Architecture ported from gsd-build/get-shit-done (MIT) — per Phase
|
|
16
|
+
* 28.7 D-02 (port architecture, not source). See NOTICE for upstream
|
|
17
|
+
* attribution. Per Phase 28.7 D-11 this is the v1 surface; future
|
|
18
|
+
* per-runtime variations beyond codex shell-var may extend the switch.
|
|
19
|
+
*
|
|
20
|
+
* Idempotency: any prior shape (`/gdd-x`, `gdd-x`, `/gdd:x`, `gdd:x`,
|
|
21
|
+
* `$gdd-x`, `$gdd:x`) is stripped and re-emitted in canonical form for
|
|
22
|
+
* the target runtime. Argument tails (whitespace + remainder) round-trip
|
|
23
|
+
* untouched — this preserves Windows paths verbatim (Phase 28.6 lesson).
|
|
24
|
+
*
|
|
25
|
+
* Pure / side-effect-free at module load: only `require('fs')` and
|
|
26
|
+
* `require('path')` are taken at top level. `fs.readFileSync` is the
|
|
27
|
+
* sole `fs.*` caller, invoked exclusively from `resolveRuntime` when a
|
|
28
|
+
* project directory is provided — and wrapped in try/catch so malformed
|
|
29
|
+
* `.planning/config.json` cannot throw.
|
|
30
|
+
*/
|
|
31
|
+
|
|
32
|
+
const fs = require('fs');
|
|
33
|
+
const path = require('path');
|
|
34
|
+
|
|
35
|
+
// ---------------------------------------------------------------------------
|
|
36
|
+
// formatGddSlash — pure rewrite of a single command token
|
|
37
|
+
// ---------------------------------------------------------------------------
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Strip any known GDD prefix from the head of `s`.
|
|
41
|
+
*
|
|
42
|
+
* Matches (case-insensitive):
|
|
43
|
+
* `/gdd-`, `/gdd:`, `gdd-`, `gdd:`, `$gdd-`, `$gdd:`
|
|
44
|
+
*
|
|
45
|
+
* Returns the substring after the matched prefix, or the original string
|
|
46
|
+
* unchanged if no prefix matches.
|
|
47
|
+
*
|
|
48
|
+
* @param {string} s
|
|
49
|
+
* @returns {string}
|
|
50
|
+
*/
|
|
51
|
+
function stripGddPrefix(s) {
|
|
52
|
+
const m = s.match(/^[/$]?gdd[-:]/i);
|
|
53
|
+
if (m) return s.slice(m[0].length);
|
|
54
|
+
return s;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Rewrite a command name to the slash-command shape for `runtime`.
|
|
59
|
+
*
|
|
60
|
+
* Behavior:
|
|
61
|
+
* - Non-string `commandName` returned unchanged (type-guard).
|
|
62
|
+
* - Empty string returned as `''`.
|
|
63
|
+
* - Any of `/gdd-`, `/gdd:`, `gdd-`, `gdd:`, `$gdd-`, `$gdd:` is
|
|
64
|
+
* stripped first (case-insensitive). Bare names pass through.
|
|
65
|
+
* - If the stripped result is empty / whitespace-only, return `''`
|
|
66
|
+
* (never re-emit `/gdd-` or `$gdd-` with no token — degenerate input).
|
|
67
|
+
* - Split on the first whitespace: the leading token is rewritten,
|
|
68
|
+
* everything after the first space (the argument tail) round-trips
|
|
69
|
+
* untouched. This preserves Windows paths in argument position.
|
|
70
|
+
* - codex → `$gdd-<token-lowercased><tail>`
|
|
71
|
+
* - all other runtimes → `/gdd-<token><tail>`
|
|
72
|
+
* - Unknown / falsy runtime → defaults to `'claude'` shape (`/gdd-`).
|
|
73
|
+
*
|
|
74
|
+
* @param {string} commandName e.g. `'explore'`, `'/gdd-debug'`, `'do x y'`.
|
|
75
|
+
* @param {string} [runtime] runtime ID; defaults to `'claude'`.
|
|
76
|
+
* @returns {string}
|
|
77
|
+
*/
|
|
78
|
+
function formatGddSlash(commandName, runtime) {
|
|
79
|
+
// Type-guard: only operate on strings; pass everything else through.
|
|
80
|
+
if (typeof commandName !== 'string') return commandName;
|
|
81
|
+
if (commandName === '') return '';
|
|
82
|
+
|
|
83
|
+
// 1. Strip any prior GDD prefix (idempotent normalization).
|
|
84
|
+
const bare = stripGddPrefix(commandName);
|
|
85
|
+
|
|
86
|
+
// 2. Defensive: empty / whitespace-only token → empty (never `/gdd-`).
|
|
87
|
+
if (bare === '' || /^\s+$/.test(bare)) return '';
|
|
88
|
+
|
|
89
|
+
// 3. Split into leading token + argument tail. The tail (including its
|
|
90
|
+
// leading whitespace) round-trips untouched for Windows-path safety.
|
|
91
|
+
const m = bare.match(/^(\S+)(\s[\s\S]*)?$/);
|
|
92
|
+
/* istanbul ignore next — `bare` is non-empty + non-whitespace-only, so
|
|
93
|
+
this regex always matches; defensive fallback only. */
|
|
94
|
+
if (!m) return '';
|
|
95
|
+
const token = m[1];
|
|
96
|
+
const tail = m[2] || '';
|
|
97
|
+
|
|
98
|
+
// 4. Runtime-specific emission.
|
|
99
|
+
const rt = String(runtime || 'claude').toLowerCase();
|
|
100
|
+
if (rt === 'codex') {
|
|
101
|
+
return '$gdd-' + token.toLowerCase() + tail;
|
|
102
|
+
}
|
|
103
|
+
return '/gdd-' + token + tail;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
// ---------------------------------------------------------------------------
|
|
107
|
+
// resolveRuntime — read-only runtime ID resolution
|
|
108
|
+
// ---------------------------------------------------------------------------
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* Resolve the active runtime ID for the given project directory.
|
|
112
|
+
*
|
|
113
|
+
* Precedence:
|
|
114
|
+
* 1. `process.env.GDD_RUNTIME` (lowercased) if truthy.
|
|
115
|
+
* 2. `<projectDir>/.planning/config.json#runtime` (lowercased) if the
|
|
116
|
+
* file exists, parses as JSON, and contains a non-empty `runtime`
|
|
117
|
+
* string. Malformed JSON, missing file, or missing key all fall
|
|
118
|
+
* through silently — this function MUST NOT throw on bad config.
|
|
119
|
+
* 3. Default `'claude'`.
|
|
120
|
+
*
|
|
121
|
+
* Side-effect-free: only `fs.readFileSync` (wrapped in try/catch), no
|
|
122
|
+
* env mutation, no writes.
|
|
123
|
+
*
|
|
124
|
+
* @param {string} [projectDir] absolute path to project root.
|
|
125
|
+
* @returns {string} runtime ID, always lowercase.
|
|
126
|
+
*/
|
|
127
|
+
function resolveRuntime(projectDir) {
|
|
128
|
+
// 1. Env-var override
|
|
129
|
+
if (process.env.GDD_RUNTIME) {
|
|
130
|
+
return String(process.env.GDD_RUNTIME).toLowerCase();
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
// 2. .planning/config.json#runtime
|
|
134
|
+
if (projectDir) {
|
|
135
|
+
try {
|
|
136
|
+
const cfgPath = path.join(projectDir, '.planning', 'config.json');
|
|
137
|
+
const raw = fs.readFileSync(cfgPath, 'utf8');
|
|
138
|
+
const parsed = JSON.parse(raw);
|
|
139
|
+
if (parsed && typeof parsed.runtime === 'string' && parsed.runtime) {
|
|
140
|
+
return String(parsed.runtime).toLowerCase();
|
|
141
|
+
}
|
|
142
|
+
} catch {
|
|
143
|
+
/* fall through — malformed JSON / missing file / missing key */
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
// 3. Default
|
|
148
|
+
return 'claude';
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
// ---------------------------------------------------------------------------
|
|
152
|
+
// formatGddSlashFor — convenience that combines the two
|
|
153
|
+
// ---------------------------------------------------------------------------
|
|
154
|
+
|
|
155
|
+
/**
|
|
156
|
+
* Resolve the runtime for `projectDir` and rewrite `commandName` accordingly.
|
|
157
|
+
* Convenience wrapper for callers that already have a project directory in
|
|
158
|
+
* hand and don't want to wire `resolveRuntime` themselves.
|
|
159
|
+
*
|
|
160
|
+
* @param {string} projectDir
|
|
161
|
+
* @param {string} commandName
|
|
162
|
+
* @returns {string}
|
|
163
|
+
*/
|
|
164
|
+
function formatGddSlashFor(projectDir, commandName) {
|
|
165
|
+
return formatGddSlash(commandName, resolveRuntime(projectDir));
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
module.exports = {
|
|
169
|
+
formatGddSlash,
|
|
170
|
+
resolveRuntime,
|
|
171
|
+
formatGddSlashFor,
|
|
172
|
+
};
|
|
@@ -7,15 +7,21 @@
|
|
|
7
7
|
// (Phase 24 D-02). Two `kind`s exist:
|
|
8
8
|
//
|
|
9
9
|
// - `claude-marketplace` — register a marketplace entry + flip
|
|
10
|
-
// `enabledPlugins[<
|
|
11
|
-
//
|
|
10
|
+
// `enabledPlugins[<plugin>@<marketplace>]` in settings.json. Claude
|
|
11
|
+
// Code only.
|
|
12
12
|
//
|
|
13
|
-
// - `
|
|
14
|
-
//
|
|
15
|
-
//
|
|
13
|
+
// - `multi-artifact` — per Phase 28.7: install one or more artifact kinds
|
|
14
|
+
// (skills, commands, agents) using runtime-artifact-layout.cjs +
|
|
15
|
+
// per-runtime converters at scripts/lib/install/converters/<runtime>.cjs.
|
|
16
|
+
// Replaces the broken Phase 24 `agents-md` placeholder which dropped a
|
|
17
|
+
// single AGENTS.md file per runtime (Phase 28.7 D-02 + D-08). The actual
|
|
18
|
+
// install logic now lives in installer.cjs → runtime-artifact-layout.cjs;
|
|
19
|
+
// `files:` is intentionally absent on these entries because destination
|
|
20
|
+
// paths are computed by the artifact-layout resolver.
|
|
16
21
|
//
|
|
17
22
|
// Adding a new runtime: append to RUNTIMES below, append the same id to the
|
|
18
|
-
// alphabetised baseline at test-fixture/baselines/phase-24/runtimes.txt
|
|
23
|
+
// alphabetised baseline at test-fixture/baselines/phase-24/runtimes.txt,
|
|
24
|
+
// and add a matching branch in runtime-artifact-layout.cjs (Phase 28.7).
|
|
19
25
|
|
|
20
26
|
const REPO = 'hegemonart/get-design-done';
|
|
21
27
|
const MARKETPLACE_NAME = 'get-design-done';
|
|
@@ -40,16 +46,14 @@ const RUNTIMES = Object.freeze([
|
|
|
40
46
|
displayName: 'OpenCode',
|
|
41
47
|
configDirEnv: 'OPENCODE_CONFIG_DIR',
|
|
42
48
|
configDirFallback: '.config/opencode',
|
|
43
|
-
kind: '
|
|
44
|
-
files: ['AGENTS.md'],
|
|
49
|
+
kind: 'multi-artifact',
|
|
45
50
|
},
|
|
46
51
|
{
|
|
47
52
|
id: 'gemini',
|
|
48
53
|
displayName: 'Gemini CLI',
|
|
49
54
|
configDirEnv: 'GEMINI_CONFIG_DIR',
|
|
50
55
|
configDirFallback: '.gemini',
|
|
51
|
-
kind: '
|
|
52
|
-
files: ['GEMINI.md'],
|
|
56
|
+
kind: 'multi-artifact',
|
|
53
57
|
// Phase 27 (Plan 27-11): peer-CLI delegation binary, ACP protocol.
|
|
54
58
|
peerBinary: process.platform === 'win32' ? 'gemini.cmd' : 'gemini',
|
|
55
59
|
},
|
|
@@ -58,16 +62,14 @@ const RUNTIMES = Object.freeze([
|
|
|
58
62
|
displayName: 'Kilo Code',
|
|
59
63
|
configDirEnv: 'KILO_CONFIG_DIR',
|
|
60
64
|
configDirFallback: '.kilo',
|
|
61
|
-
kind: '
|
|
62
|
-
files: ['AGENTS.md'],
|
|
65
|
+
kind: 'multi-artifact',
|
|
63
66
|
},
|
|
64
67
|
{
|
|
65
68
|
id: 'codex',
|
|
66
69
|
displayName: 'OpenAI Codex CLI',
|
|
67
70
|
configDirEnv: 'CODEX_HOME',
|
|
68
71
|
configDirFallback: '.codex',
|
|
69
|
-
kind: '
|
|
70
|
-
files: ['AGENTS.md'],
|
|
72
|
+
kind: 'multi-artifact',
|
|
71
73
|
// Phase 27 (Plan 27-11): peer-CLI delegation binary, ASP protocol.
|
|
72
74
|
peerBinary: process.platform === 'win32' ? 'codex.cmd' : 'codex',
|
|
73
75
|
},
|
|
@@ -76,8 +78,7 @@ const RUNTIMES = Object.freeze([
|
|
|
76
78
|
displayName: 'GitHub Copilot CLI',
|
|
77
79
|
configDirEnv: 'COPILOT_CONFIG_DIR',
|
|
78
80
|
configDirFallback: '.copilot',
|
|
79
|
-
kind: '
|
|
80
|
-
files: ['AGENTS.md'],
|
|
81
|
+
kind: 'multi-artifact',
|
|
81
82
|
// Phase 27 (Plan 27-11): peer-CLI delegation binary, ACP protocol.
|
|
82
83
|
peerBinary: process.platform === 'win32' ? 'copilot.cmd' : 'copilot',
|
|
83
84
|
},
|
|
@@ -86,8 +87,7 @@ const RUNTIMES = Object.freeze([
|
|
|
86
87
|
displayName: 'Cursor',
|
|
87
88
|
configDirEnv: 'CURSOR_CONFIG_DIR',
|
|
88
89
|
configDirFallback: '.cursor',
|
|
89
|
-
kind: '
|
|
90
|
-
files: ['AGENTS.md'],
|
|
90
|
+
kind: 'multi-artifact',
|
|
91
91
|
// Phase 27 (Plan 27-11): peer-CLI delegation binary, ACP protocol.
|
|
92
92
|
peerBinary: process.platform === 'win32' ? 'cursor-agent.cmd' : 'cursor-agent',
|
|
93
93
|
},
|
|
@@ -96,40 +96,35 @@ const RUNTIMES = Object.freeze([
|
|
|
96
96
|
displayName: 'Windsurf',
|
|
97
97
|
configDirEnv: 'WINDSURF_CONFIG_DIR',
|
|
98
98
|
configDirFallback: '.windsurf',
|
|
99
|
-
kind: '
|
|
100
|
-
files: ['AGENTS.md'],
|
|
99
|
+
kind: 'multi-artifact',
|
|
101
100
|
},
|
|
102
101
|
{
|
|
103
102
|
id: 'antigravity',
|
|
104
103
|
displayName: 'Antigravity',
|
|
105
104
|
configDirEnv: 'ANTIGRAVITY_CONFIG_DIR',
|
|
106
105
|
configDirFallback: '.antigravity',
|
|
107
|
-
kind: '
|
|
108
|
-
files: ['AGENTS.md'],
|
|
106
|
+
kind: 'multi-artifact',
|
|
109
107
|
},
|
|
110
108
|
{
|
|
111
109
|
id: 'augment',
|
|
112
110
|
displayName: 'Augment',
|
|
113
111
|
configDirEnv: 'AUGMENT_CONFIG_DIR',
|
|
114
112
|
configDirFallback: '.augment',
|
|
115
|
-
kind: '
|
|
116
|
-
files: ['AGENTS.md'],
|
|
113
|
+
kind: 'multi-artifact',
|
|
117
114
|
},
|
|
118
115
|
{
|
|
119
116
|
id: 'trae',
|
|
120
117
|
displayName: 'Trae',
|
|
121
118
|
configDirEnv: 'TRAE_CONFIG_DIR',
|
|
122
119
|
configDirFallback: '.trae',
|
|
123
|
-
kind: '
|
|
124
|
-
files: ['AGENTS.md'],
|
|
120
|
+
kind: 'multi-artifact',
|
|
125
121
|
},
|
|
126
122
|
{
|
|
127
123
|
id: 'qwen',
|
|
128
124
|
displayName: 'Qwen Code',
|
|
129
125
|
configDirEnv: 'QWEN_CONFIG_DIR',
|
|
130
126
|
configDirFallback: '.qwen',
|
|
131
|
-
kind: '
|
|
132
|
-
files: ['AGENTS.md'],
|
|
127
|
+
kind: 'multi-artifact',
|
|
133
128
|
// Phase 27 (Plan 27-11): peer-CLI delegation binary, ACP protocol.
|
|
134
129
|
peerBinary: process.platform === 'win32' ? 'qwen.cmd' : 'qwen',
|
|
135
130
|
},
|
|
@@ -138,16 +133,62 @@ const RUNTIMES = Object.freeze([
|
|
|
138
133
|
displayName: 'CodeBuddy',
|
|
139
134
|
configDirEnv: 'CODEBUDDY_CONFIG_DIR',
|
|
140
135
|
configDirFallback: '.codebuddy',
|
|
141
|
-
kind: '
|
|
142
|
-
files: ['AGENTS.md'],
|
|
136
|
+
kind: 'multi-artifact',
|
|
143
137
|
},
|
|
144
138
|
{
|
|
145
139
|
id: 'cline',
|
|
146
140
|
displayName: 'Cline',
|
|
147
141
|
configDirEnv: 'CLINE_CONFIG_DIR',
|
|
148
142
|
configDirFallback: '.cline',
|
|
149
|
-
kind: '
|
|
150
|
-
|
|
143
|
+
kind: 'multi-artifact',
|
|
144
|
+
},
|
|
145
|
+
// Phase 28.8 (Plan B1) — Tier-2 distribution channel. 15th entry, kind
|
|
146
|
+
// 'cursor-marketplace'. Separate from the existing `id: 'cursor'` entry
|
|
147
|
+
// (kind: 'multi-artifact') which remains the Tier-1 file-drop install
|
|
148
|
+
// target. Per CONTEXT D-05 (additive), the two coexist — file-drop users
|
|
149
|
+
// and marketplace consumers are independent flows.
|
|
150
|
+
//
|
|
151
|
+
// build-distribution-bundles.cjs (Plan 28-8-X1) and install.cjs --doctor
|
|
152
|
+
// (Plan 28-8-B2) consult this entry. The regular install flow skips it
|
|
153
|
+
// because `configDir` is null — detect-runtimes never matches it on disk.
|
|
154
|
+
//
|
|
155
|
+
// No `configDirEnv` / `configDirFallback` because Tier-2 channels are
|
|
156
|
+
// out-of-band distribution bundles, not per-user runtime install dirs.
|
|
157
|
+
// runtime-artifact-layout.cjs is NOT extended for this kind — Tier-2
|
|
158
|
+
// bypasses the artifact-layout pipeline entirely.
|
|
159
|
+
{
|
|
160
|
+
id: 'cursor-marketplace',
|
|
161
|
+
displayName: 'Cursor Marketplace',
|
|
162
|
+
configDir: null,
|
|
163
|
+
configDirFallback: null,
|
|
164
|
+
kind: 'cursor-marketplace',
|
|
165
|
+
},
|
|
166
|
+
// Phase 28.8 (Plan 28-8-C1) — Tier-2 distribution channel. 16th entry,
|
|
167
|
+
// kind 'codex-plugin'. Separate from the existing `id: 'codex'` entry
|
|
168
|
+
// (kind: 'multi-artifact') which remains the Tier-1 file-drop AGENTS.md
|
|
169
|
+
// install target (Phase 28.7). Per CONTEXT D-05 (additive), the two
|
|
170
|
+
// coexist — file-drop users and marketplace consumers are independent
|
|
171
|
+
// flows. Installed via `codex plugin marketplace add hegemonart/get-design-done`
|
|
172
|
+
// per .planning/research/codex-plugins-2026-05-19.md § Distribution Mechanism.
|
|
173
|
+
//
|
|
174
|
+
// build-distribution-bundles.cjs (Plan 28-8-X1) and install.cjs --doctor
|
|
175
|
+
// (Plan 28-8-C2) consult this entry. The regular install flow skips it
|
|
176
|
+
// because `configDir` is null — detect-runtimes never matches it on disk.
|
|
177
|
+
//
|
|
178
|
+
// No `configDirEnv` / `configDirFallback` because Tier-2 channels are
|
|
179
|
+
// out-of-band distribution bundles, not per-user runtime install dirs.
|
|
180
|
+
// runtime-artifact-layout.cjs is NOT extended for this kind — Tier-2
|
|
181
|
+
// bypasses the artifact-layout pipeline entirely (consumed by
|
|
182
|
+
// build-distribution-bundles.cjs, not the multi-artifact installer).
|
|
183
|
+
//
|
|
184
|
+
// D-14: Codex reuses our existing `.claude-plugin/marketplace.json` via
|
|
185
|
+
// documented legacy-compat catalog path — no separate Codex catalog file.
|
|
186
|
+
{
|
|
187
|
+
id: 'codex-plugin',
|
|
188
|
+
displayName: 'Codex Plugin',
|
|
189
|
+
configDir: null,
|
|
190
|
+
configDirFallback: null,
|
|
191
|
+
kind: 'codex-plugin',
|
|
151
192
|
},
|
|
152
193
|
]);
|
|
153
194
|
|