devtronic 1.2.3 → 1.2.5

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.
Files changed (22) hide show
  1. package/README.md +7 -7
  2. package/dist/index.js +206 -174
  3. package/package.json +1 -1
  4. package/templates/addons/auto-devtronic/agents/failure-analyst.md +156 -0
  5. package/templates/addons/auto-devtronic/agents/issue-parser.md +145 -0
  6. package/templates/addons/auto-devtronic/agents/quality-runner.md +85 -0
  7. package/templates/addons/auto-devtronic/manifest.json +16 -0
  8. package/templates/addons/auto-devtronic/skills/auto-devtronic/SKILL.md +611 -0
  9. package/templates/addons/design-best-practices/manifest.json +28 -0
  10. package/templates/addons/design-best-practices/reference/color-and-contrast.md +146 -0
  11. package/templates/addons/design-best-practices/reference/interaction-design.md +208 -0
  12. package/templates/addons/design-best-practices/reference/motion-design.md +167 -0
  13. package/templates/addons/design-best-practices/reference/responsive-design.md +180 -0
  14. package/templates/addons/design-best-practices/reference/spatial-design.md +161 -0
  15. package/templates/addons/design-best-practices/reference/typography.md +136 -0
  16. package/templates/addons/design-best-practices/reference/ux-writing.md +190 -0
  17. package/templates/addons/design-best-practices/rules/design-quality.md +53 -0
  18. package/templates/addons/design-best-practices/skills/design-harden/SKILL.md +142 -0
  19. package/templates/addons/design-best-practices/skills/design-init/SKILL.md +95 -0
  20. package/templates/addons/design-best-practices/skills/design-refine/SKILL.md +124 -0
  21. package/templates/addons/design-best-practices/skills/design-review/SKILL.md +107 -0
  22. package/templates/addons/design-best-practices/skills/design-system/SKILL.md +125 -0
package/dist/index.js CHANGED
@@ -1469,7 +1469,7 @@ Valid addons: ${validAddons.join(", ")}`);
1469
1469
  p3.log.warn(`Template not found: ${templateName}`);
1470
1470
  continue;
1471
1471
  }
1472
- const resolution = conflictResolutions.get(ide) || "overwrite";
1472
+ const resolution = conflictResolutions.get(ide) || "replace";
1473
1473
  const files = getAllFilesRecursive(templateDir);
1474
1474
  const dynamicFiles = DYNAMIC_RULE_FILES[ide] || [];
1475
1475
  for (const file of files) {
@@ -1507,7 +1507,7 @@ Valid addons: ${validAddons.join(", ")}`);
1507
1507
  const rulePath = dynamicFiles[0];
1508
1508
  if (rulePath) {
1509
1509
  const destPath = join7(targetDir, rulePath);
1510
- const resolution2 = conflictResolutions.get(ide) || "overwrite";
1510
+ const resolution2 = conflictResolutions.get(ide) || "replace";
1511
1511
  if (fileExists(destPath) && resolution2 === "keep") {
1512
1512
  skippedFiles.push(rulePath);
1513
1513
  } else if (fileExists(destPath) && resolution2 === "merge") {
@@ -1717,8 +1717,8 @@ function buildProjectConfigFromPreset(presetConfig, analysis) {
1717
1717
  }
1718
1718
 
1719
1719
  // src/commands/update.ts
1720
- import { resolve as resolve3, join as join11, dirname as dirname5 } from "path";
1721
- import { existsSync as existsSync8, unlinkSync as unlinkSync2, lstatSync, readdirSync as readdirSync2, rmdirSync as rmdirSync2, chmodSync as chmodSync2 } from "fs";
1720
+ import { resolve as resolve4, join as join11, dirname as dirname6 } from "path";
1721
+ import { existsSync as existsSync9, unlinkSync as unlinkSync2, lstatSync, readdirSync as readdirSync2, rmdirSync as rmdirSync2, chmodSync as chmodSync2 } from "fs";
1722
1722
  import * as p4 from "@clack/prompts";
1723
1723
  import chalk5 from "chalk";
1724
1724
 
@@ -1747,15 +1747,20 @@ var REMOVED_FILES = {
1747
1747
  };
1748
1748
 
1749
1749
  // src/utils/addonConfig.ts
1750
- import { existsSync as existsSync6, readFileSync as readFileSync3, writeFileSync, mkdirSync, renameSync } from "fs";
1751
- import { join as join9, dirname as dirname3 } from "path";
1750
+ import { existsSync as existsSync7, readFileSync as readFileSync3, writeFileSync, mkdirSync, renameSync } from "fs";
1751
+ import { join as join9, dirname as dirname4 } from "path";
1752
1752
 
1753
1753
  // src/addons/registry.ts
1754
- import { readFileSync as readFileSync2 } from "fs";
1755
- import { join as join8 } from "path";
1754
+ import { existsSync as existsSync6, readFileSync as readFileSync2 } from "fs";
1755
+ import { join as join8, dirname as dirname3, resolve as resolve3 } from "path";
1756
+ import { fileURLToPath as fileURLToPath3 } from "url";
1757
+ function getAddonsDir() {
1758
+ const __dirname3 = dirname3(fileURLToPath3(import.meta.url));
1759
+ const templatesDir = existsSync6(resolve3(__dirname3, "../templates")) ? resolve3(__dirname3, "../templates") : resolve3(__dirname3, "../../templates");
1760
+ return join8(templatesDir, "addons");
1761
+ }
1756
1762
  function getAddonSourceDir(name) {
1757
- const addonsDir = new URL(".", import.meta.url).pathname;
1758
- return join8(addonsDir, name);
1763
+ return join8(getAddonsDir(), name);
1759
1764
  }
1760
1765
  function getAddonManifest(name) {
1761
1766
  const sourceDir = getAddonSourceDir(name);
@@ -1783,25 +1788,29 @@ function getLegacyConfigPath(targetDir) {
1783
1788
  function readAddonConfig(targetDir) {
1784
1789
  const configPath = getConfigPath(targetDir);
1785
1790
  const legacyPath = getLegacyConfigPath(targetDir);
1786
- if (!existsSync6(configPath) && existsSync6(legacyPath)) {
1787
- mkdirSync(dirname3(configPath), { recursive: true });
1791
+ if (!existsSync7(configPath) && existsSync7(legacyPath)) {
1792
+ mkdirSync(dirname4(configPath), { recursive: true });
1788
1793
  renameSync(legacyPath, configPath);
1789
1794
  }
1790
- if (!existsSync6(configPath)) {
1795
+ if (!existsSync7(configPath)) {
1796
+ return { agents: ["claude"], installed: {} };
1797
+ }
1798
+ try {
1799
+ const raw = JSON.parse(readFileSync3(configPath, "utf-8"));
1800
+ const data = raw.addons ?? raw;
1801
+ return {
1802
+ version: 1,
1803
+ mode: data.mode,
1804
+ agents: data.agents ?? ["claude"],
1805
+ installed: data.installed ?? {}
1806
+ };
1807
+ } catch {
1791
1808
  return { agents: ["claude"], installed: {} };
1792
1809
  }
1793
- const raw = JSON.parse(readFileSync3(configPath, "utf-8"));
1794
- const data = raw.addons ?? raw;
1795
- return {
1796
- version: 1,
1797
- mode: data.mode,
1798
- agents: data.agents ?? ["claude"],
1799
- installed: data.installed ?? {}
1800
- };
1801
1810
  }
1802
1811
  function writeAddonConfig(targetDir, config) {
1803
1812
  const configPath = getConfigPath(targetDir);
1804
- mkdirSync(dirname3(configPath), { recursive: true });
1813
+ mkdirSync(dirname4(configPath), { recursive: true });
1805
1814
  const payload = { version: 1, ...config };
1806
1815
  writeFileSync(configPath, JSON.stringify(payload, null, 2) + "\n");
1807
1816
  }
@@ -1830,7 +1839,7 @@ function detectOrphanedAddonFiles(targetDir) {
1830
1839
  for (const addon of getAvailableAddons()) {
1831
1840
  if (config.installed[addon.name]) continue;
1832
1841
  const skillDir = join9(targetDir, ".claude", "skills", addon.name);
1833
- if (existsSync6(skillDir)) {
1842
+ if (existsSync7(skillDir)) {
1834
1843
  orphaned.push(addon.name);
1835
1844
  }
1836
1845
  }
@@ -1851,7 +1860,7 @@ function registerAddonInConfig(targetDir, addonName) {
1851
1860
 
1852
1861
  // src/generators/addonFiles.ts
1853
1862
  import {
1854
- existsSync as existsSync7,
1863
+ existsSync as existsSync8,
1855
1864
  readFileSync as readFileSync4,
1856
1865
  writeFileSync as writeFileSync2,
1857
1866
  mkdirSync as mkdirSync2,
@@ -1860,7 +1869,7 @@ import {
1860
1869
  readdirSync,
1861
1870
  rmdirSync
1862
1871
  } from "fs";
1863
- import { join as join10, dirname as dirname4 } from "path";
1872
+ import { join as join10, dirname as dirname5 } from "path";
1864
1873
  import { createHash } from "crypto";
1865
1874
  var AGENT_PATHS = {
1866
1875
  claude: ".claude",
@@ -1917,7 +1926,7 @@ function checksum(content) {
1917
1926
  return createHash("sha256").update(content).digest("hex").slice(0, 16);
1918
1927
  }
1919
1928
  function ensureDir2(dir) {
1920
- if (!existsSync7(dir)) mkdirSync2(dir, { recursive: true });
1929
+ if (!existsSync8(dir)) mkdirSync2(dir, { recursive: true });
1921
1930
  }
1922
1931
  function readManifest2(addonSourceDir) {
1923
1932
  const manifestPath = join10(addonSourceDir, "manifest.json");
@@ -1928,27 +1937,27 @@ function buildFileMap(addonSourceDir) {
1928
1937
  const files = /* @__PURE__ */ new Map();
1929
1938
  for (const skill of manifest.files.skills ?? []) {
1930
1939
  const skillDir = join10(addonSourceDir, "skills", skill);
1931
- if (!existsSync7(skillDir)) continue;
1940
+ if (!existsSync8(skillDir)) continue;
1932
1941
  const skillFile = join10(skillDir, "SKILL.md");
1933
- if (existsSync7(skillFile)) {
1942
+ if (existsSync8(skillFile)) {
1934
1943
  files.set(`skills/${skill}/SKILL.md`, readFileSync4(skillFile, "utf-8"));
1935
1944
  }
1936
1945
  }
1937
1946
  for (const agent of manifest.files.agents ?? []) {
1938
1947
  const agentFile = join10(addonSourceDir, "agents", `${agent}.md`);
1939
- if (existsSync7(agentFile)) {
1948
+ if (existsSync8(agentFile)) {
1940
1949
  files.set(`agents/${agent}.md`, readFileSync4(agentFile, "utf-8"));
1941
1950
  }
1942
1951
  }
1943
1952
  for (const ref of manifest.files.reference ?? []) {
1944
1953
  const refPath = join10(addonSourceDir, "reference", ref);
1945
- if (existsSync7(refPath)) {
1954
+ if (existsSync8(refPath)) {
1946
1955
  files.set(`skills/design-harden/reference/${ref}`, readFileSync4(refPath, "utf-8"));
1947
1956
  }
1948
1957
  }
1949
1958
  for (const rule of manifest.files.rules ?? []) {
1950
1959
  const rulePath = join10(addonSourceDir, "rules", rule);
1951
- if (existsSync7(rulePath)) {
1960
+ if (existsSync8(rulePath)) {
1952
1961
  files.set(`rules/${rule}`, readFileSync4(rulePath, "utf-8"));
1953
1962
  }
1954
1963
  }
@@ -1964,11 +1973,11 @@ function generateAddonFiles(projectDir, addonSourceDir, agents) {
1964
1973
  const basePath = AGENT_PATHS[agent] ?? `.${agent}`;
1965
1974
  for (const [relPath, content] of fileMap) {
1966
1975
  const destPath = join10(projectDir, basePath, relPath);
1967
- if (existsSync7(destPath)) {
1976
+ if (existsSync8(destPath)) {
1968
1977
  result.skipped++;
1969
1978
  continue;
1970
1979
  }
1971
- ensureDir2(dirname4(destPath));
1980
+ ensureDir2(dirname5(destPath));
1972
1981
  writeFileSync2(destPath, content);
1973
1982
  result.written++;
1974
1983
  result.checksums[relPath] = checksum(content);
@@ -1977,31 +1986,31 @@ function generateAddonFiles(projectDir, addonSourceDir, agents) {
1977
1986
  }
1978
1987
  for (const skillName of manifest.files.skills ?? []) {
1979
1988
  const skillFile = join10(addonSourceDir, "skills", skillName, "SKILL.md");
1980
- if (!existsSync7(skillFile)) continue;
1989
+ if (!existsSync8(skillFile)) continue;
1981
1990
  const rawContent = readFileSync4(skillFile, "utf-8");
1982
1991
  const { relPath, content } = spec.skillAdapter(skillName, rawContent);
1983
1992
  const destPath = join10(projectDir, spec.baseDir, relPath);
1984
- if (existsSync7(destPath)) {
1993
+ if (existsSync8(destPath)) {
1985
1994
  const existing = readFileSync4(destPath, "utf-8");
1986
1995
  if (existing === content) {
1987
1996
  result.skipped++;
1988
- continue;
1997
+ } else {
1998
+ result.conflicts.push(relPath);
1989
1999
  }
1990
- result.skipped++;
1991
2000
  continue;
1992
2001
  }
1993
- ensureDir2(dirname4(destPath));
2002
+ ensureDir2(dirname5(destPath));
1994
2003
  writeFileSync2(destPath, content);
1995
2004
  result.written++;
1996
2005
  result.checksums[relPath] = checksum(content);
1997
2006
  }
1998
2007
  for (const agentName of manifest.files.agents ?? []) {
1999
2008
  const agentFile = join10(addonSourceDir, "agents", `${agentName}.md`);
2000
- if (!existsSync7(agentFile)) continue;
2009
+ if (!existsSync8(agentFile)) continue;
2001
2010
  const content = readFileSync4(agentFile, "utf-8");
2002
2011
  const destPath = join10(projectDir, spec.baseDir, "agents", `${agentName}.md`);
2003
- if (!existsSync7(destPath)) {
2004
- ensureDir2(dirname4(destPath));
2012
+ if (!existsSync8(destPath)) {
2013
+ ensureDir2(dirname5(destPath));
2005
2014
  writeFileSync2(destPath, content);
2006
2015
  result.written++;
2007
2016
  result.checksums[`agents/${agentName}.md`] = checksum(content);
@@ -2012,11 +2021,11 @@ function generateAddonFiles(projectDir, addonSourceDir, agents) {
2012
2021
  if (spec.rulesDir) {
2013
2022
  for (const rule of manifest.files.rules ?? []) {
2014
2023
  const ruleSrcPath = join10(addonSourceDir, "rules", rule);
2015
- if (!existsSync7(ruleSrcPath)) continue;
2024
+ if (!existsSync8(ruleSrcPath)) continue;
2016
2025
  const content = readFileSync4(ruleSrcPath, "utf-8");
2017
2026
  const destPath = join10(projectDir, spec.baseDir, spec.rulesDir, rule);
2018
- if (!existsSync7(destPath)) {
2019
- ensureDir2(dirname4(destPath));
2027
+ if (!existsSync8(destPath)) {
2028
+ ensureDir2(dirname5(destPath));
2020
2029
  writeFileSync2(destPath, content);
2021
2030
  result.written++;
2022
2031
  result.checksums[`rules/${rule}`] = checksum(content);
@@ -2027,12 +2036,12 @@ function generateAddonFiles(projectDir, addonSourceDir, agents) {
2027
2036
  }
2028
2037
  for (const ref of manifest.files.reference ?? []) {
2029
2038
  const refSrcPath = join10(addonSourceDir, "reference", ref);
2030
- if (!existsSync7(refSrcPath)) continue;
2039
+ if (!existsSync8(refSrcPath)) continue;
2031
2040
  const content = readFileSync4(refSrcPath, "utf-8");
2032
2041
  const relPath = `skills/design-harden/reference/${ref}`;
2033
2042
  const destPath = join10(projectDir, spec.baseDir, relPath);
2034
- if (!existsSync7(destPath)) {
2035
- ensureDir2(dirname4(destPath));
2043
+ if (!existsSync8(destPath)) {
2044
+ ensureDir2(dirname5(destPath));
2036
2045
  writeFileSync2(destPath, content);
2037
2046
  result.written++;
2038
2047
  result.checksums[relPath] = checksum(content);
@@ -2071,20 +2080,20 @@ function removeAddonFiles(projectDir, addonName, agents, addonSourceDir) {
2071
2080
  const basePath = AGENT_PATHS[agent] ?? `.${agent}`;
2072
2081
  for (const skill of knownSkills) {
2073
2082
  const skillDir = join10(projectDir, basePath, "skills", skill);
2074
- if (existsSync7(skillDir)) rmSync(skillDir, { recursive: true, force: true });
2083
+ if (existsSync8(skillDir)) rmSync(skillDir, { recursive: true, force: true });
2075
2084
  }
2076
2085
  for (const agentName of knownAgents) {
2077
2086
  const agentPath = join10(projectDir, basePath, "agents", `${agentName}.md`);
2078
- if (existsSync7(agentPath)) unlinkSync(agentPath);
2087
+ if (existsSync8(agentPath)) unlinkSync(agentPath);
2079
2088
  }
2080
2089
  continue;
2081
2090
  }
2082
2091
  for (const skillName of knownSkills) {
2083
2092
  const { relPath } = spec.skillAdapter(skillName, "");
2084
2093
  const destPath = join10(projectDir, spec.baseDir, relPath);
2085
- if (existsSync7(destPath)) unlinkSync(destPath);
2086
- const parentDir = dirname4(destPath);
2087
- if (existsSync7(parentDir)) {
2094
+ if (existsSync8(destPath)) unlinkSync(destPath);
2095
+ const parentDir = dirname5(destPath);
2096
+ if (existsSync8(parentDir)) {
2088
2097
  try {
2089
2098
  const entries = readdirSync(parentDir);
2090
2099
  if (entries.length === 0) rmdirSync(parentDir);
@@ -2094,20 +2103,20 @@ function removeAddonFiles(projectDir, addonName, agents, addonSourceDir) {
2094
2103
  }
2095
2104
  for (const agentName of knownAgents) {
2096
2105
  const agentPath = join10(projectDir, spec.baseDir, "agents", `${agentName}.md`);
2097
- if (existsSync7(agentPath)) unlinkSync(agentPath);
2106
+ if (existsSync8(agentPath)) unlinkSync(agentPath);
2098
2107
  }
2099
2108
  if (spec.rulesDir) {
2100
2109
  for (const rule of manifest.files.rules ?? []) {
2101
2110
  const rulePath = join10(projectDir, spec.baseDir, spec.rulesDir, rule);
2102
- if (existsSync7(rulePath)) unlinkSync(rulePath);
2111
+ if (existsSync8(rulePath)) unlinkSync(rulePath);
2103
2112
  }
2104
2113
  }
2105
2114
  for (const ref of manifest.files.reference ?? []) {
2106
2115
  const refPath = join10(projectDir, spec.baseDir, "skills", "design-harden", "reference", ref);
2107
- if (existsSync7(refPath)) unlinkSync(refPath);
2116
+ if (existsSync8(refPath)) unlinkSync(refPath);
2108
2117
  }
2109
2118
  const refDir = join10(projectDir, spec.baseDir, "skills", "design-harden", "reference");
2110
- if (existsSync7(refDir)) {
2119
+ if (existsSync8(refDir)) {
2111
2120
  try {
2112
2121
  const entries = readdirSync(refDir);
2113
2122
  if (entries.length === 0) rmdirSync(refDir);
@@ -2115,8 +2124,10 @@ function removeAddonFiles(projectDir, addonName, agents, addonSourceDir) {
2115
2124
  }
2116
2125
  }
2117
2126
  }
2118
- const noticePath = join10(projectDir, "NOTICE.md");
2119
- if (existsSync7(noticePath)) unlinkSync(noticePath);
2127
+ if (manifest.attribution) {
2128
+ const noticePath = join10(projectDir, "NOTICE.md");
2129
+ if (existsSync8(noticePath)) unlinkSync(noticePath);
2130
+ }
2120
2131
  }
2121
2132
  function syncAddonFiles(projectDir, addonSourceDir, agents) {
2122
2133
  const fileMap = buildFileMap(addonSourceDir);
@@ -2138,8 +2149,8 @@ function syncAddonFiles(projectDir, addonSourceDir, agents) {
2138
2149
  const basePath = AGENT_PATHS[agent] ?? `.${agent}`;
2139
2150
  for (const [relPath, newContent] of fileMap) {
2140
2151
  const destPath = join10(projectDir, basePath, relPath);
2141
- if (!existsSync7(destPath)) {
2142
- ensureDir2(dirname4(destPath));
2152
+ if (!existsSync8(destPath)) {
2153
+ ensureDir2(dirname5(destPath));
2143
2154
  writeFileSync2(destPath, newContent);
2144
2155
  result.written++;
2145
2156
  continue;
@@ -2162,12 +2173,12 @@ function syncAddonFiles(projectDir, addonSourceDir, agents) {
2162
2173
  }
2163
2174
  for (const skillName of manifest.files.skills ?? []) {
2164
2175
  const skillFile = join10(addonSourceDir, "skills", skillName, "SKILL.md");
2165
- if (!existsSync7(skillFile)) continue;
2176
+ if (!existsSync8(skillFile)) continue;
2166
2177
  const rawContent = readFileSync4(skillFile, "utf-8");
2167
2178
  const { relPath, content: newContent } = spec.skillAdapter(skillName, rawContent);
2168
2179
  const destPath = join10(projectDir, spec.baseDir, relPath);
2169
- if (!existsSync7(destPath)) {
2170
- ensureDir2(dirname4(destPath));
2180
+ if (!existsSync8(destPath)) {
2181
+ ensureDir2(dirname5(destPath));
2171
2182
  writeFileSync2(destPath, newContent);
2172
2183
  result.written++;
2173
2184
  continue;
@@ -2188,12 +2199,12 @@ function syncAddonFiles(projectDir, addonSourceDir, agents) {
2188
2199
  }
2189
2200
  for (const agentName of manifest.files.agents ?? []) {
2190
2201
  const agentFile = join10(addonSourceDir, "agents", `${agentName}.md`);
2191
- if (!existsSync7(agentFile)) continue;
2202
+ if (!existsSync8(agentFile)) continue;
2192
2203
  const newContent = readFileSync4(agentFile, "utf-8");
2193
2204
  const destPath = join10(projectDir, spec.baseDir, "agents", `${agentName}.md`);
2194
2205
  const relPath = `agents/${agentName}.md`;
2195
- if (!existsSync7(destPath)) {
2196
- ensureDir2(dirname4(destPath));
2206
+ if (!existsSync8(destPath)) {
2207
+ ensureDir2(dirname5(destPath));
2197
2208
  writeFileSync2(destPath, newContent);
2198
2209
  result.written++;
2199
2210
  continue;
@@ -2215,12 +2226,12 @@ function syncAddonFiles(projectDir, addonSourceDir, agents) {
2215
2226
  if (spec.rulesDir) {
2216
2227
  for (const rule of manifest.files.rules ?? []) {
2217
2228
  const ruleSrcPath = join10(addonSourceDir, "rules", rule);
2218
- if (!existsSync7(ruleSrcPath)) continue;
2229
+ if (!existsSync8(ruleSrcPath)) continue;
2219
2230
  const newContent = readFileSync4(ruleSrcPath, "utf-8");
2220
2231
  const destPath = join10(projectDir, spec.baseDir, spec.rulesDir, rule);
2221
2232
  const relPath = `rules/${rule}`;
2222
- if (!existsSync7(destPath)) {
2223
- ensureDir2(dirname4(destPath));
2233
+ if (!existsSync8(destPath)) {
2234
+ ensureDir2(dirname5(destPath));
2224
2235
  writeFileSync2(destPath, newContent);
2225
2236
  result.written++;
2226
2237
  continue;
@@ -2242,12 +2253,12 @@ function syncAddonFiles(projectDir, addonSourceDir, agents) {
2242
2253
  }
2243
2254
  for (const ref of manifest.files.reference ?? []) {
2244
2255
  const refSrcPath = join10(addonSourceDir, "reference", ref);
2245
- if (!existsSync7(refSrcPath)) continue;
2256
+ if (!existsSync8(refSrcPath)) continue;
2246
2257
  const newContent = readFileSync4(refSrcPath, "utf-8");
2247
2258
  const relPath = `skills/design-harden/reference/${ref}`;
2248
2259
  const destPath = join10(projectDir, spec.baseDir, relPath);
2249
- if (!existsSync7(destPath)) {
2250
- ensureDir2(dirname4(destPath));
2260
+ if (!existsSync8(destPath)) {
2261
+ ensureDir2(dirname5(destPath));
2251
2262
  writeFileSync2(destPath, newContent);
2252
2263
  result.written++;
2253
2264
  continue;
@@ -2271,19 +2282,23 @@ function syncAddonFiles(projectDir, addonSourceDir, agents) {
2271
2282
  }
2272
2283
  function detectModifiedAddonFiles(projectDir, addonName) {
2273
2284
  let installedChecksums = {};
2285
+ let agents = ["claude"];
2274
2286
  try {
2275
2287
  const config = readAddonConfig(projectDir);
2276
2288
  const installed = config.installed?.[addonName];
2277
2289
  if (!installed?.checksums) return [];
2278
2290
  installedChecksums = installed.checksums;
2291
+ agents = config.agents ?? ["claude"];
2279
2292
  } catch {
2280
2293
  return [];
2281
2294
  }
2282
2295
  const modified = [];
2283
- for (const agentDir of Object.values(AGENT_PATHS)) {
2296
+ for (const agent of agents) {
2297
+ const spec = RUNTIME_SPECS[agent];
2298
+ const baseDir = spec?.baseDir ?? AGENT_PATHS[agent] ?? `.${agent}`;
2284
2299
  for (const [relPath, originalHash] of Object.entries(installedChecksums)) {
2285
- const absPath = join10(projectDir, agentDir, relPath);
2286
- if (!existsSync7(absPath)) continue;
2300
+ const absPath = join10(projectDir, baseDir, relPath);
2301
+ if (!existsSync8(absPath)) continue;
2287
2302
  const current = checksum(readFileSync4(absPath, "utf-8"));
2288
2303
  if (current !== originalHash) {
2289
2304
  modified.push(relPath);
@@ -2298,7 +2313,7 @@ async function updateCommand(options) {
2298
2313
  if (!options.check && !options.dryRun) {
2299
2314
  ensureInteractive("update");
2300
2315
  }
2301
- const targetDir = resolve3(options.path || ".");
2316
+ const targetDir = resolve4(options.path || ".");
2302
2317
  p4.intro(introTitle("Update"));
2303
2318
  const manifest = readManifest(targetDir);
2304
2319
  if (!manifest) {
@@ -2371,7 +2386,7 @@ async function updateCommand(options) {
2371
2386
  const newFiles = [];
2372
2387
  for (const ide of manifest.selectedIDEs) {
2373
2388
  const templateDir = join11(TEMPLATES_DIR, IDE_TEMPLATE_MAP[ide]);
2374
- if (!existsSync8(templateDir)) continue;
2389
+ if (!existsSync9(templateDir)) continue;
2375
2390
  const files = getAllFilesRecursive(templateDir);
2376
2391
  for (const file of files) {
2377
2392
  const templatePath = join11(templateDir, file);
@@ -2394,7 +2409,7 @@ async function updateCommand(options) {
2394
2409
  let foundInAnyTemplate = false;
2395
2410
  for (const ide of manifest.selectedIDEs) {
2396
2411
  const templateDir = join11(TEMPLATES_DIR, IDE_TEMPLATE_MAP[ide]);
2397
- if (existsSync8(join11(templateDir, relativePath))) {
2412
+ if (existsSync9(join11(templateDir, relativePath))) {
2398
2413
  foundInAnyTemplate = true;
2399
2414
  break;
2400
2415
  }
@@ -2529,7 +2544,7 @@ async function updateCommand(options) {
2529
2544
  };
2530
2545
  for (const ide of manifest.selectedIDEs) {
2531
2546
  const templateDir = join11(TEMPLATES_DIR, IDE_TEMPLATE_MAP[ide]);
2532
- if (!existsSync8(templateDir)) continue;
2547
+ if (!existsSync9(templateDir)) continue;
2533
2548
  const isPluginMode = ide === "claude-code" && manifest.installMode === "plugin";
2534
2549
  const files = getAllFilesRecursive(templateDir);
2535
2550
  for (const file of files) {
@@ -2542,7 +2557,7 @@ async function updateCommand(options) {
2542
2557
  const templatePath = join11(templateDir, file);
2543
2558
  const destPath = join11(targetDir, file);
2544
2559
  const templateContent = readFile(templatePath);
2545
- ensureDir(dirname5(destPath));
2560
+ ensureDir(dirname6(destPath));
2546
2561
  writeFile(destPath, templateContent);
2547
2562
  updatedManifest.files[file] = createManifestEntry(templateContent);
2548
2563
  }
@@ -2568,7 +2583,7 @@ async function updateCommand(options) {
2568
2583
  );
2569
2584
  for (const script of ["checkpoint.sh", "stop-guard.sh"]) {
2570
2585
  const scriptPath = join11(targetDir, pluginResult.pluginPath, "scripts", script);
2571
- if (existsSync8(scriptPath)) {
2586
+ if (existsSync9(scriptPath)) {
2572
2587
  chmodSync2(scriptPath, 493);
2573
2588
  }
2574
2589
  }
@@ -2624,6 +2639,7 @@ async function updateCommand(options) {
2624
2639
  syncSpinner.start("Updating enabled addon files...");
2625
2640
  let totalUpdated = 0;
2626
2641
  for (const name of enabledAddons) {
2642
+ if (name === "orchestration") continue;
2627
2643
  const addonSourceDir = getAddonSourceDir(name);
2628
2644
  const result = syncAddonFiles(targetDir, addonSourceDir, addonConfig.agents);
2629
2645
  totalUpdated += (result.updated ?? 0) + result.written;
@@ -2765,7 +2781,7 @@ async function regenerateWithNewStack(targetDir, manifest, analysis, dryRun) {
2765
2781
  const rulePath = DYNAMIC_RULE_FILES[ide]?.[0];
2766
2782
  if (ruleContent && rulePath) {
2767
2783
  const destPath = join11(targetDir, rulePath);
2768
- ensureDir(dirname5(destPath));
2784
+ ensureDir(dirname6(destPath));
2769
2785
  writeFile(destPath, ruleContent);
2770
2786
  regeneratedFiles.push(rulePath);
2771
2787
  manifest.files[rulePath] = createManifestEntry(ruleContent);
@@ -2792,7 +2808,7 @@ async function regenerateWithNewStack(targetDir, manifest, analysis, dryRun) {
2792
2808
  );
2793
2809
  for (const script of ["checkpoint.sh", "stop-guard.sh"]) {
2794
2810
  const scriptPath = join11(targetDir, pluginResult.pluginPath, "scripts", script);
2795
- if (existsSync8(scriptPath)) {
2811
+ if (existsSync9(scriptPath)) {
2796
2812
  chmodSync2(scriptPath, 493);
2797
2813
  }
2798
2814
  }
@@ -2841,7 +2857,7 @@ async function migrateToPlugin(targetDir, manifest, analysis, dryRun) {
2841
2857
  );
2842
2858
  for (const script of ["checkpoint.sh", "stop-guard.sh"]) {
2843
2859
  const scriptPath = join11(targetDir, pluginResult.pluginPath, "scripts", script);
2844
- if (existsSync8(scriptPath)) {
2860
+ if (existsSync9(scriptPath)) {
2845
2861
  chmodSync2(scriptPath, 493);
2846
2862
  }
2847
2863
  }
@@ -2911,11 +2927,11 @@ function buildDefaultConfig(analysis) {
2911
2927
  };
2912
2928
  }
2913
2929
  function cleanEmptyDirs(dirPath) {
2914
- if (!existsSync8(dirPath)) return;
2930
+ if (!existsSync9(dirPath)) return;
2915
2931
  const entries = readdirSync2(dirPath);
2916
2932
  for (const entry of entries) {
2917
2933
  const fullPath = join11(dirPath, entry);
2918
- if (existsSync8(fullPath) && lstatSync(fullPath).isDirectory()) {
2934
+ if (existsSync9(fullPath) && lstatSync(fullPath).isDirectory()) {
2919
2935
  cleanEmptyDirs(fullPath);
2920
2936
  }
2921
2937
  }
@@ -2926,11 +2942,11 @@ function cleanEmptyDirs(dirPath) {
2926
2942
  }
2927
2943
 
2928
2944
  // src/commands/status.ts
2929
- import { resolve as resolve4, join as join12 } from "path";
2945
+ import { resolve as resolve5, join as join12 } from "path";
2930
2946
  import * as p5 from "@clack/prompts";
2931
2947
  import chalk6 from "chalk";
2932
2948
  async function statusCommand(options = {}) {
2933
- const targetDir = resolve4(options.path || ".");
2949
+ const targetDir = resolve5(options.path || ".");
2934
2950
  p5.intro(introTitle("Status"));
2935
2951
  const manifest = readManifest(targetDir);
2936
2952
  const latestPromise = getLatestVersion("devtronic");
@@ -3012,12 +3028,12 @@ async function statusCommand(options = {}) {
3012
3028
  }
3013
3029
 
3014
3030
  // src/commands/diff.ts
3015
- import { resolve as resolve5, join as join13 } from "path";
3016
- import { existsSync as existsSync9 } from "fs";
3031
+ import { resolve as resolve6, join as join13 } from "path";
3032
+ import { existsSync as existsSync10 } from "fs";
3017
3033
  import * as p6 from "@clack/prompts";
3018
3034
  import chalk7 from "chalk";
3019
3035
  async function diffCommand(options = {}) {
3020
- const targetDir = resolve5(options.path || ".");
3036
+ const targetDir = resolve6(options.path || ".");
3021
3037
  p6.intro(introTitle("Diff"));
3022
3038
  const manifest = readManifest(targetDir);
3023
3039
  if (!manifest) {
@@ -3029,7 +3045,7 @@ async function diffCommand(options = {}) {
3029
3045
  const diffs = [];
3030
3046
  for (const ide of manifest.selectedIDEs) {
3031
3047
  const templateDir = join13(TEMPLATES_DIR, IDE_TEMPLATE_MAP[ide]);
3032
- if (!existsSync9(templateDir)) continue;
3048
+ if (!existsSync10(templateDir)) continue;
3033
3049
  const templateFiles = getAllFilesRecursive(templateDir);
3034
3050
  for (const file of templateFiles) {
3035
3051
  const templatePath = join13(templateDir, file);
@@ -3086,8 +3102,8 @@ async function diffCommand(options = {}) {
3086
3102
  }
3087
3103
 
3088
3104
  // src/commands/add.ts
3089
- import { existsSync as existsSync10 } from "fs";
3090
- import { resolve as resolve6, join as join14, dirname as dirname6 } from "path";
3105
+ import { existsSync as existsSync11 } from "fs";
3106
+ import { resolve as resolve7, join as join14, dirname as dirname7 } from "path";
3091
3107
  import * as p7 from "@clack/prompts";
3092
3108
  import chalk8 from "chalk";
3093
3109
  var ALL_IDES = [
@@ -3101,7 +3117,7 @@ async function addCommand(ide, options) {
3101
3117
  if (!options.yes) {
3102
3118
  ensureInteractive("add");
3103
3119
  }
3104
- const targetDir = resolve6(options.path || ".");
3120
+ const targetDir = resolve7(options.path || ".");
3105
3121
  p7.intro(introTitle("Add IDE"));
3106
3122
  const manifest = readManifest(targetDir);
3107
3123
  if (!manifest) {
@@ -3182,7 +3198,7 @@ Valid options: ${ALL_IDES.map((i) => i.value).join(", ")}`
3182
3198
  const generatedRules = generateArchitectureRules(manifest.projectConfig);
3183
3199
  const templateName = IDE_TEMPLATE_MAP[selectedIDE];
3184
3200
  const templateDir = join14(TEMPLATES_DIR, templateName);
3185
- if (!existsSync10(templateDir)) {
3201
+ if (!existsSync11(templateDir)) {
3186
3202
  spinner8.stop("Error");
3187
3203
  p7.cancel(`Template not found: ${templateName}`);
3188
3204
  process.exit(1);
@@ -3211,7 +3227,7 @@ Valid options: ${ALL_IDES.map((i) => i.value).join(", ")}`
3211
3227
  continue;
3212
3228
  }
3213
3229
  }
3214
- ensureDir(dirname6(destPath));
3230
+ ensureDir(dirname7(destPath));
3215
3231
  writeFile(destPath, sourceContent);
3216
3232
  appliedFiles.push(file);
3217
3233
  manifest.files[file] = createManifestEntry(sourceContent);
@@ -3231,7 +3247,7 @@ Valid options: ${ALL_IDES.map((i) => i.value).join(", ")}`
3231
3247
  mergedFiles.push(rulePath);
3232
3248
  manifest.files[rulePath] = createManifestEntry(mergedContent);
3233
3249
  } else {
3234
- ensureDir(dirname6(destPath));
3250
+ ensureDir(dirname7(destPath));
3235
3251
  writeFile(destPath, ruleContent);
3236
3252
  generatedFiles.push(`${rulePath} (personalized)`);
3237
3253
  manifest.files[rulePath] = createManifestEntry(ruleContent);
@@ -3272,17 +3288,17 @@ Valid options: ${ALL_IDES.map((i) => i.value).join(", ")}`
3272
3288
  }
3273
3289
 
3274
3290
  // src/commands/regenerate.ts
3275
- import { existsSync as existsSync11 } from "fs";
3276
- import { resolve as resolve7, join as join15, dirname as dirname7 } from "path";
3277
- import { fileURLToPath as fileURLToPath3 } from "url";
3291
+ import { existsSync as existsSync12 } from "fs";
3292
+ import { resolve as resolve8, join as join15, dirname as dirname8 } from "path";
3293
+ import { fileURLToPath as fileURLToPath4 } from "url";
3278
3294
  import * as p8 from "@clack/prompts";
3279
3295
  import chalk9 from "chalk";
3280
- var __filename = fileURLToPath3(import.meta.url);
3281
- var __regen_dirname = dirname7(__filename);
3282
- var TEMPLATES_DIR2 = existsSync11(resolve7(__regen_dirname, "../templates")) ? resolve7(__regen_dirname, "../templates") : resolve7(__regen_dirname, "../../templates");
3296
+ var __filename = fileURLToPath4(import.meta.url);
3297
+ var __regen_dirname = dirname8(__filename);
3298
+ var TEMPLATES_DIR2 = existsSync12(resolve8(__regen_dirname, "../templates")) ? resolve8(__regen_dirname, "../templates") : resolve8(__regen_dirname, "../../templates");
3283
3299
  async function regenerateCommand(target, options) {
3284
3300
  ensureInteractive("regenerate");
3285
- const targetDir = resolve7(options.path || ".");
3301
+ const targetDir = resolve8(options.path || ".");
3286
3302
  p8.intro(introTitle("Regenerate"));
3287
3303
  const manifest = readManifest(targetDir);
3288
3304
  if (!manifest) {
@@ -3422,7 +3438,7 @@ Valid options:
3422
3438
  const rulePath = DYNAMIC_RULE_FILES[ide]?.[0];
3423
3439
  if (ruleContent && rulePath) {
3424
3440
  const destPath = join15(targetDir, rulePath);
3425
- ensureDir(dirname7(destPath));
3441
+ ensureDir(dirname8(destPath));
3426
3442
  writeFile(destPath, ruleContent);
3427
3443
  regeneratedFiles.push(rulePath);
3428
3444
  manifest.files[rulePath] = createManifestEntry(ruleContent);
@@ -3471,12 +3487,12 @@ Valid options:
3471
3487
  }
3472
3488
 
3473
3489
  // src/commands/info.ts
3474
- import { resolve as resolve8, join as join16 } from "path";
3475
- import { existsSync as existsSync12, readdirSync as readdirSync3 } from "fs";
3490
+ import { resolve as resolve9, join as join16 } from "path";
3491
+ import { existsSync as existsSync13, readdirSync as readdirSync3 } from "fs";
3476
3492
  import * as p9 from "@clack/prompts";
3477
3493
  import chalk10 from "chalk";
3478
3494
  async function infoCommand() {
3479
- const targetDir = resolve8(".");
3495
+ const targetDir = resolve9(".");
3480
3496
  p9.intro(introTitle("Info"));
3481
3497
  const manifest = readManifest(targetDir);
3482
3498
  const currentVersion = getCliVersion();
@@ -3486,15 +3502,15 @@ async function infoCommand() {
3486
3502
  let agentCount = 0;
3487
3503
  if (manifest) {
3488
3504
  const pluginDir = manifest.pluginPath ? join16(targetDir, manifest.pluginPath) : null;
3489
- if (pluginDir && existsSync12(pluginDir)) {
3505
+ if (pluginDir && existsSync13(pluginDir)) {
3490
3506
  const skillsDir = join16(pluginDir, "skills");
3491
3507
  const agentsDir = join16(pluginDir, "agents");
3492
- if (existsSync12(skillsDir)) {
3508
+ if (existsSync13(skillsDir)) {
3493
3509
  skillCount = readdirSync3(skillsDir, { withFileTypes: true }).filter(
3494
3510
  (e) => e.isDirectory() || e.isFile() && e.name.endsWith(".md")
3495
3511
  ).length;
3496
3512
  }
3497
- if (existsSync12(agentsDir)) {
3513
+ if (existsSync13(agentsDir)) {
3498
3514
  agentCount = readdirSync3(agentsDir, { withFileTypes: true }).filter(
3499
3515
  (e) => e.isFile() && e.name.endsWith(".md")
3500
3516
  ).length;
@@ -3502,7 +3518,7 @@ async function infoCommand() {
3502
3518
  }
3503
3519
  if (skillCount === 0) {
3504
3520
  const claudeSkills = join16(targetDir, ".claude", "skills");
3505
- if (existsSync12(claudeSkills)) {
3521
+ if (existsSync13(claudeSkills)) {
3506
3522
  skillCount = readdirSync3(claudeSkills, { withFileTypes: true }).filter(
3507
3523
  (e) => e.isDirectory() || e.isFile() && e.name.endsWith(".md")
3508
3524
  ).length;
@@ -3510,7 +3526,7 @@ async function infoCommand() {
3510
3526
  }
3511
3527
  if (agentCount === 0) {
3512
3528
  const claudeAgents = join16(targetDir, ".claude", "agents");
3513
- if (existsSync12(claudeAgents)) {
3529
+ if (existsSync13(claudeAgents)) {
3514
3530
  agentCount = readdirSync3(claudeAgents, { withFileTypes: true }).filter(
3515
3531
  (e) => e.isFile() && e.name.endsWith(".md")
3516
3532
  ).length;
@@ -3554,12 +3570,12 @@ async function infoCommand() {
3554
3570
  }
3555
3571
 
3556
3572
  // src/commands/list.ts
3557
- import { resolve as resolve9, join as join17 } from "path";
3558
- import { existsSync as existsSync13, readdirSync as readdirSync4, readFileSync as readFileSync5 } from "fs";
3573
+ import { resolve as resolve10, join as join17 } from "path";
3574
+ import { existsSync as existsSync14, readdirSync as readdirSync4, readFileSync as readFileSync5 } from "fs";
3559
3575
  import * as p10 from "@clack/prompts";
3560
3576
  import chalk11 from "chalk";
3561
3577
  async function listCommand(filter, options) {
3562
- const targetDir = resolve9(options.path || ".");
3578
+ const targetDir = resolve10(options.path || ".");
3563
3579
  p10.intro(introTitle("List"));
3564
3580
  const manifest = readManifest(targetDir);
3565
3581
  const showSkills = !filter || filter === "skills";
@@ -3573,29 +3589,29 @@ Valid options: skills, agents`);
3573
3589
  const skills = [];
3574
3590
  const agents = [];
3575
3591
  const pluginDir = manifest?.pluginPath ? join17(targetDir, manifest.pluginPath) : null;
3576
- if (pluginDir && existsSync13(pluginDir)) {
3592
+ if (pluginDir && existsSync14(pluginDir)) {
3577
3593
  if (showSkills) {
3578
3594
  const skillsDir = join17(pluginDir, "skills");
3579
- if (existsSync13(skillsDir)) {
3595
+ if (existsSync14(skillsDir)) {
3580
3596
  skills.push(...discoverSkills(skillsDir));
3581
3597
  }
3582
3598
  }
3583
3599
  if (showAgents) {
3584
3600
  const agentsDir = join17(pluginDir, "agents");
3585
- if (existsSync13(agentsDir)) {
3601
+ if (existsSync14(agentsDir)) {
3586
3602
  agents.push(...discoverAgents(agentsDir));
3587
3603
  }
3588
3604
  }
3589
3605
  }
3590
3606
  if (showSkills && skills.length === 0) {
3591
3607
  const claudeSkills = join17(targetDir, ".claude", "skills");
3592
- if (existsSync13(claudeSkills)) {
3608
+ if (existsSync14(claudeSkills)) {
3593
3609
  skills.push(...discoverSkills(claudeSkills));
3594
3610
  }
3595
3611
  }
3596
3612
  if (showAgents && agents.length === 0) {
3597
3613
  const claudeAgents = join17(targetDir, ".claude", "agents");
3598
- if (existsSync13(claudeAgents)) {
3614
+ if (existsSync14(claudeAgents)) {
3599
3615
  agents.push(...discoverAgents(claudeAgents));
3600
3616
  }
3601
3617
  }
@@ -3623,7 +3639,7 @@ function discoverSkills(skillsDir) {
3623
3639
  for (const entry of entries) {
3624
3640
  if (entry.isDirectory()) {
3625
3641
  const skillMd = join17(skillsDir, entry.name, "SKILL.md");
3626
- const description = existsSync13(skillMd) ? extractDescription(skillMd) : "";
3642
+ const description = existsSync14(skillMd) ? extractDescription(skillMd) : "";
3627
3643
  items.push({ name: entry.name, description });
3628
3644
  } else if (entry.isFile() && entry.name.endsWith(".md")) {
3629
3645
  const name = entry.name.replace(/\.md$/, "");
@@ -3668,7 +3684,7 @@ function extractDescription(filePath) {
3668
3684
  }
3669
3685
 
3670
3686
  // src/commands/config.ts
3671
- import { resolve as resolve10 } from "path";
3687
+ import { resolve as resolve11 } from "path";
3672
3688
  import * as p11 from "@clack/prompts";
3673
3689
  import chalk12 from "chalk";
3674
3690
  var ARRAY_KEYS = [
@@ -3688,7 +3704,7 @@ var VALID_KEYS = [
3688
3704
  ...ARRAY_KEYS
3689
3705
  ];
3690
3706
  async function configCommand(options) {
3691
- const targetDir = resolve10(options.path || ".");
3707
+ const targetDir = resolve11(options.path || ".");
3692
3708
  p11.intro(introTitle("Config"));
3693
3709
  const manifest = readManifest(targetDir);
3694
3710
  if (!manifest) {
@@ -3720,7 +3736,7 @@ async function configCommand(options) {
3720
3736
  p11.outro("");
3721
3737
  }
3722
3738
  async function configSetCommand(key, value, options) {
3723
- const targetDir = resolve10(options.path || ".");
3739
+ const targetDir = resolve11(options.path || ".");
3724
3740
  p11.intro(introTitle("Config Set"));
3725
3741
  const manifest = readManifest(targetDir);
3726
3742
  if (!manifest || !manifest.projectConfig) {
@@ -3775,7 +3791,7 @@ Valid addons: ${validAddons.join(", ")}`
3775
3791
  p11.outro(chalk12.green("Configuration updated"));
3776
3792
  }
3777
3793
  async function configResetCommand(options) {
3778
- const targetDir = resolve10(options.path || ".");
3794
+ const targetDir = resolve11(options.path || ".");
3779
3795
  p11.intro(introTitle("Config Reset"));
3780
3796
  const manifest = readManifest(targetDir);
3781
3797
  if (!manifest) {
@@ -3826,13 +3842,13 @@ async function configResetCommand(options) {
3826
3842
  }
3827
3843
 
3828
3844
  // src/commands/doctor.ts
3829
- import { resolve as resolve11, join as join18 } from "path";
3830
- import { existsSync as existsSync14, readdirSync as readdirSync5, statSync, chmodSync as chmodSync3, mkdirSync as mkdirSync3 } from "fs";
3845
+ import { resolve as resolve12, join as join18 } from "path";
3846
+ import { existsSync as existsSync15, readdirSync as readdirSync5, statSync, chmodSync as chmodSync3, mkdirSync as mkdirSync3 } from "fs";
3831
3847
  import { execSync } from "child_process";
3832
3848
  import * as p12 from "@clack/prompts";
3833
3849
  import chalk13 from "chalk";
3834
3850
  async function doctorCommand(options) {
3835
- const targetDir = resolve11(options.path || ".");
3851
+ const targetDir = resolve12(options.path || ".");
3836
3852
  p12.intro(introTitle("Doctor"));
3837
3853
  const manifest = readManifest(targetDir);
3838
3854
  if (!manifest) {
@@ -3950,9 +3966,9 @@ function checkManifestFiles(targetDir, manifest) {
3950
3966
  function checkScriptPermissions(targetDir, manifest) {
3951
3967
  const pluginDir = manifest.pluginPath ? join18(targetDir, manifest.pluginPath) : null;
3952
3968
  const shFiles = [];
3953
- if (pluginDir && existsSync14(pluginDir)) {
3969
+ if (pluginDir && existsSync15(pluginDir)) {
3954
3970
  const scriptsDir = join18(pluginDir, "scripts");
3955
- if (existsSync14(scriptsDir)) {
3971
+ if (existsSync15(scriptsDir)) {
3956
3972
  const entries = readdirSync5(scriptsDir);
3957
3973
  for (const entry of entries) {
3958
3974
  if (entry.endsWith(".sh")) {
@@ -4020,7 +4036,7 @@ function checkPluginRegistered(targetDir) {
4020
4036
  }
4021
4037
  function checkHookScripts(targetDir, manifest) {
4022
4038
  const pluginDir = manifest.pluginPath ? join18(targetDir, manifest.pluginPath) : null;
4023
- if (!pluginDir || !existsSync14(pluginDir)) {
4039
+ if (!pluginDir || !existsSync15(pluginDir)) {
4024
4040
  return {
4025
4041
  name: "hooks",
4026
4042
  status: "pass",
@@ -4028,7 +4044,7 @@ function checkHookScripts(targetDir, manifest) {
4028
4044
  };
4029
4045
  }
4030
4046
  const hooksDir = join18(pluginDir, "hooks");
4031
- if (!existsSync14(hooksDir)) {
4047
+ if (!existsSync15(hooksDir)) {
4032
4048
  return {
4033
4049
  name: "hooks",
4034
4050
  status: "pass",
@@ -4055,7 +4071,7 @@ function checkHookScripts(targetDir, manifest) {
4055
4071
  ""
4056
4072
  );
4057
4073
  const scriptPath = join18(pluginDir, resolved);
4058
- if (existsSync14(scriptPath)) {
4074
+ if (existsSync15(scriptPath)) {
4059
4075
  valid++;
4060
4076
  }
4061
4077
  } else {
@@ -4106,7 +4122,7 @@ function checkQualityScripts(targetDir) {
4106
4122
  }
4107
4123
  function checkThoughtsDir(targetDir) {
4108
4124
  const thoughtsDir = join18(targetDir, "thoughts");
4109
- if (existsSync14(thoughtsDir)) {
4125
+ if (existsSync15(thoughtsDir)) {
4110
4126
  return {
4111
4127
  name: "thoughts",
4112
4128
  status: "pass",
@@ -4138,7 +4154,7 @@ function checkThoughtsDir(targetDir) {
4138
4154
  function checkEslint(targetDir) {
4139
4155
  try {
4140
4156
  const eslintLocal = join18(targetDir, "node_modules", ".bin", "eslint");
4141
- if (existsSync14(eslintLocal)) {
4157
+ if (existsSync15(eslintLocal)) {
4142
4158
  return { name: "eslint", status: "pass", message: "eslint is available" };
4143
4159
  }
4144
4160
  execSync("which eslint", { stdio: "pipe" });
@@ -4153,14 +4169,14 @@ function checkEslint(targetDir) {
4153
4169
  }
4154
4170
 
4155
4171
  // src/commands/uninstall.ts
4156
- import { existsSync as existsSync15, rmSync as rmSync2, readdirSync as readdirSync6 } from "fs";
4157
- import { resolve as resolve12, join as join19, dirname as dirname8 } from "path";
4172
+ import { existsSync as existsSync16, rmSync as rmSync2, readdirSync as readdirSync6 } from "fs";
4173
+ import { resolve as resolve13, join as join19, dirname as dirname9 } from "path";
4158
4174
  import * as p13 from "@clack/prompts";
4159
4175
  import chalk14 from "chalk";
4160
4176
  var DEVTRONIC_FILES = ["CLAUDE.md", "AGENTS.md"];
4161
4177
  async function uninstallCommand(options) {
4162
4178
  ensureInteractive("uninstall");
4163
- const targetDir = resolve12(options.path || ".");
4179
+ const targetDir = resolve13(options.path || ".");
4164
4180
  p13.intro(introTitle("Uninstall"));
4165
4181
  const manifest = readManifest(targetDir);
4166
4182
  if (!manifest) {
@@ -4174,8 +4190,8 @@ async function uninstallCommand(options) {
4174
4190
  const managedFiles = Object.keys(manifest.files);
4175
4191
  const existingFiles = managedFiles.filter((f) => fileExists(join19(targetDir, f)));
4176
4192
  const missingFiles = managedFiles.filter((f) => !fileExists(join19(targetDir, f)));
4177
- const hasPlugin = manifest.installMode === "plugin" && existsSync15(join19(targetDir, PLUGIN_DIR, PLUGIN_NAME));
4178
- const hasThoughts = existsSync15(join19(targetDir, "thoughts"));
4193
+ const hasPlugin = manifest.installMode === "plugin" && existsSync16(join19(targetDir, PLUGIN_DIR, PLUGIN_NAME));
4194
+ const hasThoughts = existsSync16(join19(targetDir, "thoughts"));
4179
4195
  const hasClaudeMd = fileExists(join19(targetDir, "CLAUDE.md"));
4180
4196
  const hasAgentsMd = fileExists(join19(targetDir, "AGENTS.md"));
4181
4197
  p13.log.info(`Installation found: v${manifest.version} (${manifest.implantedAt})`);
@@ -4266,12 +4282,12 @@ async function uninstallCommand(options) {
4266
4282
  rmSync2(join19(targetDir, PLUGIN_DIR, PLUGIN_NAME), { recursive: true, force: true });
4267
4283
  removed.push(`${PLUGIN_DIR}/${PLUGIN_NAME}/`);
4268
4284
  const marketplaceDescDir = join19(targetDir, PLUGIN_DIR, ".claude-plugin");
4269
- if (existsSync15(marketplaceDescDir)) {
4285
+ if (existsSync16(marketplaceDescDir)) {
4270
4286
  rmSync2(marketplaceDescDir, { recursive: true, force: true });
4271
4287
  removed.push(`${PLUGIN_DIR}/.claude-plugin/`);
4272
4288
  }
4273
4289
  const pluginsDir = join19(targetDir, PLUGIN_DIR);
4274
- if (existsSync15(pluginsDir)) {
4290
+ if (existsSync16(pluginsDir)) {
4275
4291
  const remaining = readdirSafe(pluginsDir);
4276
4292
  if (remaining.length === 0) {
4277
4293
  rmSync2(pluginsDir, { recursive: true, force: true });
@@ -4288,10 +4304,10 @@ async function uninstallCommand(options) {
4288
4304
  if (file.startsWith(PLUGIN_DIR + "/")) continue;
4289
4305
  try {
4290
4306
  const filePath = join19(targetDir, file);
4291
- if (existsSync15(filePath)) {
4307
+ if (existsSync16(filePath)) {
4292
4308
  rmSync2(filePath, { force: true });
4293
4309
  removed.push(file);
4294
- cleanEmptyParents(targetDir, dirname8(file));
4310
+ cleanEmptyParents(targetDir, dirname9(file));
4295
4311
  }
4296
4312
  } catch (err) {
4297
4313
  errors.push(`Failed to remove ${file}: ${err instanceof Error ? err.message : String(err)}`);
@@ -4335,7 +4351,7 @@ async function uninstallCommand(options) {
4335
4351
  }
4336
4352
  try {
4337
4353
  const manifestDir = join19(targetDir, MANIFEST_DIR);
4338
- if (existsSync15(manifestDir)) {
4354
+ if (existsSync16(manifestDir)) {
4339
4355
  rmSync2(manifestDir, { recursive: true, force: true });
4340
4356
  removed.push(`${MANIFEST_DIR}/`);
4341
4357
  }
@@ -4382,12 +4398,12 @@ async function uninstallCommand(options) {
4382
4398
  function cleanEmptyParents(targetDir, relDir) {
4383
4399
  if (!relDir || relDir === ".") return;
4384
4400
  const absDir = join19(targetDir, relDir);
4385
- if (!existsSync15(absDir)) return;
4401
+ if (!existsSync16(absDir)) return;
4386
4402
  const entries = readdirSafe(absDir);
4387
4403
  if (entries.length === 0) {
4388
4404
  try {
4389
4405
  rmSync2(absDir, { recursive: true, force: true });
4390
- cleanEmptyParents(targetDir, dirname8(relDir));
4406
+ cleanEmptyParents(targetDir, dirname9(relDir));
4391
4407
  } catch {
4392
4408
  }
4393
4409
  }
@@ -4401,15 +4417,15 @@ function readdirSafe(dir) {
4401
4417
  }
4402
4418
 
4403
4419
  // src/commands/addon.ts
4404
- import { resolve as resolve13, join as join20, dirname as dirname9 } from "path";
4405
- import { existsSync as existsSync16, unlinkSync as unlinkSync3, rmSync as rmSync3, readFileSync as readFileSync6 } from "fs";
4420
+ import { resolve as resolve14, join as join20, dirname as dirname10 } from "path";
4421
+ import { existsSync as existsSync17, unlinkSync as unlinkSync3, rmSync as rmSync3 } from "fs";
4406
4422
  import * as p14 from "@clack/prompts";
4407
4423
  import chalk15 from "chalk";
4408
4424
  function isFileBasedAddon(addonName) {
4409
4425
  return addonName !== "orchestration";
4410
4426
  }
4411
4427
  async function addonCommand(action, addonName, options) {
4412
- const targetDir = resolve13(options.path || ".");
4428
+ const targetDir = resolve14(options.path || ".");
4413
4429
  p14.intro(introTitle(`Addon ${action}`));
4414
4430
  const validAddons = Object.keys(ADDONS);
4415
4431
  if (!validAddons.includes(addonName)) {
@@ -4420,8 +4436,8 @@ Valid addons: ${validAddons.join(", ")}`);
4420
4436
  }
4421
4437
  const typedName = addonName;
4422
4438
  const canonicalAction = action === "enable" ? "add" : action === "disable" ? "remove" : action;
4423
- if (action === "add" || action === "remove") {
4424
- const canonical = action === "add" ? "enable" : "disable";
4439
+ if (action === "enable" || action === "disable") {
4440
+ const canonical = action === "enable" ? "add" : "remove";
4425
4441
  p14.log.warn(
4426
4442
  `"addon ${action}" is deprecated. Use "addon ${canonical}" instead.`
4427
4443
  );
@@ -4483,7 +4499,7 @@ async function addAddon(targetDir, manifest, addonName, currentAddons) {
4483
4499
  const addedFiles = [];
4484
4500
  for (const skillDir of addon.skills) {
4485
4501
  const sourceDir = join20(skillsSourceDir, skillDir);
4486
- if (!existsSync16(sourceDir)) {
4502
+ if (!existsSync17(sourceDir)) {
4487
4503
  spinner8.stop(`Template not found for skill: ${skillDir}`);
4488
4504
  p14.log.warn(`Skipping ${skillDir} \u2014 template not found.`);
4489
4505
  continue;
@@ -4493,7 +4509,7 @@ async function addAddon(targetDir, manifest, addonName, currentAddons) {
4493
4509
  const content = readFile(join20(sourceDir, file));
4494
4510
  const destRelPath = join20(pluginRoot, "skills", skillDir, file);
4495
4511
  const destAbsPath = join20(targetDir, destRelPath);
4496
- ensureDir(dirname9(destAbsPath));
4512
+ ensureDir(dirname10(destAbsPath));
4497
4513
  writeFile(destAbsPath, content);
4498
4514
  manifest.files[destRelPath] = createManifestEntry(content);
4499
4515
  addedFiles.push(destRelPath);
@@ -4542,7 +4558,7 @@ async function removeAddon(targetDir, manifest, addonName, currentAddons) {
4542
4558
  for (const [filePath, fileInfo] of Object.entries(manifest.files)) {
4543
4559
  if (!filePath.startsWith(skillRelBase)) continue;
4544
4560
  const absPath = join20(targetDir, filePath);
4545
- if (!existsSync16(absPath)) continue;
4561
+ if (!existsSync17(absPath)) continue;
4546
4562
  const current = calculateChecksum(readFile(absPath));
4547
4563
  if (current !== fileInfo.originalChecksum) {
4548
4564
  modifiedFiles.push(filePath);
@@ -4570,11 +4586,11 @@ async function removeAddon(targetDir, manifest, addonName, currentAddons) {
4570
4586
  for (const filePath of Object.keys(manifest.files)) {
4571
4587
  if (filePath.startsWith(skillRelBase)) {
4572
4588
  const absPath = join20(targetDir, filePath);
4573
- if (existsSync16(absPath)) unlinkSync3(absPath);
4589
+ if (existsSync17(absPath)) unlinkSync3(absPath);
4574
4590
  delete manifest.files[filePath];
4575
4591
  }
4576
4592
  }
4577
- if (existsSync16(skillAbsDir)) {
4593
+ if (existsSync17(skillAbsDir)) {
4578
4594
  try {
4579
4595
  rmSync3(skillAbsDir, { recursive: true });
4580
4596
  } catch {
@@ -4619,16 +4635,14 @@ async function addFileBasedAddon(targetDir, addonName, _options) {
4619
4635
  spinner8.start(`Adding ${addon.label}...`);
4620
4636
  const addonSourceDir = getAddonSourceDir(addonName);
4621
4637
  const result = generateAddonFiles(targetDir, addonSourceDir, config.agents);
4622
- const addonManifest = JSON.parse(
4623
- readFileSync6(join20(addonSourceDir, "manifest.json"), "utf-8")
4624
- );
4638
+ const addonMeta = getAddonManifest(addonName);
4625
4639
  const fileList = [
4626
- ...(addonManifest.files.skills ?? []).map((s) => `skills/${s}`),
4627
- ...(addonManifest.files.agents ?? []).map((a) => `agents/${a}.md`),
4628
- ...(addonManifest.files.rules ?? []).map((r) => `rules/${r}`)
4640
+ ...(addonMeta.files.skills ?? []).map((s) => `skills/${s}`),
4641
+ ...(addonMeta.files.agents ?? []).map((a) => `agents/${a}.md`),
4642
+ ...(addonMeta.files.rules ?? []).map((r) => `rules/${r}`)
4629
4643
  ];
4630
4644
  writeAddonToConfig(targetDir, addonName, {
4631
- version: addonManifest.version,
4645
+ version: addonMeta.version,
4632
4646
  files: fileList,
4633
4647
  checksums: result.checksums ?? {}
4634
4648
  });
@@ -4685,7 +4699,7 @@ function getAddonListInfo(targetDir) {
4685
4699
  }));
4686
4700
  }
4687
4701
  async function addonListCommand(options) {
4688
- const targetDir = resolve13(options.path || ".");
4702
+ const targetDir = resolve14(options.path || ".");
4689
4703
  p14.intro(introTitle("Addon List"));
4690
4704
  const items = getAddonListInfo(targetDir);
4691
4705
  const lines = items.map((item) => {
@@ -4698,10 +4712,27 @@ async function addonListCommand(options) {
4698
4712
  p14.outro(`Use ${chalk15.cyan("devtronic addon add <name>")} to install.`);
4699
4713
  }
4700
4714
  async function addonSyncCommand(options) {
4701
- const targetDir = resolve13(options.path || ".");
4715
+ const targetDir = resolve14(options.path || ".");
4702
4716
  p14.intro(introTitle("Addon Sync"));
4703
4717
  const config = readAddonConfig(targetDir);
4704
- const installedNames = Object.keys(config.installed);
4718
+ const manifest = readManifest(targetDir);
4719
+ const manifestAddons = manifest?.projectConfig?.enabledAddons ?? [];
4720
+ for (const name of manifestAddons) {
4721
+ if (!config.installed[name] && isFileBasedAddon(name)) {
4722
+ const addonMeta = getAddonManifest(name);
4723
+ const fileList = [
4724
+ ...(addonMeta.files.skills ?? []).map((s) => `skills/${s}`),
4725
+ ...(addonMeta.files.agents ?? []).map((a) => `agents/${a}.md`),
4726
+ ...(addonMeta.files.rules ?? []).map((r) => `rules/${r}`)
4727
+ ];
4728
+ writeAddonToConfig(targetDir, name, {
4729
+ version: addonMeta.version,
4730
+ files: fileList
4731
+ });
4732
+ }
4733
+ }
4734
+ const freshConfig = readAddonConfig(targetDir);
4735
+ const installedNames = Object.keys(freshConfig.installed);
4705
4736
  if (installedNames.length === 0) {
4706
4737
  p14.log.info("No addons installed. Nothing to sync.");
4707
4738
  p14.outro("");
@@ -4712,8 +4743,9 @@ async function addonSyncCommand(options) {
4712
4743
  let totalWritten = 0;
4713
4744
  let totalConflicts = [];
4714
4745
  for (const name of installedNames) {
4746
+ if (!isFileBasedAddon(name)) continue;
4715
4747
  const addonSourceDir = getAddonSourceDir(name);
4716
- const result = syncAddonFiles(targetDir, addonSourceDir, config.agents);
4748
+ const result = syncAddonFiles(targetDir, addonSourceDir, freshConfig.agents);
4717
4749
  totalWritten += result.written + (result.updated ?? 0);
4718
4750
  totalConflicts = totalConflicts.concat(result.conflicts);
4719
4751
  }
@@ -4739,16 +4771,16 @@ function updateDescriptors(targetDir, manifest, pluginRoot, addonSkillCount) {
4739
4771
  }
4740
4772
 
4741
4773
  // src/commands/mode.ts
4742
- import { resolve as resolve14, join as join21 } from "path";
4743
- import { existsSync as existsSync17 } from "fs";
4774
+ import { resolve as resolve15, join as join21 } from "path";
4775
+ import { existsSync as existsSync18 } from "fs";
4744
4776
  import * as p15 from "@clack/prompts";
4745
4777
  import chalk16 from "chalk";
4746
4778
  async function modeCommand(action, options) {
4747
- const targetDir = resolve14(options.path || ".");
4779
+ const targetDir = resolve15(options.path || ".");
4748
4780
  p15.intro(introTitle("Mode"));
4749
4781
  if (action === "show") {
4750
4782
  const configPath = join21(targetDir, ".claude", "devtronic.json");
4751
- const hasConfig = existsSync17(configPath);
4783
+ const hasConfig = existsSync18(configPath);
4752
4784
  const config = readAddonConfig(targetDir);
4753
4785
  const currentMode = config.mode;
4754
4786
  const isDefault = !hasConfig || currentMode === void 0;