thachvd-kit 1.0.34 → 1.0.35

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/bin/entry.js CHANGED
@@ -11,6 +11,8 @@ function isInitInvocation(args) {
11
11
  if (args.includes('--help') || args.includes('-h') || args.includes('--version') || args.includes('-v')) {
12
12
  return false;
13
13
  }
14
+ // Note: 'upgrade' and 'global' are handled and returned above before this
15
+ // is ever called, so they never reach here.
14
16
  const first = args[0];
15
17
  return !first || first === 'init' || first.startsWith('-');
16
18
  }
@@ -0,0 +1,191 @@
1
+ const fs = require('fs');
2
+ const path = require('path');
3
+ const { spawnSync } = require('child_process');
4
+
5
+ // Source repository for Matt Pocock's promoted skills, installed via the
6
+ // upstream `skills` CLI (npx skills@latest add <source>).
7
+ const MATT_SKILLS_SOURCE = 'mattpocock/skills';
8
+
9
+ // This list mirrors upstream's promoted daily-driver catalog:
10
+ // https://github.com/mattpocock/skills -> skills/engineering/ + skills/productivity/
11
+ // Do NOT add anything from skills/in-progress, skills/misc, or skills/deprecated —
12
+ // those are explicitly not part of the supported set. Update this list by hand
13
+ // when upstream promotes a new skill or retires one; there is no reliable
14
+ // upstream "promoted only" filter, so this manifest is the source of truth.
15
+ const PROMOTED_SKILLS = [
16
+ // skills/engineering
17
+ 'ask-matt',
18
+ 'code-review',
19
+ 'codebase-design',
20
+ 'diagnosing-bugs',
21
+ 'domain-modeling',
22
+ 'grill-with-docs',
23
+ 'implement',
24
+ 'improve-codebase-architecture',
25
+ 'prototype',
26
+ 'research',
27
+ 'resolving-merge-conflicts',
28
+ 'setup-matt-pocock-skills',
29
+ 'tdd',
30
+ 'to-spec',
31
+ 'to-tickets',
32
+ 'triage',
33
+ 'wayfinder',
34
+ 'wizard',
35
+ // skills/productivity
36
+ 'grill-me',
37
+ 'grilling',
38
+ 'handoff',
39
+ 'teach',
40
+ 'to-questionnaire',
41
+ 'wait-what',
42
+ 'writing-for-agents'
43
+ ];
44
+
45
+ // Agent identifiers as understood by the upstream `skills` CLI (verified
46
+ // against its installed agent registry). Both currently resolve to the same
47
+ // project-local skills directory below.
48
+ const SUPPORTED_AGENTS = ['codex', 'antigravity'];
49
+
50
+ // Project-local install target. Skills are intentionally not installed
51
+ // globally (see AGENTS.md / .agent/docs/tooling.md for the reasoning).
52
+ const SKILLS_RELATIVE_DIR = path.join('.agents', 'skills');
53
+
54
+ const SETUP_SKILL_NAME = 'setup-matt-pocock-skills';
55
+
56
+ function npxCommand() {
57
+ return process.platform === 'win32' ? 'npx.cmd' : 'npx';
58
+ }
59
+
60
+ function skillsDirFor(targetDir) {
61
+ return path.join(targetDir, SKILLS_RELATIVE_DIR);
62
+ }
63
+
64
+ function isSkillInstalled(targetDir, name) {
65
+ return fs.existsSync(path.join(skillsDirFor(targetDir), name, 'SKILL.md'));
66
+ }
67
+
68
+ // Read-only: never spawns a process. Safe to call from `doctor` and
69
+ // `skills check`.
70
+ function checkSkills(targetDir) {
71
+ const installed = [];
72
+ const missing = [];
73
+ for (const name of PROMOTED_SKILLS) {
74
+ (isSkillInstalled(targetDir, name) ? installed : missing).push(name);
75
+ }
76
+ return { installed, missing, total: PROMOTED_SKILLS.length };
77
+ }
78
+
79
+ // Builds the argv for `npx skills@latest add <source> ...`. Always passes
80
+ // `--skill <name>` as separate argv entries (never `--skill=<name>`): current
81
+ // `skills` CLI versions have a parsing bug where the `--skill=<name>` form is
82
+ // silently ignored and installs every skill in the source repository,
83
+ // including skills/in-progress, skills/misc, and skills/deprecated.
84
+ function buildAddArgs(skillNames) {
85
+ return [
86
+ '-y', // npx: auto-confirm installing the `skills` package itself
87
+ 'skills@latest',
88
+ 'add',
89
+ MATT_SKILLS_SOURCE,
90
+ '--skill', ...skillNames,
91
+ '--agent', ...SUPPORTED_AGENTS,
92
+ '-y' // skills CLI: skip its own confirmation prompts
93
+ ];
94
+ }
95
+
96
+ function formatCommand(args) {
97
+ return `${npxCommand()} ${args.join(' ')}`;
98
+ }
99
+
100
+ function runNpx(args, options = {}) {
101
+ return spawnSync(npxCommand(), args, {
102
+ cwd: options.cwd,
103
+ encoding: 'utf8',
104
+ stdio: options.stdio || 'pipe',
105
+ shell: process.platform === 'win32'
106
+ });
107
+ }
108
+
109
+ // Installs the full promoted set in a single `add` call (one clone, one
110
+ // filtered install). Never uses `--all`, which would also install
111
+ // in-progress/misc/deprecated skills.
112
+ function installSkills(targetDir, options = {}) {
113
+ const dryRun = options.dryRun === true;
114
+ const args = buildAddArgs(PROMOTED_SKILLS);
115
+ const command = formatCommand(args);
116
+
117
+ if (dryRun) {
118
+ return { ok: true, dryRun: true, command, message: `Dry run: would run ${command}` };
119
+ }
120
+
121
+ const result = runNpx(args, { cwd: targetDir, stdio: 'inherit' });
122
+ if (result.error || result.status !== 0) {
123
+ return { ok: false, dryRun: false, command, message: `failed to install promoted skills; run manually: ${command}` };
124
+ }
125
+ return {
126
+ ok: true,
127
+ dryRun: false,
128
+ command,
129
+ message: `installed ${PROMOTED_SKILLS.length} promoted Matt Pocock skills to ${SKILLS_RELATIVE_DIR}`
130
+ };
131
+ }
132
+
133
+ // Updates each promoted skill by re-adding it individually and idempotently.
134
+ // This is deliberately NOT `npx skills update`: upstream has a known issue
135
+ // where updating one project skill can reinstall every skill from the
136
+ // source. Re-adding by explicit single-skill name only ever touches that
137
+ // skill's directory (verified manually against the upstream CLI).
138
+ // Trade-off: this does one network clone of the source repo per promoted
139
+ // skill (~PROMOTED_SKILLS.length calls), so it is noticeably slower than
140
+ // `installSkills`'s single batched call. That cost is accepted deliberately
141
+ // for the safety guarantee above; revisit only if upstream ships a scoped,
142
+ // non-destructive `update`.
143
+ function updateSkills(targetDir, options = {}) {
144
+ const dryRun = options.dryRun === true;
145
+ const results = [];
146
+
147
+ for (const name of PROMOTED_SKILLS) {
148
+ const args = buildAddArgs([name]);
149
+ const command = formatCommand(args);
150
+
151
+ if (dryRun) {
152
+ results.push({ name, ok: true, dryRun: true, command });
153
+ continue;
154
+ }
155
+
156
+ const result = runNpx(args, { cwd: targetDir, stdio: 'pipe' });
157
+ const ok = !result.error && result.status === 0;
158
+ results.push({
159
+ name,
160
+ ok,
161
+ dryRun: false,
162
+ command,
163
+ error: ok ? null : (result.stderr || result.stdout || `exit ${result.status}`)
164
+ });
165
+ }
166
+
167
+ const failed = results.filter(r => !r.ok);
168
+ const message = dryRun
169
+ ? `Dry run: would update ${PROMOTED_SKILLS.length} promoted skills one by one`
170
+ : failed.length === 0
171
+ ? `updated ${PROMOTED_SKILLS.length} promoted Matt Pocock skills`
172
+ : `updated ${results.length - failed.length}/${PROMOTED_SKILLS.length} promoted skills; failed: ${failed.map(f => f.name).join(', ')}`;
173
+
174
+ return { ok: failed.length === 0, dryRun, results, message };
175
+ }
176
+
177
+ module.exports = {
178
+ MATT_SKILLS_SOURCE,
179
+ PROMOTED_SKILLS,
180
+ SUPPORTED_AGENTS,
181
+ SKILLS_RELATIVE_DIR,
182
+ SETUP_SKILL_NAME,
183
+ npxCommand,
184
+ skillsDirFor,
185
+ isSkillInstalled,
186
+ checkSkills,
187
+ buildAddArgs,
188
+ formatCommand,
189
+ installSkills,
190
+ updateSkills
191
+ };
package/bin/policy.js CHANGED
@@ -49,11 +49,11 @@ const FAST_PATH_SECTION = `## Fast Path
49
49
 
50
50
  Fast-path eligibility is based on risk and contract surface, not file count. Use it only when the change is localized, mechanically obvious, has no meaningful public API, schema, security, data-integrity, dependency, CI/release, or architectural risk, and has focused verification available. A two-file change such as code plus its focused test may still be fast-path; a one-file auth, payment, schema, concurrency, or other high-risk change is not.
51
51
 
52
- State the narrow scope and verification before editing. If the task becomes ambiguous, introduces new behavior or architectural decisions, or its risk/contract surface grows, switch to brainstorming and planning.`;
52
+ State the narrow scope and verification before editing. If the task becomes ambiguous, introduces new behavior or architectural decisions, or its risk/contract surface grows, switch to the matching planning skill (for example /grill-with-docs or /wayfinder).`;
53
53
 
54
54
  const GETTING_STARTED_FAST_PATH_SECTION = `## Fast Path
55
55
 
56
- Use a fast path when the change is localized, mechanically obvious, low-risk, and has focused verification. File count alone does not determine eligibility: code plus a focused test can still be trivial, while a one-file security, schema, payment, concurrency, or public-contract change requires the full workflow. If scope or risk grows, return to brainstorming and planning.`;
56
+ Use a fast path when the change is localized, mechanically obvious, low-risk, and has focused verification. File count alone does not determine eligibility: code plus a focused test can still be trivial, while a one-file security, schema, payment, concurrency, or public-contract change requires the full workflow. If scope or risk grows, return to the matching planning skill (for example /grill-with-docs or /wayfinder).`;
57
57
 
58
58
  const TOOL_ROUTING_SECTION = `## Tool Routing
59
59
 
@@ -100,11 +100,11 @@ function replaceFastPathInline(markdown) {
100
100
  return normalizeNewlines(markdown)
101
101
  .replace(
102
102
  'Questions and research do not edit product code. A simple fix may use a fast path only when it is one-file, unambiguous, and changes no behavior or contract. State the scope and verification before editing. If the scope grows, switch to the full Superpowers flow.',
103
- 'Questions and research do not edit product code. A fast path is allowed only when the change is localized, mechanically obvious, low-risk, and has focused verification; file count alone is not a gate. State the scope and verification before editing. If the task becomes ambiguous or its behavior, contract, or risk surface grows, switch to the full Superpowers flow.'
103
+ 'Questions and research do not edit product code. A fast path is allowed only when the change is localized, mechanically obvious, low-risk, and has focused verification; file count alone is not a gate. State the scope and verification before editing. If the task becomes ambiguous or its behavior, contract, or risk surface grows, switch to the matching planning skill instead.'
104
104
  )
105
105
  .replace(
106
106
  'Questions and research do not edit product code. A simple fix may use a fast path only when it is one-file, unambiguous, and changes no behavior or contract. State the narrow scope and verification before editing. If the scope grows, return to brainstorming and planning.',
107
- 'Questions and research do not edit product code. A fast path is allowed only when the change is localized, mechanically obvious, low-risk, and has focused verification; file count alone is not a gate. State the narrow scope and verification before editing. If scope or risk grows, return to brainstorming and planning.'
107
+ 'Questions and research do not edit product code. A fast path is allowed only when the change is localized, mechanically obvious, low-risk, and has focused verification; file count alone is not a gate. State the narrow scope and verification before editing. If scope or risk grows, return to the matching planning skill instead.'
108
108
  );
109
109
  }
110
110
 
@@ -183,8 +183,12 @@ module.exports = {
183
183
  POLICY_PATHS,
184
184
  QUALITY_FLOOR_SECTION,
185
185
  AGENT_RULES_SECTION,
186
+ CONVENTIONS_STANDARDS_SECTION,
186
187
  FAST_PATH_SECTION,
188
+ GETTING_STARTED_FAST_PATH_SECTION,
187
189
  TOOL_ROUTING_SECTION,
190
+ normalizeNewlines,
191
+ replaceSection,
188
192
  upgradeGeneratedContent,
189
193
  upgradeAgentsMarkdown,
190
194
  upgradeConventionsMarkdown,
package/bin/upgrade.js CHANGED
@@ -1,86 +1,298 @@
1
- const fs = require('fs');
2
- const path = require('path');
3
-
4
- const START = '<!-- thachvd-kit:project-policy:start -->';
5
- const END = '<!-- thachvd-kit:project-policy:end -->';
6
-
7
- const PROJECT_POLICY = `${START}
8
- ## Engineering Policy
9
-
10
- Prefer the smallest sufficient change, not the fewest lines of code.
11
-
12
- - Preserve required behavior, product and architectural contracts, UX/accessibility, security/data integrity, compatibility/performance, and maintainability before optimizing for simplicity.
13
- - Reuse an existing project abstraction when it satisfies the required contract. Do not bypass it merely because a lower-level primitive is shorter.
14
- - Avoid speculative abstractions and unrelated refactors.
15
- - Do not split or reorganize code solely to satisfy a line-count target. Prefer cohesive modules and split only for a concrete cohesion, ownership, testability, or maintainability benefit.
16
- - Fast-path eligibility is based on risk and contract surface, not file count. A code change plus its focused test can still be trivial; a one-file auth, payment, schema, concurrency, or public-contract change is not.
17
- - Use the cheapest reliable context source. Read/search directly for known local code and exact text; use one structural index such as codebase-memory-mcp or CodeGraph for unknown ownership, call paths, architecture, or impact; avoid duplicate retrieval once sufficient evidence is available.
18
- - Prefer RTK for verbose shell output when it preserves the information needed. Use raw output when required for diagnosis.
19
- - Tests or equivalent verification are mandatory before claiming completion.
20
- ${END}`;
21
-
22
- const TARGETS = [
23
- 'AGENTS.md',
24
- path.join('.agent', 'docs', 'conventions.md'),
25
- path.join('.agent', 'docs', 'workflow.md'),
26
- path.join('.agent', 'docs', 'tooling.md')
27
- ];
28
-
29
- function normalize(text) {
30
- return String(text || '').replace(/\r\n/g, '\n');
31
- }
32
-
33
- function removeKnownObsoleteDefaults(text) {
34
- return normalize(text)
35
- .replace(/^\s*- Maximum file length: 300 lines unless the existing project standard is stricter\.\s*\n?/gm, '')
36
- .replace(/^\s*- Keep files under 300 lines unless the project already has a different standard[^\n]*\n?/gm, '')
37
- .replace(/^\s*- \*\*MCP First\*\*:[^\n]*\n?/gm, '')
38
- .replace(/^\s*- Use MCP first for code discovery and technical documentation;[^\n]*\n?/gm, '')
39
- .replace(/Use it only for one-file, unambiguous changes with no behavior, API, schema, security, dependency, CI, workflow, or release contract change\.[^\n]*/g,
40
- 'Fast-path eligibility is based on risk and contract surface, not file count. Use it only for localized, mechanically obvious, low-risk changes with focused verification.')
41
- .replace(/Use a fast path only for one-file, unambiguous changes with no behavior or contract change\.[^\n]*/g,
42
- 'Use a fast path only for localized, mechanically obvious, low-risk changes with focused verification; file count alone is not a gate.')
43
- .replace(/\n{3,}/g, '\n\n');
44
- }
45
-
46
- function upsertManagedBlock(content) {
47
- let text = removeKnownObsoleteDefaults(content);
48
- const start = text.indexOf(START);
49
- const end = text.indexOf(END);
50
-
51
- if (start >= 0 && end >= start) {
52
- const after = end + END.length;
53
- return `${text.slice(0, start)}${PROJECT_POLICY}${text.slice(after)}`.replace(/\n{3,}/g, '\n\n').trimEnd() + '\n';
54
- }
55
-
56
- const trimmed = text.trimEnd();
57
- return `${trimmed}${trimmed ? '\n\n' : ''}${PROJECT_POLICY}\n`;
58
- }
59
-
60
- function upgradeProject(rootDir, options = {}) {
61
- const dryRun = options.dryRun === true;
62
- const results = [];
63
-
64
- for (const relativePath of TARGETS) {
65
- const fullPath = path.join(rootDir, relativePath);
66
- if (!fs.existsSync(fullPath)) continue;
67
-
68
- const existing = fs.readFileSync(fullPath, 'utf8');
69
- const updated = upsertManagedBlock(existing);
70
- const changed = normalize(existing) !== updated;
71
- if (changed && !dryRun) fs.writeFileSync(fullPath, updated, 'utf8');
72
- results.push({ path: relativePath, changed, dryRun: changed && dryRun });
73
- }
74
-
75
- return results;
76
- }
77
-
78
- module.exports = {
79
- START,
80
- END,
81
- PROJECT_POLICY,
82
- TARGETS,
83
- removeKnownObsoleteDefaults,
84
- upsertManagedBlock,
85
- upgradeProject
86
- };
1
+ const fs = require('fs');
2
+ const path = require('path');
3
+ const { normalizeNewlines, replaceSection, FAST_PATH_SECTION, GETTING_STARTED_FAST_PATH_SECTION } = require('./policy');
4
+
5
+ const START = '<!-- thachvd-kit:project-policy:start -->';
6
+ const END = '<!-- thachvd-kit:project-policy:end -->';
7
+
8
+ const PROJECT_POLICY = `${START}
9
+ ## Engineering Policy
10
+
11
+ Prefer the smallest sufficient change, not the fewest lines of code.
12
+
13
+ - Preserve required behavior, product and architectural contracts, UX/accessibility, security/data integrity, compatibility/performance, and maintainability before optimizing for simplicity.
14
+ - Reuse an existing project abstraction when it satisfies the required contract. Do not bypass it merely because a lower-level primitive is shorter.
15
+ - Avoid speculative abstractions and unrelated refactors.
16
+ - Do not split or reorganize code solely to satisfy a line-count target. Prefer cohesive modules and split only for a concrete cohesion, ownership, testability, or maintainability benefit.
17
+ - Fast-path eligibility is based on risk and contract surface, not file count. A code change plus its focused test can still be trivial; a one-file auth, payment, schema, concurrency, or public-contract change is not.
18
+ - Use the cheapest reliable context source. Read/search directly for known local code and exact text; use one structural index such as codebase-memory-mcp or CodeGraph for unknown ownership, call paths, architecture, or impact; avoid duplicate retrieval once sufficient evidence is available.
19
+ - Prefer RTK for verbose shell output when it preserves the information needed. Use raw output when required for diagnosis.
20
+ - Tests or equivalent verification are mandatory before claiming completion.
21
+ ${END}`;
22
+
23
+ // Files managed by the "## Engineering Policy" block above (unchanged from
24
+ // before the Matt Pocock migration).
25
+ const TARGETS = [
26
+ 'AGENTS.md',
27
+ path.join('.agent', 'docs', 'conventions.md'),
28
+ path.join('.agent', 'docs', 'workflow.md'),
29
+ path.join('.agent', 'docs', 'tooling.md')
30
+ ];
31
+
32
+ function normalize(text) {
33
+ return normalizeNewlines(text);
34
+ }
35
+
36
+ function removeKnownObsoleteDefaults(text) {
37
+ return normalize(text)
38
+ .replace(/^\s*- Maximum file length: 300 lines unless the existing project standard is stricter\.\s*\n?/gm, '')
39
+ .replace(/^\s*- Keep files under 300 lines unless the project already has a different standard[^\n]*\n?/gm, '')
40
+ .replace(/^\s*- \*\*MCP First\*\*:[^\n]*\n?/gm, '')
41
+ .replace(/^\s*- Use MCP first for code discovery and technical documentation;[^\n]*\n?/gm, '')
42
+ .replace(/Use it only for one-file, unambiguous changes with no behavior, API, schema, security, dependency, CI, workflow, or release contract change\.[^\n]*/g,
43
+ 'Fast-path eligibility is based on risk and contract surface, not file count. Use it only for localized, mechanically obvious, low-risk changes with focused verification.')
44
+ .replace(/Use a fast path only for one-file, unambiguous changes with no behavior or contract change\.[^\n]*/g,
45
+ 'Use a fast path only for localized, mechanically obvious, low-risk changes with focused verification; file count alone is not a gate.')
46
+ .replace(/\n{3,}/g, '\n\n');
47
+ }
48
+
49
+ function upsertManagedBlock(content) {
50
+ let text = removeKnownObsoleteDefaults(content);
51
+ const start = text.indexOf(START);
52
+ const end = text.indexOf(END);
53
+
54
+ if (start >= 0 && end >= start) {
55
+ const after = end + END.length;
56
+ return `${text.slice(0, start)}${PROJECT_POLICY}${text.slice(after)}`.replace(/\n{3,}/g, '\n\n').trimEnd() + '\n';
57
+ }
58
+
59
+ const trimmed = text.trimEnd();
60
+ return `${trimmed}${trimmed ? '\n\n' : ''}${PROJECT_POLICY}\n`;
61
+ }
62
+
63
+ // --- Superpowers -> Matt Pocock skills migration -------------------------
64
+ //
65
+ // thachvd-kit used to generate Superpowers-branded workflow content into
66
+ // AGENTS.md, .cursorrules, and .agent/docs/{workflow,tooling,getting-started,
67
+ // index-project-prompt}.md. `upgrade` must move an existing project's
68
+ // *generated* sections over to the current Matt Pocock skill workflow while
69
+ // leaving hand-written/custom content alone.
70
+ //
71
+ // This never does a blind "contains Superpowers" strip. Each replacement is
72
+ // gated on the exact signature thachvd-kit itself used to emit for that
73
+ // section (checked with `LEGACY.test(...)` against the section body before
74
+ // touching it); a section whose content doesn't match is left untouched,
75
+ // including if the user rewrote it themselves. The "## Fast Path" sections
76
+ // are the one exception: they are already synced unconditionally by
77
+ // bin/policy.js for `init`, and this mirrors that exact behavior instead of
78
+ // duplicating a second definition of "current" fast-path wording.
79
+
80
+ const SUPERPOWERS_MIGRATION_TARGETS = [
81
+ 'AGENTS.md',
82
+ '.cursorrules',
83
+ path.join('.agent', 'docs', 'workflow.md'),
84
+ path.join('.agent', 'docs', 'tooling.md'),
85
+ path.join('.agent', 'docs', 'getting-started.md'),
86
+ path.join('.agent', 'docs', 'index-project-prompt.md')
87
+ ];
88
+
89
+ function extractSection(text, heading) {
90
+ const marker = `${heading}\n`;
91
+ const start = text.indexOf(marker);
92
+ if (start < 0) return null;
93
+ const searchFrom = start + marker.length;
94
+ const nextHeading = text.indexOf('\n## ', searchFrom);
95
+ const end = nextHeading >= 0 ? nextHeading + 1 : text.length;
96
+ return { start, end, body: text.slice(start, end) };
97
+ }
98
+
99
+ // Replaces a heading-delimited section only when its current body matches a
100
+ // known legacy signature. Leaves the text unchanged if the heading is
101
+ // missing or its content doesn't look like thachvd-kit's own old output.
102
+ function replaceLegacySection(text, heading, legacySignature, replacement) {
103
+ const section = extractSection(text, heading);
104
+ if (!section || !legacySignature.test(section.body)) return text;
105
+ const prefix = text.slice(0, section.start);
106
+ const suffix = text.slice(section.end).replace(/^\n+/, '');
107
+ return `${prefix}${replacement.trimEnd()}\n\n${suffix}`.replace(/\n{3,}/g, '\n\n');
108
+ }
109
+
110
+ // Replaces one exact known-legacy line/sentence with its current
111
+ // equivalent. Safe because the match is the full, specific sentence
112
+ // thachvd-kit generated, not a loose keyword.
113
+ function replaceLegacyLine(text, legacyLine, replacementLine) {
114
+ return text.includes(legacyLine) ? text.split(legacyLine).join(replacementLine) : text;
115
+ }
116
+
117
+ const AGENTS_WORKFLOW_SECTION = `## Workflow
118
+
119
+ Matt Pocock's promoted skills (installed under \`.agents/skills/\` by \`thachvd-kit setup\`) are the workflow layer. Use the matching skill when a specialized workflow is useful:
120
+
121
+ - Clear, localized change: inspect -> edit -> focused verification. Do not force a heavyweight skill.
122
+ - Ambiguous feature or design: \`/grill-with-docs\`, then optionally \`/to-spec\` for a durable contract.
123
+ - Normal feature: \`/grill-with-docs\` -> \`/to-spec\` -> \`/implement\`.
124
+ - Large feature needing decomposition: add \`/to-tickets\` before \`/implement\`.
125
+ - Huge, multi-session uncertainty: \`/wayfinder\`.
126
+ - Bug or failing behavior: \`/diagnosing-bugs\`.
127
+ - Test-driven implementation: \`/tdd\` (skip the ceremony for trivial config/text changes).
128
+ - Architecture survey: \`/improve-codebase-architecture\`; use \`/codebase-design\` as the design vocabulary.
129
+ - Pre-completion review: \`/code-review\` once when code risk warrants it.
130
+
131
+ If unsure which skill fits, use \`/ask-matt\`.
132
+
133
+ Questions and research do not edit product code. A fast path is allowed only when the change is localized, mechanically obvious, low-risk, and has focused verification; file count alone is not a gate. State the scope and verification before editing. If the task becomes ambiguous or its behavior, contract, or risk surface grows, use the matching planning skill above instead.
134
+
135
+ See \`.agent/docs/workflow.md\` for the full route matrix. This kit does not implement a second workflow engine; it only installs and checks the promoted skill set (\`thachvd-kit skills install|check|update\`).`;
136
+
137
+ function migrateAgentsStyleMarkdown(content) {
138
+ let text = normalize(content);
139
+ text = replaceLegacySection(text, '## Workflow', /Superpowers is the primary workflow backend/, AGENTS_WORKFLOW_SECTION);
140
+ text = replaceLegacyLine(
141
+ text,
142
+ "- Superpowers: installed through the AI client's official plugin surface",
143
+ '- Matt Pocock skills: promoted set installed under `.agents/skills/` via `thachvd-kit skills install`'
144
+ );
145
+ // Older, short-form .cursorrules that never embedded the full AGENTS.md body.
146
+ text = replaceLegacyLine(
147
+ text,
148
+ 'Use Superpowers as the workflow backend. Use direct local evidence when it is sufficient and structural tooling such as codebase-memory MCP only when ownership, call paths, architecture, or impact need discovery.',
149
+ "Use Matt Pocock's promoted skills (`.agents/skills/`) as the workflow backend; run `/ask-matt` if unsure which one fits. Use direct local evidence when it is sufficient and structural tooling such as codebase-memory MCP only when ownership, call paths, architecture, or impact need discovery."
150
+ );
151
+ return text;
152
+ }
153
+
154
+ const WORKFLOW_ROUTE_MATRIX_SECTION = `## Route Matrix
155
+
156
+ | Situation | Skill | Gate |
157
+ |---|---|---|
158
+ | Question or research only | direct answer or research | no product-code edits |
159
+ | Clear, localized change | fast path (no skill) | inspect -> edit -> focused verify |
160
+ | Ambiguous feature or design | /grill-with-docs, then optionally /to-spec | durable contract before implementation when useful |
161
+ | Normal feature | /grill-with-docs -> /to-spec -> /implement | spec agreed before implementation |
162
+ | Large feature needing decomposition | /grill-with-docs -> /to-spec -> /to-tickets -> /implement | tickets agreed before implementation |
163
+ | Huge, multi-session uncertainty | /wayfinder | shared decision map before implementation |
164
+ | Bug or failing behavior | /diagnosing-bugs | reproduce -> root cause -> regression protection -> fix -> verify |
165
+ | Test-driven implementation | /tdd | red -> green -> refactor per slice |
166
+ | Architecture survey | /improve-codebase-architecture (+ /codebase-design vocabulary) | findings reviewed before large refactors |
167
+ | Pre-merge | /code-review | blocking findings resolved |
168
+
169
+ Not sure which row applies? Run /ask-matt instead of guessing.`;
170
+
171
+ const WORKFLOW_STANDARD_FLOW_SECTION = `## Standard Feature Flow
172
+
173
+ /grill-with-docs -> /to-spec -> (/to-tickets for large work) -> /implement (with /tdd where it helps) -> /code-review.`;
174
+
175
+ function migrateWorkflowMarkdown(content) {
176
+ let text = normalize(content);
177
+ text = replaceLegacyLine(
178
+ text,
179
+ 'This project uses Superpowers as the workflow backend. thachvd-kit only provides project context and integration setup.',
180
+ "This project uses Matt Pocock's promoted skills (installed under .agents/skills/ by `thachvd-kit setup`) as the workflow layer. thachvd-kit only provides project context, the skill manifest, and integration setup; it is not a second workflow engine."
181
+ );
182
+ text = replaceLegacyLine(
183
+ text,
184
+ '2. Use the native Superpowers skill that matches the request.',
185
+ '2. Use the promoted skill that matches the request, or run /ask-matt if unsure which one fits.'
186
+ );
187
+ text = replaceLegacySection(text, '## Route Matrix', /Superpowers path/, WORKFLOW_ROUTE_MATRIX_SECTION);
188
+ text = replaceLegacySection(text, '## Standard Feature Flow', /\bbrainstorming\s*->/, WORKFLOW_STANDARD_FLOW_SECTION);
189
+ // Always kept in sync with the current risk-based wording, same as
190
+ // bin/policy.js does for a freshly generated project.
191
+ text = replaceSection(text, '## Fast Path', FAST_PATH_SECTION);
192
+ return text;
193
+ }
194
+
195
+ const TOOLING_MATT_SKILLS_SECTION = `## Matt Pocock Skills
196
+
197
+ Matt Pocock's promoted engineering and productivity skills are the workflow layer for this project, installed project-locally under \`.agents/skills/\` (never globally):
198
+
199
+ - Install the promoted set: \`thachvd-kit skills install\` (\`--dry-run\` to preview the command without running it)
200
+ - Check what is installed: \`thachvd-kit skills check\` (read-only)
201
+ - Update the promoted set: \`thachvd-kit skills update\` (re-adds each skill individually for safety, so it is slower than install — one network clone per skill)
202
+ - The full manifest lives in \`bin/matt-skills.js\` (\`PROMOTED_SKILLS\`); it mirrors upstream's \`skills/engineering/\` + \`skills/productivity/\` catalog and never includes \`in-progress\`, \`misc\`, or \`deprecated\` skills.
203
+ - After the first install, run \`/setup-matt-pocock-skills\` once inside the AI client to configure the issue tracker, triage labels, and generated docs location. thachvd-kit does not simulate that skill.
204
+ - Unsure which skill fits a task? Run \`/ask-matt\`.`;
205
+
206
+ function migrateToolingMarkdown(content) {
207
+ const text = normalize(content);
208
+ return replaceLegacySection(text, '## Superpowers', /Install Superpowers separately/, TOOLING_MATT_SKILLS_SECTION);
209
+ }
210
+
211
+ const GETTING_STARTED_SETUP_SECTION = `## Setup
212
+
213
+ 1. Run \`thachvd-kit init\` in the repository.
214
+ 2. Open or print \`.agent/docs/index-project-prompt.md\` with \`thachvd-kit prompt\`.
215
+ 3. Run \`thachvd-kit setup\` (installs the promoted skill set by default; add \`--no-install-skills\` to skip) and RTK.
216
+ 4. Inside the AI client, run \`/setup-matt-pocock-skills\` once to configure the issue tracker, triage labels, and doc layout.
217
+ 5. Run \`thachvd-kit doctor\` and restart the AI client.`;
218
+
219
+ const GETTING_STARTED_STANDARD_FLOW_SECTION = `## Standard Flow
220
+
221
+ 1. \`/grill-with-docs\` for unclear requirements or design.
222
+ 2. \`/to-spec\` when a durable implementation contract is useful.
223
+ 3. \`/to-tickets\` for large work that benefits from decomposition.
224
+ 4. \`/implement\`, with \`/tdd\` where red-green-refactor helps.
225
+ 5. \`/code-review\` once before completion.
226
+
227
+ Not sure which skill fits? Run \`/ask-matt\`.`;
228
+
229
+ const GETTING_STARTED_BUG_FLOW_SECTION = `## Bug Flow
230
+
231
+ Use \`/diagnosing-bugs\`: reproduce the symptom, inspect the path with codebase-memory MCP, test hypotheses, add regression protection, fix the root cause, and verify.`;
232
+
233
+ function migrateGettingStartedMarkdown(content) {
234
+ let text = normalize(content);
235
+ text = replaceLegacyLine(
236
+ text,
237
+ 'thachvd-kit creates project context. Superpowers owns the development workflow.',
238
+ "thachvd-kit creates project context. Matt Pocock's promoted skills own the development workflow."
239
+ );
240
+ text = replaceLegacySection(text, '## Setup', /Install Superpowers and RTK/, GETTING_STARTED_SETUP_SECTION);
241
+ text = replaceLegacySection(text, '## Standard Flow', /Use Superpowers native skills/, GETTING_STARTED_STANDARD_FLOW_SECTION);
242
+ text = replaceLegacySection(text, '## Bug Flow', /`systematic-debugging`/, GETTING_STARTED_BUG_FLOW_SECTION);
243
+ // Always kept in sync, same reasoning as the workflow.md Fast Path above.
244
+ text = replaceSection(text, '## Fast Path', GETTING_STARTED_FAST_PATH_SECTION);
245
+ return text;
246
+ }
247
+
248
+ function migrateIndexProjectPrompt(content) {
249
+ return replaceLegacyLine(
250
+ normalize(content),
251
+ 'Use Superpowers for the workflow and use codebase-memory MCP for structural code discovery when available.',
252
+ 'Use the project\'s Matt Pocock skills for workflow (see AGENTS.md; run /ask-matt if unsure which fits) and use codebase-memory MCP for structural code discovery when available.'
253
+ );
254
+ }
255
+
256
+ function migrateSuperpowersWorkflow(relativePath, content) {
257
+ const normalized = relativePath.split(path.sep).join('/');
258
+ if (normalized === 'AGENTS.md' || normalized === '.cursorrules') return migrateAgentsStyleMarkdown(content);
259
+ if (normalized.endsWith('/workflow.md')) return migrateWorkflowMarkdown(content);
260
+ if (normalized.endsWith('/tooling.md')) return migrateToolingMarkdown(content);
261
+ if (normalized.endsWith('/getting-started.md')) return migrateGettingStartedMarkdown(content);
262
+ if (normalized.endsWith('/index-project-prompt.md')) return migrateIndexProjectPrompt(content);
263
+ return normalize(content);
264
+ }
265
+
266
+ const ALL_UPGRADE_TARGETS = Array.from(new Set([...TARGETS, ...SUPERPOWERS_MIGRATION_TARGETS]));
267
+
268
+ function upgradeProject(rootDir, options = {}) {
269
+ const dryRun = options.dryRun === true;
270
+ const results = [];
271
+
272
+ for (const relativePath of ALL_UPGRADE_TARGETS) {
273
+ const fullPath = path.join(rootDir, relativePath);
274
+ if (!fs.existsSync(fullPath)) continue;
275
+
276
+ const existing = fs.readFileSync(fullPath, 'utf8');
277
+ let updated = migrateSuperpowersWorkflow(relativePath, existing);
278
+ if (TARGETS.includes(relativePath)) updated = upsertManagedBlock(updated);
279
+
280
+ const changed = normalize(existing) !== updated;
281
+ if (changed && !dryRun) fs.writeFileSync(fullPath, updated, 'utf8');
282
+ results.push({ path: relativePath, changed, dryRun: changed && dryRun });
283
+ }
284
+
285
+ return results;
286
+ }
287
+
288
+ module.exports = {
289
+ START,
290
+ END,
291
+ PROJECT_POLICY,
292
+ TARGETS,
293
+ SUPERPOWERS_MIGRATION_TARGETS,
294
+ removeKnownObsoleteDefaults,
295
+ upsertManagedBlock,
296
+ migrateSuperpowersWorkflow,
297
+ upgradeProject
298
+ };