@hegemonart/get-design-done 1.28.5 → 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 +102 -0
- package/README.md +2 -0
- package/package.json +1 -1
- package/reference/registry.json +0 -140
- package/reference/skill-authoring-contract.md +40 -9
- 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
- package/skills/apply-reflections/SKILL.md +1 -1
- package/skills/cache-manager/SKILL.md +2 -2
- package/skills/compare/SKILL.md +8 -8
- package/skills/connections/SKILL.md +9 -9
- package/skills/darkmode/SKILL.md +8 -8
- package/skills/debug/SKILL.md +3 -3
- package/skills/design/SKILL.md +6 -6
- package/skills/discover/SKILL.md +7 -7
- package/skills/explore/SKILL.md +6 -6
- package/skills/health/SKILL.md +2 -2
- package/skills/new-cycle/SKILL.md +1 -1
- package/skills/peer-cli-add/SKILL.md +6 -6
- package/skills/peer-cli-customize/SKILL.md +5 -5
- package/skills/peers/SKILL.md +2 -2
- package/skills/plan/SKILL.md +10 -10
- package/skills/quality-gate/SKILL.md +1 -1
- package/skills/router/SKILL.md +3 -3
- package/skills/scan/SKILL.md +17 -17
- package/skills/start/SKILL.md +1 -1
- package/skills/style/SKILL.md +5 -5
- package/skills/turn-closeout/SKILL.md +1 -1
- package/skills/verify/SKILL.md +10 -10
- package/skills/warm-cache/SKILL.md +2 -2
- /package/{reference → skills/apply-reflections}/apply-reflections-procedure.md +0 -0
- /package/{reference → skills/cache-manager}/cache-policy.md +0 -0
- /package/{reference → skills/compare}/compare-rubric.md +0 -0
- /package/{reference → skills/connections}/connections-onboarding.md +0 -0
- /package/{reference → skills/darkmode}/darkmode-audit-procedure.md +0 -0
- /package/{reference → skills/debug}/debug-feedback-loops.md +0 -0
- /package/{reference → skills/design}/design-procedure.md +0 -0
- /package/{reference → skills/discover}/discover-procedure.md +0 -0
- /package/{reference → skills/explore}/explore-procedure.md +0 -0
- /package/{reference → skills/health}/health-mcp-detection.md +0 -0
- /package/{reference → skills/health}/health-skill-length-report.md +0 -0
- /package/{reference → skills/new-cycle}/milestone-completeness-rubric.md +0 -0
- /package/{reference → skills/peer-cli-add}/peer-cli-protocol.md +0 -0
- /package/{reference → skills/plan}/plan-procedure.md +0 -0
- /package/{reference → skills/quality-gate}/threat-modeling.md +0 -0
- /package/{reference → skills/router}/router-rules.md +0 -0
- /package/{reference → skills/scan}/scan-procedure.md +0 -0
- /package/{reference → skills/start}/start-procedure.md +0 -0
- /package/{reference → skills/style}/style-doc-procedure.md +0 -0
- /package/{reference → skills/verify}/verify-procedure.md +0 -0
|
@@ -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,14 @@ 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
|
-
files: ['AGENTS.md'],
|
|
143
|
+
kind: 'multi-artifact',
|
|
151
144
|
},
|
|
152
145
|
]);
|
|
153
146
|
|
|
@@ -52,7 +52,7 @@ Based on user choice:
|
|
|
52
52
|
|
|
53
53
|
### 4. Apply Logic by Proposal Type
|
|
54
54
|
|
|
55
|
-
After the user chooses `a` (apply) or `e` (edit-then-apply), branch on the proposal's bracketed type tag and follow the per-type apply procedure in `./
|
|
55
|
+
After the user chooses `a` (apply) or `e` (edit-then-apply), branch on the proposal's bracketed type tag and follow the per-type apply procedure in `./apply-reflections-procedure.md` — one numbered procedure each for `[FRONTMATTER]`, `[REFERENCE]`, `[BUDGET]`, `[QUESTION]`, `[GLOBAL-SKILL]`. All branches end with `**Applied**: <date>` appended to the proposal block in the reflections file.
|
|
56
56
|
|
|
57
57
|
### 5. Summary
|
|
58
58
|
|
|
@@ -38,7 +38,7 @@ You are the deterministic cache-key computer and cache-manifest writer for the o
|
|
|
38
38
|
|
|
39
39
|
## Deterministic Input-Hash Algorithm
|
|
40
40
|
|
|
41
|
-
The canonical reference implementation (single source of truth; `hooks/budget-enforcer.js` imports the same primitive via a shared helper) lives in `./
|
|
41
|
+
The canonical reference implementation (single source of truth; `hooks/budget-enforcer.js` imports the same primitive via a shared helper) lives in `./cache-policy.md#deterministic-input-hash-algorithm-layer-b` — it documents the JS implementation, the maintainer notes (sorted-unique paths, MISSING-file sentinel, agent-path bust behavior), the manifest shape, and TTL semantics in one place. Conform to the algorithm exactly so the hook and any orchestrator agree byte-for-byte.
|
|
42
42
|
|
|
43
43
|
## Integration Points
|
|
44
44
|
|
|
@@ -63,4 +63,4 @@ Per D-09:
|
|
|
63
63
|
|
|
64
64
|
## TTL Semantics
|
|
65
65
|
|
|
66
|
-
Default `ttl_seconds` = `.design/budget.json.cache_ttl_seconds` = 3600s (1 hour) per D-10. `expires_at` is computed at write time and stored; readers do not recompute. Stale entries are lazily cleaned on read (no eager reaper in v1). Full TTL discussion: `./
|
|
66
|
+
Default `ttl_seconds` = `.design/budget.json.cache_ttl_seconds` = 3600s (1 hour) per D-10. `expires_at` is computed at write time and stored; readers do not recompute. Stale entries are lazily cleaned on read (no eager reaper in v1). Full TTL discussion: `./cache-policy.md#ttl-semantics-layer-b`.
|
package/skills/compare/SKILL.md
CHANGED
|
@@ -9,7 +9,7 @@ user-invocable: true
|
|
|
9
9
|
|
|
10
10
|
Standalone delta command. Computes the difference between the scan baseline (`DESIGN.md`) and the verification result (`DESIGN-VERIFICATION.md`), and flags design drift for any regression not covered by an explicit task in `DESIGN-PLAN.md`. Writes one artifact: `.design/COMPARE-REPORT.md`.
|
|
11
11
|
|
|
12
|
-
For the full step-by-step methodology (score parsing, set arithmetic for anti-patterns, drift-coverage map, screenshot-delta probe, and `COMPARE-REPORT.md` template), see
|
|
12
|
+
For the full step-by-step methodology (score parsing, set arithmetic for anti-patterns, drift-coverage map, screenshot-delta probe, and `COMPARE-REPORT.md` template), see `./compare-rubric.md`. For the cross-skill output discipline (artifact prefix, completion marker, MUST-NOT-write list, connection-probe pattern), see `../../reference/shared-preamble.md#output-contract-reminders` and `../../reference/shared-preamble.md#connection-handshake-summary`. For the underlying 0–10 category-scoring rubric the delta is computed against, see `../../reference/audit-scoring.md`.
|
|
13
13
|
|
|
14
14
|
---
|
|
15
15
|
|
|
@@ -45,13 +45,13 @@ Probe `preview` connection per `../../reference/shared-preamble.md#connection-ha
|
|
|
45
45
|
|
|
46
46
|
## Workflow
|
|
47
47
|
|
|
48
|
-
1. **Parse Category Scores** — extract baseline + result score tables, normalize names, flag unmatched. Detail:
|
|
49
|
-
2. **Compute Score Delta** — `delta = result - baseline`, classify (`improvement`/`no_change`/`regression`). Detail:
|
|
50
|
-
3. **Anti-Pattern Delta** — set arithmetic on baseline vs result anti-pattern sets (resolved / new / unchanged). Detail:
|
|
51
|
-
4. **Must-Have Pass/Fail Change** — read `<must_haves>` from `DESIGN-CONTEXT.md`, status from `DESIGN-VERIFICATION.md`. Detail:
|
|
52
|
-
5. **Design Drift Detection (COMP-04)** — build coverage map from `DESIGN-PLAN.md` `Type:` fields; for each `regression` not in coverage_map → emit `DRIFT: [category] ...`. Detail:
|
|
53
|
-
6. **Screenshot Delta (preview: available only)** — capture per-route screenshots to `.design/screenshots/{before,after}/<route>.png`. Detail:
|
|
54
|
-
7. **Write `.design/COMPARE-REPORT.md`** — full template at
|
|
48
|
+
1. **Parse Category Scores** — extract baseline + result score tables, normalize names, flag unmatched. Detail: `./compare-rubric.md#step-1--parse-category-scores`.
|
|
49
|
+
2. **Compute Score Delta** — `delta = result - baseline`, classify (`improvement`/`no_change`/`regression`). Detail: `./compare-rubric.md#step-2--compute-score-delta-comp-03`.
|
|
50
|
+
3. **Anti-Pattern Delta** — set arithmetic on baseline vs result anti-pattern sets (resolved / new / unchanged). Detail: `./compare-rubric.md#step-3--anti-pattern-delta`.
|
|
51
|
+
4. **Must-Have Pass/Fail Change** — read `<must_haves>` from `DESIGN-CONTEXT.md`, status from `DESIGN-VERIFICATION.md`. Detail: `./compare-rubric.md#step-4--must-have-passfail-change`.
|
|
52
|
+
5. **Design Drift Detection (COMP-04)** — build coverage map from `DESIGN-PLAN.md` `Type:` fields; for each `regression` not in coverage_map → emit `DRIFT: [category] ...`. Detail: `./compare-rubric.md#step-5--design-drift-detection-comp-04`.
|
|
53
|
+
6. **Screenshot Delta (preview: available only)** — capture per-route screenshots to `.design/screenshots/{before,after}/<route>.png`. Detail: `./compare-rubric.md#step-5b--screenshot-delta-when-preview-available`.
|
|
54
|
+
7. **Write `.design/COMPARE-REPORT.md`** — full template at `./compare-rubric.md#step-6--compare-reportmd-template`.
|
|
55
55
|
|
|
56
56
|
---
|
|
57
57
|
|
|
@@ -12,7 +12,7 @@ Interactive onboarding for the 12 external integrations the pipeline supports. R
|
|
|
12
12
|
|
|
13
13
|
Canonical per-connection specs live in `../../connections/<name>.md` (one file per integration). The capability matrix + probe-pattern spec live in `../../connections/connections.md`. This skill is the **user-facing front end** for those specs.
|
|
14
14
|
|
|
15
|
-
For the 12 probe scripts (MCP + HTTP + CLI + file probes), bucket categorization, per-connection setup screen, auto-run eligibility matrix, value-prop one-liners, and STATE.md / config.json write contracts, see
|
|
15
|
+
For the 12 probe scripts (MCP + HTTP + CLI + file probes), bucket categorization, per-connection setup screen, auto-run eligibility matrix, value-prop one-liners, and STATE.md / config.json write contracts, see `./connections-onboarding.md`. For the cross-skill probe pattern + connection-handshake summary, see `../../reference/shared-preamble.md#connection-handshake-summary`. For the cross-skill output discipline, see `../../reference/shared-preamble.md#output-contract-reminders`.
|
|
16
16
|
|
|
17
17
|
---
|
|
18
18
|
|
|
@@ -38,20 +38,20 @@ For the 12 probe scripts (MCP + HTTP + CLI + file probes), bucket categorization
|
|
|
38
38
|
|
|
39
39
|
## Workflow
|
|
40
40
|
|
|
41
|
-
1. **Probe all 12 connections** — run every probe script per
|
|
42
|
-
2. **Categorize + build summary** — bucket each probe result (available / recommended / optional / skipped / unavailable) using project-hint detection. Detail + recommendation mapping:
|
|
43
|
-
3. **Print summary table** — show buckets + value-prop one-liners (verbatim from
|
|
44
|
-
4. **Route by mode** — `list` / `--auto` exits after summary; `<name>` jumps straight to Step 5; default mode opens an AskUserQuestion (configure recommended / pick one by one / configure all optional / re-check specific / exit). Routing detail:
|
|
45
|
-
5. **Per-connection setup screen** — for each target: read `connections/<name>.md`, present the setup screen, AskUserQuestion (run now / copy-paste / skip / never ask). Auto-run only if reversible (see eligibility matrix). On success: append name to `connections_onboarding.pending_verification[]`. Detail:
|
|
46
|
-
6. **Verification pass** — re-probe every name in `pending_verification[]`. Available → remove. `not_configured` → leave (needs session restart). `unavailable` → leave + note OAuth needed. Print "Setup complete" summary. Detail:
|
|
41
|
+
1. **Probe all 12 connections** — run every probe script per `./connections-onboarding.md#step-1--probe-all-12-connections`. MCP probes use `ToolSearch` first; HTTP / CLI / file probes follow non-MCP patterns. Merge results into `STATE.md <connections>` with the three-value schema (`available | unavailable | not_configured`) — never add new values.
|
|
42
|
+
2. **Categorize + build summary** — bucket each probe result (available / recommended / optional / skipped / unavailable) using project-hint detection. Detail + recommendation mapping: `./connections-onboarding.md#step-2--bucket-categorization`.
|
|
43
|
+
3. **Print summary table** — show buckets + value-prop one-liners (verbatim from `./connections-onboarding.md#step-3--summary-table`).
|
|
44
|
+
4. **Route by mode** — `list` / `--auto` exits after summary; `<name>` jumps straight to Step 5; default mode opens an AskUserQuestion (configure recommended / pick one by one / configure all optional / re-check specific / exit). Routing detail: `./connections-onboarding.md#step-4--route-by-mode`.
|
|
45
|
+
5. **Per-connection setup screen** — for each target: read `connections/<name>.md`, present the setup screen, AskUserQuestion (run now / copy-paste / skip / never ask). Auto-run only if reversible (see eligibility matrix). On success: append name to `connections_onboarding.pending_verification[]`. Detail: `./connections-onboarding.md#step-5--per-connection-setup-screen`.
|
|
46
|
+
6. **Verification pass** — re-probe every name in `pending_verification[]`. Available → remove. `not_configured` → leave (needs session restart). `unavailable` → leave + note OAuth needed. Print "Setup complete" summary. Detail: `./connections-onboarding.md#step-6--verification-pass`.
|
|
47
47
|
|
|
48
|
-
If `.design/config.json > connections_onboarding.pending_verification[]` is non-empty at entry → enter **resume flow**: run Step 6 immediately; if clean, exit; otherwise fall through to Step 3. Detail:
|
|
48
|
+
If `.design/config.json > connections_onboarding.pending_verification[]` is non-empty at entry → enter **resume flow**: run Step 6 immediately; if clean, exit; otherwise fall through to Step 3. Detail: `./connections-onboarding.md#resumability`.
|
|
49
49
|
|
|
50
50
|
---
|
|
51
51
|
|
|
52
52
|
## Do Not
|
|
53
53
|
|
|
54
|
-
Per
|
|
54
|
+
Per `./connections-onboarding.md#do-not`:
|
|
55
55
|
|
|
56
56
|
- Never run `npm install -g` globals automatically.
|
|
57
57
|
- Never write to `~/.bashrc`, `~/.zshrc`, or shell RC files.
|