devtronic 1.2.2 → 1.2.4
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/dist/index.js +154 -149
- package/package.json +1 -1
- package/templates/addons/auto-devtronic/agents/failure-analyst.md +156 -0
- package/templates/addons/auto-devtronic/agents/issue-parser.md +145 -0
- package/templates/addons/auto-devtronic/agents/quality-runner.md +85 -0
- package/templates/addons/auto-devtronic/manifest.json +16 -0
- package/templates/addons/auto-devtronic/skills/auto-devtronic/SKILL.md +611 -0
- package/templates/addons/design-best-practices/manifest.json +28 -0
- package/templates/addons/design-best-practices/reference/color-and-contrast.md +146 -0
- package/templates/addons/design-best-practices/reference/interaction-design.md +208 -0
- package/templates/addons/design-best-practices/reference/motion-design.md +167 -0
- package/templates/addons/design-best-practices/reference/responsive-design.md +180 -0
- package/templates/addons/design-best-practices/reference/spatial-design.md +161 -0
- package/templates/addons/design-best-practices/reference/typography.md +136 -0
- package/templates/addons/design-best-practices/reference/ux-writing.md +190 -0
- package/templates/addons/design-best-practices/rules/design-quality.md +53 -0
- package/templates/addons/design-best-practices/skills/design-harden/SKILL.md +142 -0
- package/templates/addons/design-best-practices/skills/design-init/SKILL.md +95 -0
- package/templates/addons/design-best-practices/skills/design-refine/SKILL.md +124 -0
- package/templates/addons/design-best-practices/skills/design-review/SKILL.md +107 -0
- package/templates/addons/design-best-practices/skills/design-system/SKILL.md +125 -0
package/dist/index.js
CHANGED
|
@@ -1373,7 +1373,7 @@ Valid addons: ${validAddons.join(", ")}`);
|
|
|
1373
1373
|
p3.log.warn(`Addon "${options.addon}" requires claude-code IDE. Skipping.`);
|
|
1374
1374
|
}
|
|
1375
1375
|
}
|
|
1376
|
-
if (selectedIDEs.includes("claude-code") && !options.addon && !options.yes && !options.
|
|
1376
|
+
if (selectedIDEs.includes("claude-code") && !options.addon && !options.yes && !options.preview) {
|
|
1377
1377
|
const selectedAddons = await promptForAddons();
|
|
1378
1378
|
if (p3.isCancel(selectedAddons)) {
|
|
1379
1379
|
p3.cancel("Operation cancelled");
|
|
@@ -1717,8 +1717,8 @@ function buildProjectConfigFromPreset(presetConfig, analysis) {
|
|
|
1717
1717
|
}
|
|
1718
1718
|
|
|
1719
1719
|
// src/commands/update.ts
|
|
1720
|
-
import { resolve as
|
|
1721
|
-
import { existsSync as
|
|
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
|
|
1751
|
-
import { join as join9, dirname as
|
|
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
|
-
|
|
1758
|
-
return join8(addonsDir, name);
|
|
1763
|
+
return join8(getAddonsDir(), name);
|
|
1759
1764
|
}
|
|
1760
1765
|
function getAddonManifest(name) {
|
|
1761
1766
|
const sourceDir = getAddonSourceDir(name);
|
|
@@ -1783,11 +1788,11 @@ function getLegacyConfigPath(targetDir) {
|
|
|
1783
1788
|
function readAddonConfig(targetDir) {
|
|
1784
1789
|
const configPath = getConfigPath(targetDir);
|
|
1785
1790
|
const legacyPath = getLegacyConfigPath(targetDir);
|
|
1786
|
-
if (!
|
|
1787
|
-
mkdirSync(
|
|
1791
|
+
if (!existsSync7(configPath) && existsSync7(legacyPath)) {
|
|
1792
|
+
mkdirSync(dirname4(configPath), { recursive: true });
|
|
1788
1793
|
renameSync(legacyPath, configPath);
|
|
1789
1794
|
}
|
|
1790
|
-
if (!
|
|
1795
|
+
if (!existsSync7(configPath)) {
|
|
1791
1796
|
return { agents: ["claude"], installed: {} };
|
|
1792
1797
|
}
|
|
1793
1798
|
const raw = JSON.parse(readFileSync3(configPath, "utf-8"));
|
|
@@ -1801,7 +1806,7 @@ function readAddonConfig(targetDir) {
|
|
|
1801
1806
|
}
|
|
1802
1807
|
function writeAddonConfig(targetDir, config) {
|
|
1803
1808
|
const configPath = getConfigPath(targetDir);
|
|
1804
|
-
mkdirSync(
|
|
1809
|
+
mkdirSync(dirname4(configPath), { recursive: true });
|
|
1805
1810
|
const payload = { version: 1, ...config };
|
|
1806
1811
|
writeFileSync(configPath, JSON.stringify(payload, null, 2) + "\n");
|
|
1807
1812
|
}
|
|
@@ -1830,7 +1835,7 @@ function detectOrphanedAddonFiles(targetDir) {
|
|
|
1830
1835
|
for (const addon of getAvailableAddons()) {
|
|
1831
1836
|
if (config.installed[addon.name]) continue;
|
|
1832
1837
|
const skillDir = join9(targetDir, ".claude", "skills", addon.name);
|
|
1833
|
-
if (
|
|
1838
|
+
if (existsSync7(skillDir)) {
|
|
1834
1839
|
orphaned.push(addon.name);
|
|
1835
1840
|
}
|
|
1836
1841
|
}
|
|
@@ -1851,7 +1856,7 @@ function registerAddonInConfig(targetDir, addonName) {
|
|
|
1851
1856
|
|
|
1852
1857
|
// src/generators/addonFiles.ts
|
|
1853
1858
|
import {
|
|
1854
|
-
existsSync as
|
|
1859
|
+
existsSync as existsSync8,
|
|
1855
1860
|
readFileSync as readFileSync4,
|
|
1856
1861
|
writeFileSync as writeFileSync2,
|
|
1857
1862
|
mkdirSync as mkdirSync2,
|
|
@@ -1860,7 +1865,7 @@ import {
|
|
|
1860
1865
|
readdirSync,
|
|
1861
1866
|
rmdirSync
|
|
1862
1867
|
} from "fs";
|
|
1863
|
-
import { join as join10, dirname as
|
|
1868
|
+
import { join as join10, dirname as dirname5 } from "path";
|
|
1864
1869
|
import { createHash } from "crypto";
|
|
1865
1870
|
var AGENT_PATHS = {
|
|
1866
1871
|
claude: ".claude",
|
|
@@ -1917,7 +1922,7 @@ function checksum(content) {
|
|
|
1917
1922
|
return createHash("sha256").update(content).digest("hex").slice(0, 16);
|
|
1918
1923
|
}
|
|
1919
1924
|
function ensureDir2(dir) {
|
|
1920
|
-
if (!
|
|
1925
|
+
if (!existsSync8(dir)) mkdirSync2(dir, { recursive: true });
|
|
1921
1926
|
}
|
|
1922
1927
|
function readManifest2(addonSourceDir) {
|
|
1923
1928
|
const manifestPath = join10(addonSourceDir, "manifest.json");
|
|
@@ -1928,27 +1933,27 @@ function buildFileMap(addonSourceDir) {
|
|
|
1928
1933
|
const files = /* @__PURE__ */ new Map();
|
|
1929
1934
|
for (const skill of manifest.files.skills ?? []) {
|
|
1930
1935
|
const skillDir = join10(addonSourceDir, "skills", skill);
|
|
1931
|
-
if (!
|
|
1936
|
+
if (!existsSync8(skillDir)) continue;
|
|
1932
1937
|
const skillFile = join10(skillDir, "SKILL.md");
|
|
1933
|
-
if (
|
|
1938
|
+
if (existsSync8(skillFile)) {
|
|
1934
1939
|
files.set(`skills/${skill}/SKILL.md`, readFileSync4(skillFile, "utf-8"));
|
|
1935
1940
|
}
|
|
1936
1941
|
}
|
|
1937
1942
|
for (const agent of manifest.files.agents ?? []) {
|
|
1938
1943
|
const agentFile = join10(addonSourceDir, "agents", `${agent}.md`);
|
|
1939
|
-
if (
|
|
1944
|
+
if (existsSync8(agentFile)) {
|
|
1940
1945
|
files.set(`agents/${agent}.md`, readFileSync4(agentFile, "utf-8"));
|
|
1941
1946
|
}
|
|
1942
1947
|
}
|
|
1943
1948
|
for (const ref of manifest.files.reference ?? []) {
|
|
1944
1949
|
const refPath = join10(addonSourceDir, "reference", ref);
|
|
1945
|
-
if (
|
|
1950
|
+
if (existsSync8(refPath)) {
|
|
1946
1951
|
files.set(`skills/design-harden/reference/${ref}`, readFileSync4(refPath, "utf-8"));
|
|
1947
1952
|
}
|
|
1948
1953
|
}
|
|
1949
1954
|
for (const rule of manifest.files.rules ?? []) {
|
|
1950
1955
|
const rulePath = join10(addonSourceDir, "rules", rule);
|
|
1951
|
-
if (
|
|
1956
|
+
if (existsSync8(rulePath)) {
|
|
1952
1957
|
files.set(`rules/${rule}`, readFileSync4(rulePath, "utf-8"));
|
|
1953
1958
|
}
|
|
1954
1959
|
}
|
|
@@ -1964,11 +1969,11 @@ function generateAddonFiles(projectDir, addonSourceDir, agents) {
|
|
|
1964
1969
|
const basePath = AGENT_PATHS[agent] ?? `.${agent}`;
|
|
1965
1970
|
for (const [relPath, content] of fileMap) {
|
|
1966
1971
|
const destPath = join10(projectDir, basePath, relPath);
|
|
1967
|
-
if (
|
|
1972
|
+
if (existsSync8(destPath)) {
|
|
1968
1973
|
result.skipped++;
|
|
1969
1974
|
continue;
|
|
1970
1975
|
}
|
|
1971
|
-
ensureDir2(
|
|
1976
|
+
ensureDir2(dirname5(destPath));
|
|
1972
1977
|
writeFileSync2(destPath, content);
|
|
1973
1978
|
result.written++;
|
|
1974
1979
|
result.checksums[relPath] = checksum(content);
|
|
@@ -1977,11 +1982,11 @@ function generateAddonFiles(projectDir, addonSourceDir, agents) {
|
|
|
1977
1982
|
}
|
|
1978
1983
|
for (const skillName of manifest.files.skills ?? []) {
|
|
1979
1984
|
const skillFile = join10(addonSourceDir, "skills", skillName, "SKILL.md");
|
|
1980
|
-
if (!
|
|
1985
|
+
if (!existsSync8(skillFile)) continue;
|
|
1981
1986
|
const rawContent = readFileSync4(skillFile, "utf-8");
|
|
1982
1987
|
const { relPath, content } = spec.skillAdapter(skillName, rawContent);
|
|
1983
1988
|
const destPath = join10(projectDir, spec.baseDir, relPath);
|
|
1984
|
-
if (
|
|
1989
|
+
if (existsSync8(destPath)) {
|
|
1985
1990
|
const existing = readFileSync4(destPath, "utf-8");
|
|
1986
1991
|
if (existing === content) {
|
|
1987
1992
|
result.skipped++;
|
|
@@ -1990,18 +1995,18 @@ function generateAddonFiles(projectDir, addonSourceDir, agents) {
|
|
|
1990
1995
|
result.skipped++;
|
|
1991
1996
|
continue;
|
|
1992
1997
|
}
|
|
1993
|
-
ensureDir2(
|
|
1998
|
+
ensureDir2(dirname5(destPath));
|
|
1994
1999
|
writeFileSync2(destPath, content);
|
|
1995
2000
|
result.written++;
|
|
1996
2001
|
result.checksums[relPath] = checksum(content);
|
|
1997
2002
|
}
|
|
1998
2003
|
for (const agentName of manifest.files.agents ?? []) {
|
|
1999
2004
|
const agentFile = join10(addonSourceDir, "agents", `${agentName}.md`);
|
|
2000
|
-
if (!
|
|
2005
|
+
if (!existsSync8(agentFile)) continue;
|
|
2001
2006
|
const content = readFileSync4(agentFile, "utf-8");
|
|
2002
2007
|
const destPath = join10(projectDir, spec.baseDir, "agents", `${agentName}.md`);
|
|
2003
|
-
if (!
|
|
2004
|
-
ensureDir2(
|
|
2008
|
+
if (!existsSync8(destPath)) {
|
|
2009
|
+
ensureDir2(dirname5(destPath));
|
|
2005
2010
|
writeFileSync2(destPath, content);
|
|
2006
2011
|
result.written++;
|
|
2007
2012
|
result.checksums[`agents/${agentName}.md`] = checksum(content);
|
|
@@ -2012,11 +2017,11 @@ function generateAddonFiles(projectDir, addonSourceDir, agents) {
|
|
|
2012
2017
|
if (spec.rulesDir) {
|
|
2013
2018
|
for (const rule of manifest.files.rules ?? []) {
|
|
2014
2019
|
const ruleSrcPath = join10(addonSourceDir, "rules", rule);
|
|
2015
|
-
if (!
|
|
2020
|
+
if (!existsSync8(ruleSrcPath)) continue;
|
|
2016
2021
|
const content = readFileSync4(ruleSrcPath, "utf-8");
|
|
2017
2022
|
const destPath = join10(projectDir, spec.baseDir, spec.rulesDir, rule);
|
|
2018
|
-
if (!
|
|
2019
|
-
ensureDir2(
|
|
2023
|
+
if (!existsSync8(destPath)) {
|
|
2024
|
+
ensureDir2(dirname5(destPath));
|
|
2020
2025
|
writeFileSync2(destPath, content);
|
|
2021
2026
|
result.written++;
|
|
2022
2027
|
result.checksums[`rules/${rule}`] = checksum(content);
|
|
@@ -2027,12 +2032,12 @@ function generateAddonFiles(projectDir, addonSourceDir, agents) {
|
|
|
2027
2032
|
}
|
|
2028
2033
|
for (const ref of manifest.files.reference ?? []) {
|
|
2029
2034
|
const refSrcPath = join10(addonSourceDir, "reference", ref);
|
|
2030
|
-
if (!
|
|
2035
|
+
if (!existsSync8(refSrcPath)) continue;
|
|
2031
2036
|
const content = readFileSync4(refSrcPath, "utf-8");
|
|
2032
2037
|
const relPath = `skills/design-harden/reference/${ref}`;
|
|
2033
2038
|
const destPath = join10(projectDir, spec.baseDir, relPath);
|
|
2034
|
-
if (!
|
|
2035
|
-
ensureDir2(
|
|
2039
|
+
if (!existsSync8(destPath)) {
|
|
2040
|
+
ensureDir2(dirname5(destPath));
|
|
2036
2041
|
writeFileSync2(destPath, content);
|
|
2037
2042
|
result.written++;
|
|
2038
2043
|
result.checksums[relPath] = checksum(content);
|
|
@@ -2071,20 +2076,20 @@ function removeAddonFiles(projectDir, addonName, agents, addonSourceDir) {
|
|
|
2071
2076
|
const basePath = AGENT_PATHS[agent] ?? `.${agent}`;
|
|
2072
2077
|
for (const skill of knownSkills) {
|
|
2073
2078
|
const skillDir = join10(projectDir, basePath, "skills", skill);
|
|
2074
|
-
if (
|
|
2079
|
+
if (existsSync8(skillDir)) rmSync(skillDir, { recursive: true, force: true });
|
|
2075
2080
|
}
|
|
2076
2081
|
for (const agentName of knownAgents) {
|
|
2077
2082
|
const agentPath = join10(projectDir, basePath, "agents", `${agentName}.md`);
|
|
2078
|
-
if (
|
|
2083
|
+
if (existsSync8(agentPath)) unlinkSync(agentPath);
|
|
2079
2084
|
}
|
|
2080
2085
|
continue;
|
|
2081
2086
|
}
|
|
2082
2087
|
for (const skillName of knownSkills) {
|
|
2083
2088
|
const { relPath } = spec.skillAdapter(skillName, "");
|
|
2084
2089
|
const destPath = join10(projectDir, spec.baseDir, relPath);
|
|
2085
|
-
if (
|
|
2086
|
-
const parentDir =
|
|
2087
|
-
if (
|
|
2090
|
+
if (existsSync8(destPath)) unlinkSync(destPath);
|
|
2091
|
+
const parentDir = dirname5(destPath);
|
|
2092
|
+
if (existsSync8(parentDir)) {
|
|
2088
2093
|
try {
|
|
2089
2094
|
const entries = readdirSync(parentDir);
|
|
2090
2095
|
if (entries.length === 0) rmdirSync(parentDir);
|
|
@@ -2094,20 +2099,20 @@ function removeAddonFiles(projectDir, addonName, agents, addonSourceDir) {
|
|
|
2094
2099
|
}
|
|
2095
2100
|
for (const agentName of knownAgents) {
|
|
2096
2101
|
const agentPath = join10(projectDir, spec.baseDir, "agents", `${agentName}.md`);
|
|
2097
|
-
if (
|
|
2102
|
+
if (existsSync8(agentPath)) unlinkSync(agentPath);
|
|
2098
2103
|
}
|
|
2099
2104
|
if (spec.rulesDir) {
|
|
2100
2105
|
for (const rule of manifest.files.rules ?? []) {
|
|
2101
2106
|
const rulePath = join10(projectDir, spec.baseDir, spec.rulesDir, rule);
|
|
2102
|
-
if (
|
|
2107
|
+
if (existsSync8(rulePath)) unlinkSync(rulePath);
|
|
2103
2108
|
}
|
|
2104
2109
|
}
|
|
2105
2110
|
for (const ref of manifest.files.reference ?? []) {
|
|
2106
2111
|
const refPath = join10(projectDir, spec.baseDir, "skills", "design-harden", "reference", ref);
|
|
2107
|
-
if (
|
|
2112
|
+
if (existsSync8(refPath)) unlinkSync(refPath);
|
|
2108
2113
|
}
|
|
2109
2114
|
const refDir = join10(projectDir, spec.baseDir, "skills", "design-harden", "reference");
|
|
2110
|
-
if (
|
|
2115
|
+
if (existsSync8(refDir)) {
|
|
2111
2116
|
try {
|
|
2112
2117
|
const entries = readdirSync(refDir);
|
|
2113
2118
|
if (entries.length === 0) rmdirSync(refDir);
|
|
@@ -2116,7 +2121,7 @@ function removeAddonFiles(projectDir, addonName, agents, addonSourceDir) {
|
|
|
2116
2121
|
}
|
|
2117
2122
|
}
|
|
2118
2123
|
const noticePath = join10(projectDir, "NOTICE.md");
|
|
2119
|
-
if (
|
|
2124
|
+
if (existsSync8(noticePath)) unlinkSync(noticePath);
|
|
2120
2125
|
}
|
|
2121
2126
|
function syncAddonFiles(projectDir, addonSourceDir, agents) {
|
|
2122
2127
|
const fileMap = buildFileMap(addonSourceDir);
|
|
@@ -2138,8 +2143,8 @@ function syncAddonFiles(projectDir, addonSourceDir, agents) {
|
|
|
2138
2143
|
const basePath = AGENT_PATHS[agent] ?? `.${agent}`;
|
|
2139
2144
|
for (const [relPath, newContent] of fileMap) {
|
|
2140
2145
|
const destPath = join10(projectDir, basePath, relPath);
|
|
2141
|
-
if (!
|
|
2142
|
-
ensureDir2(
|
|
2146
|
+
if (!existsSync8(destPath)) {
|
|
2147
|
+
ensureDir2(dirname5(destPath));
|
|
2143
2148
|
writeFileSync2(destPath, newContent);
|
|
2144
2149
|
result.written++;
|
|
2145
2150
|
continue;
|
|
@@ -2162,12 +2167,12 @@ function syncAddonFiles(projectDir, addonSourceDir, agents) {
|
|
|
2162
2167
|
}
|
|
2163
2168
|
for (const skillName of manifest.files.skills ?? []) {
|
|
2164
2169
|
const skillFile = join10(addonSourceDir, "skills", skillName, "SKILL.md");
|
|
2165
|
-
if (!
|
|
2170
|
+
if (!existsSync8(skillFile)) continue;
|
|
2166
2171
|
const rawContent = readFileSync4(skillFile, "utf-8");
|
|
2167
2172
|
const { relPath, content: newContent } = spec.skillAdapter(skillName, rawContent);
|
|
2168
2173
|
const destPath = join10(projectDir, spec.baseDir, relPath);
|
|
2169
|
-
if (!
|
|
2170
|
-
ensureDir2(
|
|
2174
|
+
if (!existsSync8(destPath)) {
|
|
2175
|
+
ensureDir2(dirname5(destPath));
|
|
2171
2176
|
writeFileSync2(destPath, newContent);
|
|
2172
2177
|
result.written++;
|
|
2173
2178
|
continue;
|
|
@@ -2188,12 +2193,12 @@ function syncAddonFiles(projectDir, addonSourceDir, agents) {
|
|
|
2188
2193
|
}
|
|
2189
2194
|
for (const agentName of manifest.files.agents ?? []) {
|
|
2190
2195
|
const agentFile = join10(addonSourceDir, "agents", `${agentName}.md`);
|
|
2191
|
-
if (!
|
|
2196
|
+
if (!existsSync8(agentFile)) continue;
|
|
2192
2197
|
const newContent = readFileSync4(agentFile, "utf-8");
|
|
2193
2198
|
const destPath = join10(projectDir, spec.baseDir, "agents", `${agentName}.md`);
|
|
2194
2199
|
const relPath = `agents/${agentName}.md`;
|
|
2195
|
-
if (!
|
|
2196
|
-
ensureDir2(
|
|
2200
|
+
if (!existsSync8(destPath)) {
|
|
2201
|
+
ensureDir2(dirname5(destPath));
|
|
2197
2202
|
writeFileSync2(destPath, newContent);
|
|
2198
2203
|
result.written++;
|
|
2199
2204
|
continue;
|
|
@@ -2215,12 +2220,12 @@ function syncAddonFiles(projectDir, addonSourceDir, agents) {
|
|
|
2215
2220
|
if (spec.rulesDir) {
|
|
2216
2221
|
for (const rule of manifest.files.rules ?? []) {
|
|
2217
2222
|
const ruleSrcPath = join10(addonSourceDir, "rules", rule);
|
|
2218
|
-
if (!
|
|
2223
|
+
if (!existsSync8(ruleSrcPath)) continue;
|
|
2219
2224
|
const newContent = readFileSync4(ruleSrcPath, "utf-8");
|
|
2220
2225
|
const destPath = join10(projectDir, spec.baseDir, spec.rulesDir, rule);
|
|
2221
2226
|
const relPath = `rules/${rule}`;
|
|
2222
|
-
if (!
|
|
2223
|
-
ensureDir2(
|
|
2227
|
+
if (!existsSync8(destPath)) {
|
|
2228
|
+
ensureDir2(dirname5(destPath));
|
|
2224
2229
|
writeFileSync2(destPath, newContent);
|
|
2225
2230
|
result.written++;
|
|
2226
2231
|
continue;
|
|
@@ -2242,12 +2247,12 @@ function syncAddonFiles(projectDir, addonSourceDir, agents) {
|
|
|
2242
2247
|
}
|
|
2243
2248
|
for (const ref of manifest.files.reference ?? []) {
|
|
2244
2249
|
const refSrcPath = join10(addonSourceDir, "reference", ref);
|
|
2245
|
-
if (!
|
|
2250
|
+
if (!existsSync8(refSrcPath)) continue;
|
|
2246
2251
|
const newContent = readFileSync4(refSrcPath, "utf-8");
|
|
2247
2252
|
const relPath = `skills/design-harden/reference/${ref}`;
|
|
2248
2253
|
const destPath = join10(projectDir, spec.baseDir, relPath);
|
|
2249
|
-
if (!
|
|
2250
|
-
ensureDir2(
|
|
2254
|
+
if (!existsSync8(destPath)) {
|
|
2255
|
+
ensureDir2(dirname5(destPath));
|
|
2251
2256
|
writeFileSync2(destPath, newContent);
|
|
2252
2257
|
result.written++;
|
|
2253
2258
|
continue;
|
|
@@ -2283,7 +2288,7 @@ function detectModifiedAddonFiles(projectDir, addonName) {
|
|
|
2283
2288
|
for (const agentDir of Object.values(AGENT_PATHS)) {
|
|
2284
2289
|
for (const [relPath, originalHash] of Object.entries(installedChecksums)) {
|
|
2285
2290
|
const absPath = join10(projectDir, agentDir, relPath);
|
|
2286
|
-
if (!
|
|
2291
|
+
if (!existsSync8(absPath)) continue;
|
|
2287
2292
|
const current = checksum(readFileSync4(absPath, "utf-8"));
|
|
2288
2293
|
if (current !== originalHash) {
|
|
2289
2294
|
modified.push(relPath);
|
|
@@ -2298,7 +2303,7 @@ async function updateCommand(options) {
|
|
|
2298
2303
|
if (!options.check && !options.dryRun) {
|
|
2299
2304
|
ensureInteractive("update");
|
|
2300
2305
|
}
|
|
2301
|
-
const targetDir =
|
|
2306
|
+
const targetDir = resolve4(options.path || ".");
|
|
2302
2307
|
p4.intro(introTitle("Update"));
|
|
2303
2308
|
const manifest = readManifest(targetDir);
|
|
2304
2309
|
if (!manifest) {
|
|
@@ -2371,7 +2376,7 @@ async function updateCommand(options) {
|
|
|
2371
2376
|
const newFiles = [];
|
|
2372
2377
|
for (const ide of manifest.selectedIDEs) {
|
|
2373
2378
|
const templateDir = join11(TEMPLATES_DIR, IDE_TEMPLATE_MAP[ide]);
|
|
2374
|
-
if (!
|
|
2379
|
+
if (!existsSync9(templateDir)) continue;
|
|
2375
2380
|
const files = getAllFilesRecursive(templateDir);
|
|
2376
2381
|
for (const file of files) {
|
|
2377
2382
|
const templatePath = join11(templateDir, file);
|
|
@@ -2394,7 +2399,7 @@ async function updateCommand(options) {
|
|
|
2394
2399
|
let foundInAnyTemplate = false;
|
|
2395
2400
|
for (const ide of manifest.selectedIDEs) {
|
|
2396
2401
|
const templateDir = join11(TEMPLATES_DIR, IDE_TEMPLATE_MAP[ide]);
|
|
2397
|
-
if (
|
|
2402
|
+
if (existsSync9(join11(templateDir, relativePath))) {
|
|
2398
2403
|
foundInAnyTemplate = true;
|
|
2399
2404
|
break;
|
|
2400
2405
|
}
|
|
@@ -2529,7 +2534,7 @@ async function updateCommand(options) {
|
|
|
2529
2534
|
};
|
|
2530
2535
|
for (const ide of manifest.selectedIDEs) {
|
|
2531
2536
|
const templateDir = join11(TEMPLATES_DIR, IDE_TEMPLATE_MAP[ide]);
|
|
2532
|
-
if (!
|
|
2537
|
+
if (!existsSync9(templateDir)) continue;
|
|
2533
2538
|
const isPluginMode = ide === "claude-code" && manifest.installMode === "plugin";
|
|
2534
2539
|
const files = getAllFilesRecursive(templateDir);
|
|
2535
2540
|
for (const file of files) {
|
|
@@ -2542,7 +2547,7 @@ async function updateCommand(options) {
|
|
|
2542
2547
|
const templatePath = join11(templateDir, file);
|
|
2543
2548
|
const destPath = join11(targetDir, file);
|
|
2544
2549
|
const templateContent = readFile(templatePath);
|
|
2545
|
-
ensureDir(
|
|
2550
|
+
ensureDir(dirname6(destPath));
|
|
2546
2551
|
writeFile(destPath, templateContent);
|
|
2547
2552
|
updatedManifest.files[file] = createManifestEntry(templateContent);
|
|
2548
2553
|
}
|
|
@@ -2568,7 +2573,7 @@ async function updateCommand(options) {
|
|
|
2568
2573
|
);
|
|
2569
2574
|
for (const script of ["checkpoint.sh", "stop-guard.sh"]) {
|
|
2570
2575
|
const scriptPath = join11(targetDir, pluginResult.pluginPath, "scripts", script);
|
|
2571
|
-
if (
|
|
2576
|
+
if (existsSync9(scriptPath)) {
|
|
2572
2577
|
chmodSync2(scriptPath, 493);
|
|
2573
2578
|
}
|
|
2574
2579
|
}
|
|
@@ -2765,7 +2770,7 @@ async function regenerateWithNewStack(targetDir, manifest, analysis, dryRun) {
|
|
|
2765
2770
|
const rulePath = DYNAMIC_RULE_FILES[ide]?.[0];
|
|
2766
2771
|
if (ruleContent && rulePath) {
|
|
2767
2772
|
const destPath = join11(targetDir, rulePath);
|
|
2768
|
-
ensureDir(
|
|
2773
|
+
ensureDir(dirname6(destPath));
|
|
2769
2774
|
writeFile(destPath, ruleContent);
|
|
2770
2775
|
regeneratedFiles.push(rulePath);
|
|
2771
2776
|
manifest.files[rulePath] = createManifestEntry(ruleContent);
|
|
@@ -2792,7 +2797,7 @@ async function regenerateWithNewStack(targetDir, manifest, analysis, dryRun) {
|
|
|
2792
2797
|
);
|
|
2793
2798
|
for (const script of ["checkpoint.sh", "stop-guard.sh"]) {
|
|
2794
2799
|
const scriptPath = join11(targetDir, pluginResult.pluginPath, "scripts", script);
|
|
2795
|
-
if (
|
|
2800
|
+
if (existsSync9(scriptPath)) {
|
|
2796
2801
|
chmodSync2(scriptPath, 493);
|
|
2797
2802
|
}
|
|
2798
2803
|
}
|
|
@@ -2841,7 +2846,7 @@ async function migrateToPlugin(targetDir, manifest, analysis, dryRun) {
|
|
|
2841
2846
|
);
|
|
2842
2847
|
for (const script of ["checkpoint.sh", "stop-guard.sh"]) {
|
|
2843
2848
|
const scriptPath = join11(targetDir, pluginResult.pluginPath, "scripts", script);
|
|
2844
|
-
if (
|
|
2849
|
+
if (existsSync9(scriptPath)) {
|
|
2845
2850
|
chmodSync2(scriptPath, 493);
|
|
2846
2851
|
}
|
|
2847
2852
|
}
|
|
@@ -2911,11 +2916,11 @@ function buildDefaultConfig(analysis) {
|
|
|
2911
2916
|
};
|
|
2912
2917
|
}
|
|
2913
2918
|
function cleanEmptyDirs(dirPath) {
|
|
2914
|
-
if (!
|
|
2919
|
+
if (!existsSync9(dirPath)) return;
|
|
2915
2920
|
const entries = readdirSync2(dirPath);
|
|
2916
2921
|
for (const entry of entries) {
|
|
2917
2922
|
const fullPath = join11(dirPath, entry);
|
|
2918
|
-
if (
|
|
2923
|
+
if (existsSync9(fullPath) && lstatSync(fullPath).isDirectory()) {
|
|
2919
2924
|
cleanEmptyDirs(fullPath);
|
|
2920
2925
|
}
|
|
2921
2926
|
}
|
|
@@ -2926,11 +2931,11 @@ function cleanEmptyDirs(dirPath) {
|
|
|
2926
2931
|
}
|
|
2927
2932
|
|
|
2928
2933
|
// src/commands/status.ts
|
|
2929
|
-
import { resolve as
|
|
2934
|
+
import { resolve as resolve5, join as join12 } from "path";
|
|
2930
2935
|
import * as p5 from "@clack/prompts";
|
|
2931
2936
|
import chalk6 from "chalk";
|
|
2932
2937
|
async function statusCommand(options = {}) {
|
|
2933
|
-
const targetDir =
|
|
2938
|
+
const targetDir = resolve5(options.path || ".");
|
|
2934
2939
|
p5.intro(introTitle("Status"));
|
|
2935
2940
|
const manifest = readManifest(targetDir);
|
|
2936
2941
|
const latestPromise = getLatestVersion("devtronic");
|
|
@@ -3012,12 +3017,12 @@ async function statusCommand(options = {}) {
|
|
|
3012
3017
|
}
|
|
3013
3018
|
|
|
3014
3019
|
// src/commands/diff.ts
|
|
3015
|
-
import { resolve as
|
|
3016
|
-
import { existsSync as
|
|
3020
|
+
import { resolve as resolve6, join as join13 } from "path";
|
|
3021
|
+
import { existsSync as existsSync10 } from "fs";
|
|
3017
3022
|
import * as p6 from "@clack/prompts";
|
|
3018
3023
|
import chalk7 from "chalk";
|
|
3019
3024
|
async function diffCommand(options = {}) {
|
|
3020
|
-
const targetDir =
|
|
3025
|
+
const targetDir = resolve6(options.path || ".");
|
|
3021
3026
|
p6.intro(introTitle("Diff"));
|
|
3022
3027
|
const manifest = readManifest(targetDir);
|
|
3023
3028
|
if (!manifest) {
|
|
@@ -3029,7 +3034,7 @@ async function diffCommand(options = {}) {
|
|
|
3029
3034
|
const diffs = [];
|
|
3030
3035
|
for (const ide of manifest.selectedIDEs) {
|
|
3031
3036
|
const templateDir = join13(TEMPLATES_DIR, IDE_TEMPLATE_MAP[ide]);
|
|
3032
|
-
if (!
|
|
3037
|
+
if (!existsSync10(templateDir)) continue;
|
|
3033
3038
|
const templateFiles = getAllFilesRecursive(templateDir);
|
|
3034
3039
|
for (const file of templateFiles) {
|
|
3035
3040
|
const templatePath = join13(templateDir, file);
|
|
@@ -3086,8 +3091,8 @@ async function diffCommand(options = {}) {
|
|
|
3086
3091
|
}
|
|
3087
3092
|
|
|
3088
3093
|
// src/commands/add.ts
|
|
3089
|
-
import { existsSync as
|
|
3090
|
-
import { resolve as
|
|
3094
|
+
import { existsSync as existsSync11 } from "fs";
|
|
3095
|
+
import { resolve as resolve7, join as join14, dirname as dirname7 } from "path";
|
|
3091
3096
|
import * as p7 from "@clack/prompts";
|
|
3092
3097
|
import chalk8 from "chalk";
|
|
3093
3098
|
var ALL_IDES = [
|
|
@@ -3101,7 +3106,7 @@ async function addCommand(ide, options) {
|
|
|
3101
3106
|
if (!options.yes) {
|
|
3102
3107
|
ensureInteractive("add");
|
|
3103
3108
|
}
|
|
3104
|
-
const targetDir =
|
|
3109
|
+
const targetDir = resolve7(options.path || ".");
|
|
3105
3110
|
p7.intro(introTitle("Add IDE"));
|
|
3106
3111
|
const manifest = readManifest(targetDir);
|
|
3107
3112
|
if (!manifest) {
|
|
@@ -3182,7 +3187,7 @@ Valid options: ${ALL_IDES.map((i) => i.value).join(", ")}`
|
|
|
3182
3187
|
const generatedRules = generateArchitectureRules(manifest.projectConfig);
|
|
3183
3188
|
const templateName = IDE_TEMPLATE_MAP[selectedIDE];
|
|
3184
3189
|
const templateDir = join14(TEMPLATES_DIR, templateName);
|
|
3185
|
-
if (!
|
|
3190
|
+
if (!existsSync11(templateDir)) {
|
|
3186
3191
|
spinner8.stop("Error");
|
|
3187
3192
|
p7.cancel(`Template not found: ${templateName}`);
|
|
3188
3193
|
process.exit(1);
|
|
@@ -3211,7 +3216,7 @@ Valid options: ${ALL_IDES.map((i) => i.value).join(", ")}`
|
|
|
3211
3216
|
continue;
|
|
3212
3217
|
}
|
|
3213
3218
|
}
|
|
3214
|
-
ensureDir(
|
|
3219
|
+
ensureDir(dirname7(destPath));
|
|
3215
3220
|
writeFile(destPath, sourceContent);
|
|
3216
3221
|
appliedFiles.push(file);
|
|
3217
3222
|
manifest.files[file] = createManifestEntry(sourceContent);
|
|
@@ -3231,7 +3236,7 @@ Valid options: ${ALL_IDES.map((i) => i.value).join(", ")}`
|
|
|
3231
3236
|
mergedFiles.push(rulePath);
|
|
3232
3237
|
manifest.files[rulePath] = createManifestEntry(mergedContent);
|
|
3233
3238
|
} else {
|
|
3234
|
-
ensureDir(
|
|
3239
|
+
ensureDir(dirname7(destPath));
|
|
3235
3240
|
writeFile(destPath, ruleContent);
|
|
3236
3241
|
generatedFiles.push(`${rulePath} (personalized)`);
|
|
3237
3242
|
manifest.files[rulePath] = createManifestEntry(ruleContent);
|
|
@@ -3272,17 +3277,17 @@ Valid options: ${ALL_IDES.map((i) => i.value).join(", ")}`
|
|
|
3272
3277
|
}
|
|
3273
3278
|
|
|
3274
3279
|
// src/commands/regenerate.ts
|
|
3275
|
-
import { existsSync as
|
|
3276
|
-
import { resolve as
|
|
3277
|
-
import { fileURLToPath as
|
|
3280
|
+
import { existsSync as existsSync12 } from "fs";
|
|
3281
|
+
import { resolve as resolve8, join as join15, dirname as dirname8 } from "path";
|
|
3282
|
+
import { fileURLToPath as fileURLToPath4 } from "url";
|
|
3278
3283
|
import * as p8 from "@clack/prompts";
|
|
3279
3284
|
import chalk9 from "chalk";
|
|
3280
|
-
var __filename =
|
|
3281
|
-
var __regen_dirname =
|
|
3282
|
-
var TEMPLATES_DIR2 =
|
|
3285
|
+
var __filename = fileURLToPath4(import.meta.url);
|
|
3286
|
+
var __regen_dirname = dirname8(__filename);
|
|
3287
|
+
var TEMPLATES_DIR2 = existsSync12(resolve8(__regen_dirname, "../templates")) ? resolve8(__regen_dirname, "../templates") : resolve8(__regen_dirname, "../../templates");
|
|
3283
3288
|
async function regenerateCommand(target, options) {
|
|
3284
3289
|
ensureInteractive("regenerate");
|
|
3285
|
-
const targetDir =
|
|
3290
|
+
const targetDir = resolve8(options.path || ".");
|
|
3286
3291
|
p8.intro(introTitle("Regenerate"));
|
|
3287
3292
|
const manifest = readManifest(targetDir);
|
|
3288
3293
|
if (!manifest) {
|
|
@@ -3422,7 +3427,7 @@ Valid options:
|
|
|
3422
3427
|
const rulePath = DYNAMIC_RULE_FILES[ide]?.[0];
|
|
3423
3428
|
if (ruleContent && rulePath) {
|
|
3424
3429
|
const destPath = join15(targetDir, rulePath);
|
|
3425
|
-
ensureDir(
|
|
3430
|
+
ensureDir(dirname8(destPath));
|
|
3426
3431
|
writeFile(destPath, ruleContent);
|
|
3427
3432
|
regeneratedFiles.push(rulePath);
|
|
3428
3433
|
manifest.files[rulePath] = createManifestEntry(ruleContent);
|
|
@@ -3471,12 +3476,12 @@ Valid options:
|
|
|
3471
3476
|
}
|
|
3472
3477
|
|
|
3473
3478
|
// src/commands/info.ts
|
|
3474
|
-
import { resolve as
|
|
3475
|
-
import { existsSync as
|
|
3479
|
+
import { resolve as resolve9, join as join16 } from "path";
|
|
3480
|
+
import { existsSync as existsSync13, readdirSync as readdirSync3 } from "fs";
|
|
3476
3481
|
import * as p9 from "@clack/prompts";
|
|
3477
3482
|
import chalk10 from "chalk";
|
|
3478
3483
|
async function infoCommand() {
|
|
3479
|
-
const targetDir =
|
|
3484
|
+
const targetDir = resolve9(".");
|
|
3480
3485
|
p9.intro(introTitle("Info"));
|
|
3481
3486
|
const manifest = readManifest(targetDir);
|
|
3482
3487
|
const currentVersion = getCliVersion();
|
|
@@ -3486,15 +3491,15 @@ async function infoCommand() {
|
|
|
3486
3491
|
let agentCount = 0;
|
|
3487
3492
|
if (manifest) {
|
|
3488
3493
|
const pluginDir = manifest.pluginPath ? join16(targetDir, manifest.pluginPath) : null;
|
|
3489
|
-
if (pluginDir &&
|
|
3494
|
+
if (pluginDir && existsSync13(pluginDir)) {
|
|
3490
3495
|
const skillsDir = join16(pluginDir, "skills");
|
|
3491
3496
|
const agentsDir = join16(pluginDir, "agents");
|
|
3492
|
-
if (
|
|
3497
|
+
if (existsSync13(skillsDir)) {
|
|
3493
3498
|
skillCount = readdirSync3(skillsDir, { withFileTypes: true }).filter(
|
|
3494
3499
|
(e) => e.isDirectory() || e.isFile() && e.name.endsWith(".md")
|
|
3495
3500
|
).length;
|
|
3496
3501
|
}
|
|
3497
|
-
if (
|
|
3502
|
+
if (existsSync13(agentsDir)) {
|
|
3498
3503
|
agentCount = readdirSync3(agentsDir, { withFileTypes: true }).filter(
|
|
3499
3504
|
(e) => e.isFile() && e.name.endsWith(".md")
|
|
3500
3505
|
).length;
|
|
@@ -3502,7 +3507,7 @@ async function infoCommand() {
|
|
|
3502
3507
|
}
|
|
3503
3508
|
if (skillCount === 0) {
|
|
3504
3509
|
const claudeSkills = join16(targetDir, ".claude", "skills");
|
|
3505
|
-
if (
|
|
3510
|
+
if (existsSync13(claudeSkills)) {
|
|
3506
3511
|
skillCount = readdirSync3(claudeSkills, { withFileTypes: true }).filter(
|
|
3507
3512
|
(e) => e.isDirectory() || e.isFile() && e.name.endsWith(".md")
|
|
3508
3513
|
).length;
|
|
@@ -3510,7 +3515,7 @@ async function infoCommand() {
|
|
|
3510
3515
|
}
|
|
3511
3516
|
if (agentCount === 0) {
|
|
3512
3517
|
const claudeAgents = join16(targetDir, ".claude", "agents");
|
|
3513
|
-
if (
|
|
3518
|
+
if (existsSync13(claudeAgents)) {
|
|
3514
3519
|
agentCount = readdirSync3(claudeAgents, { withFileTypes: true }).filter(
|
|
3515
3520
|
(e) => e.isFile() && e.name.endsWith(".md")
|
|
3516
3521
|
).length;
|
|
@@ -3554,12 +3559,12 @@ async function infoCommand() {
|
|
|
3554
3559
|
}
|
|
3555
3560
|
|
|
3556
3561
|
// src/commands/list.ts
|
|
3557
|
-
import { resolve as
|
|
3558
|
-
import { existsSync as
|
|
3562
|
+
import { resolve as resolve10, join as join17 } from "path";
|
|
3563
|
+
import { existsSync as existsSync14, readdirSync as readdirSync4, readFileSync as readFileSync5 } from "fs";
|
|
3559
3564
|
import * as p10 from "@clack/prompts";
|
|
3560
3565
|
import chalk11 from "chalk";
|
|
3561
3566
|
async function listCommand(filter, options) {
|
|
3562
|
-
const targetDir =
|
|
3567
|
+
const targetDir = resolve10(options.path || ".");
|
|
3563
3568
|
p10.intro(introTitle("List"));
|
|
3564
3569
|
const manifest = readManifest(targetDir);
|
|
3565
3570
|
const showSkills = !filter || filter === "skills";
|
|
@@ -3573,29 +3578,29 @@ Valid options: skills, agents`);
|
|
|
3573
3578
|
const skills = [];
|
|
3574
3579
|
const agents = [];
|
|
3575
3580
|
const pluginDir = manifest?.pluginPath ? join17(targetDir, manifest.pluginPath) : null;
|
|
3576
|
-
if (pluginDir &&
|
|
3581
|
+
if (pluginDir && existsSync14(pluginDir)) {
|
|
3577
3582
|
if (showSkills) {
|
|
3578
3583
|
const skillsDir = join17(pluginDir, "skills");
|
|
3579
|
-
if (
|
|
3584
|
+
if (existsSync14(skillsDir)) {
|
|
3580
3585
|
skills.push(...discoverSkills(skillsDir));
|
|
3581
3586
|
}
|
|
3582
3587
|
}
|
|
3583
3588
|
if (showAgents) {
|
|
3584
3589
|
const agentsDir = join17(pluginDir, "agents");
|
|
3585
|
-
if (
|
|
3590
|
+
if (existsSync14(agentsDir)) {
|
|
3586
3591
|
agents.push(...discoverAgents(agentsDir));
|
|
3587
3592
|
}
|
|
3588
3593
|
}
|
|
3589
3594
|
}
|
|
3590
3595
|
if (showSkills && skills.length === 0) {
|
|
3591
3596
|
const claudeSkills = join17(targetDir, ".claude", "skills");
|
|
3592
|
-
if (
|
|
3597
|
+
if (existsSync14(claudeSkills)) {
|
|
3593
3598
|
skills.push(...discoverSkills(claudeSkills));
|
|
3594
3599
|
}
|
|
3595
3600
|
}
|
|
3596
3601
|
if (showAgents && agents.length === 0) {
|
|
3597
3602
|
const claudeAgents = join17(targetDir, ".claude", "agents");
|
|
3598
|
-
if (
|
|
3603
|
+
if (existsSync14(claudeAgents)) {
|
|
3599
3604
|
agents.push(...discoverAgents(claudeAgents));
|
|
3600
3605
|
}
|
|
3601
3606
|
}
|
|
@@ -3623,7 +3628,7 @@ function discoverSkills(skillsDir) {
|
|
|
3623
3628
|
for (const entry of entries) {
|
|
3624
3629
|
if (entry.isDirectory()) {
|
|
3625
3630
|
const skillMd = join17(skillsDir, entry.name, "SKILL.md");
|
|
3626
|
-
const description =
|
|
3631
|
+
const description = existsSync14(skillMd) ? extractDescription(skillMd) : "";
|
|
3627
3632
|
items.push({ name: entry.name, description });
|
|
3628
3633
|
} else if (entry.isFile() && entry.name.endsWith(".md")) {
|
|
3629
3634
|
const name = entry.name.replace(/\.md$/, "");
|
|
@@ -3668,7 +3673,7 @@ function extractDescription(filePath) {
|
|
|
3668
3673
|
}
|
|
3669
3674
|
|
|
3670
3675
|
// src/commands/config.ts
|
|
3671
|
-
import { resolve as
|
|
3676
|
+
import { resolve as resolve11 } from "path";
|
|
3672
3677
|
import * as p11 from "@clack/prompts";
|
|
3673
3678
|
import chalk12 from "chalk";
|
|
3674
3679
|
var ARRAY_KEYS = [
|
|
@@ -3688,7 +3693,7 @@ var VALID_KEYS = [
|
|
|
3688
3693
|
...ARRAY_KEYS
|
|
3689
3694
|
];
|
|
3690
3695
|
async function configCommand(options) {
|
|
3691
|
-
const targetDir =
|
|
3696
|
+
const targetDir = resolve11(options.path || ".");
|
|
3692
3697
|
p11.intro(introTitle("Config"));
|
|
3693
3698
|
const manifest = readManifest(targetDir);
|
|
3694
3699
|
if (!manifest) {
|
|
@@ -3720,7 +3725,7 @@ async function configCommand(options) {
|
|
|
3720
3725
|
p11.outro("");
|
|
3721
3726
|
}
|
|
3722
3727
|
async function configSetCommand(key, value, options) {
|
|
3723
|
-
const targetDir =
|
|
3728
|
+
const targetDir = resolve11(options.path || ".");
|
|
3724
3729
|
p11.intro(introTitle("Config Set"));
|
|
3725
3730
|
const manifest = readManifest(targetDir);
|
|
3726
3731
|
if (!manifest || !manifest.projectConfig) {
|
|
@@ -3775,7 +3780,7 @@ Valid addons: ${validAddons.join(", ")}`
|
|
|
3775
3780
|
p11.outro(chalk12.green("Configuration updated"));
|
|
3776
3781
|
}
|
|
3777
3782
|
async function configResetCommand(options) {
|
|
3778
|
-
const targetDir =
|
|
3783
|
+
const targetDir = resolve11(options.path || ".");
|
|
3779
3784
|
p11.intro(introTitle("Config Reset"));
|
|
3780
3785
|
const manifest = readManifest(targetDir);
|
|
3781
3786
|
if (!manifest) {
|
|
@@ -3826,13 +3831,13 @@ async function configResetCommand(options) {
|
|
|
3826
3831
|
}
|
|
3827
3832
|
|
|
3828
3833
|
// src/commands/doctor.ts
|
|
3829
|
-
import { resolve as
|
|
3830
|
-
import { existsSync as
|
|
3834
|
+
import { resolve as resolve12, join as join18 } from "path";
|
|
3835
|
+
import { existsSync as existsSync15, readdirSync as readdirSync5, statSync, chmodSync as chmodSync3, mkdirSync as mkdirSync3 } from "fs";
|
|
3831
3836
|
import { execSync } from "child_process";
|
|
3832
3837
|
import * as p12 from "@clack/prompts";
|
|
3833
3838
|
import chalk13 from "chalk";
|
|
3834
3839
|
async function doctorCommand(options) {
|
|
3835
|
-
const targetDir =
|
|
3840
|
+
const targetDir = resolve12(options.path || ".");
|
|
3836
3841
|
p12.intro(introTitle("Doctor"));
|
|
3837
3842
|
const manifest = readManifest(targetDir);
|
|
3838
3843
|
if (!manifest) {
|
|
@@ -3950,9 +3955,9 @@ function checkManifestFiles(targetDir, manifest) {
|
|
|
3950
3955
|
function checkScriptPermissions(targetDir, manifest) {
|
|
3951
3956
|
const pluginDir = manifest.pluginPath ? join18(targetDir, manifest.pluginPath) : null;
|
|
3952
3957
|
const shFiles = [];
|
|
3953
|
-
if (pluginDir &&
|
|
3958
|
+
if (pluginDir && existsSync15(pluginDir)) {
|
|
3954
3959
|
const scriptsDir = join18(pluginDir, "scripts");
|
|
3955
|
-
if (
|
|
3960
|
+
if (existsSync15(scriptsDir)) {
|
|
3956
3961
|
const entries = readdirSync5(scriptsDir);
|
|
3957
3962
|
for (const entry of entries) {
|
|
3958
3963
|
if (entry.endsWith(".sh")) {
|
|
@@ -4020,7 +4025,7 @@ function checkPluginRegistered(targetDir) {
|
|
|
4020
4025
|
}
|
|
4021
4026
|
function checkHookScripts(targetDir, manifest) {
|
|
4022
4027
|
const pluginDir = manifest.pluginPath ? join18(targetDir, manifest.pluginPath) : null;
|
|
4023
|
-
if (!pluginDir || !
|
|
4028
|
+
if (!pluginDir || !existsSync15(pluginDir)) {
|
|
4024
4029
|
return {
|
|
4025
4030
|
name: "hooks",
|
|
4026
4031
|
status: "pass",
|
|
@@ -4028,7 +4033,7 @@ function checkHookScripts(targetDir, manifest) {
|
|
|
4028
4033
|
};
|
|
4029
4034
|
}
|
|
4030
4035
|
const hooksDir = join18(pluginDir, "hooks");
|
|
4031
|
-
if (!
|
|
4036
|
+
if (!existsSync15(hooksDir)) {
|
|
4032
4037
|
return {
|
|
4033
4038
|
name: "hooks",
|
|
4034
4039
|
status: "pass",
|
|
@@ -4055,7 +4060,7 @@ function checkHookScripts(targetDir, manifest) {
|
|
|
4055
4060
|
""
|
|
4056
4061
|
);
|
|
4057
4062
|
const scriptPath = join18(pluginDir, resolved);
|
|
4058
|
-
if (
|
|
4063
|
+
if (existsSync15(scriptPath)) {
|
|
4059
4064
|
valid++;
|
|
4060
4065
|
}
|
|
4061
4066
|
} else {
|
|
@@ -4106,7 +4111,7 @@ function checkQualityScripts(targetDir) {
|
|
|
4106
4111
|
}
|
|
4107
4112
|
function checkThoughtsDir(targetDir) {
|
|
4108
4113
|
const thoughtsDir = join18(targetDir, "thoughts");
|
|
4109
|
-
if (
|
|
4114
|
+
if (existsSync15(thoughtsDir)) {
|
|
4110
4115
|
return {
|
|
4111
4116
|
name: "thoughts",
|
|
4112
4117
|
status: "pass",
|
|
@@ -4138,7 +4143,7 @@ function checkThoughtsDir(targetDir) {
|
|
|
4138
4143
|
function checkEslint(targetDir) {
|
|
4139
4144
|
try {
|
|
4140
4145
|
const eslintLocal = join18(targetDir, "node_modules", ".bin", "eslint");
|
|
4141
|
-
if (
|
|
4146
|
+
if (existsSync15(eslintLocal)) {
|
|
4142
4147
|
return { name: "eslint", status: "pass", message: "eslint is available" };
|
|
4143
4148
|
}
|
|
4144
4149
|
execSync("which eslint", { stdio: "pipe" });
|
|
@@ -4153,14 +4158,14 @@ function checkEslint(targetDir) {
|
|
|
4153
4158
|
}
|
|
4154
4159
|
|
|
4155
4160
|
// src/commands/uninstall.ts
|
|
4156
|
-
import { existsSync as
|
|
4157
|
-
import { resolve as
|
|
4161
|
+
import { existsSync as existsSync16, rmSync as rmSync2, readdirSync as readdirSync6 } from "fs";
|
|
4162
|
+
import { resolve as resolve13, join as join19, dirname as dirname9 } from "path";
|
|
4158
4163
|
import * as p13 from "@clack/prompts";
|
|
4159
4164
|
import chalk14 from "chalk";
|
|
4160
4165
|
var DEVTRONIC_FILES = ["CLAUDE.md", "AGENTS.md"];
|
|
4161
4166
|
async function uninstallCommand(options) {
|
|
4162
4167
|
ensureInteractive("uninstall");
|
|
4163
|
-
const targetDir =
|
|
4168
|
+
const targetDir = resolve13(options.path || ".");
|
|
4164
4169
|
p13.intro(introTitle("Uninstall"));
|
|
4165
4170
|
const manifest = readManifest(targetDir);
|
|
4166
4171
|
if (!manifest) {
|
|
@@ -4174,8 +4179,8 @@ async function uninstallCommand(options) {
|
|
|
4174
4179
|
const managedFiles = Object.keys(manifest.files);
|
|
4175
4180
|
const existingFiles = managedFiles.filter((f) => fileExists(join19(targetDir, f)));
|
|
4176
4181
|
const missingFiles = managedFiles.filter((f) => !fileExists(join19(targetDir, f)));
|
|
4177
|
-
const hasPlugin = manifest.installMode === "plugin" &&
|
|
4178
|
-
const hasThoughts =
|
|
4182
|
+
const hasPlugin = manifest.installMode === "plugin" && existsSync16(join19(targetDir, PLUGIN_DIR, PLUGIN_NAME));
|
|
4183
|
+
const hasThoughts = existsSync16(join19(targetDir, "thoughts"));
|
|
4179
4184
|
const hasClaudeMd = fileExists(join19(targetDir, "CLAUDE.md"));
|
|
4180
4185
|
const hasAgentsMd = fileExists(join19(targetDir, "AGENTS.md"));
|
|
4181
4186
|
p13.log.info(`Installation found: v${manifest.version} (${manifest.implantedAt})`);
|
|
@@ -4266,12 +4271,12 @@ async function uninstallCommand(options) {
|
|
|
4266
4271
|
rmSync2(join19(targetDir, PLUGIN_DIR, PLUGIN_NAME), { recursive: true, force: true });
|
|
4267
4272
|
removed.push(`${PLUGIN_DIR}/${PLUGIN_NAME}/`);
|
|
4268
4273
|
const marketplaceDescDir = join19(targetDir, PLUGIN_DIR, ".claude-plugin");
|
|
4269
|
-
if (
|
|
4274
|
+
if (existsSync16(marketplaceDescDir)) {
|
|
4270
4275
|
rmSync2(marketplaceDescDir, { recursive: true, force: true });
|
|
4271
4276
|
removed.push(`${PLUGIN_DIR}/.claude-plugin/`);
|
|
4272
4277
|
}
|
|
4273
4278
|
const pluginsDir = join19(targetDir, PLUGIN_DIR);
|
|
4274
|
-
if (
|
|
4279
|
+
if (existsSync16(pluginsDir)) {
|
|
4275
4280
|
const remaining = readdirSafe(pluginsDir);
|
|
4276
4281
|
if (remaining.length === 0) {
|
|
4277
4282
|
rmSync2(pluginsDir, { recursive: true, force: true });
|
|
@@ -4288,10 +4293,10 @@ async function uninstallCommand(options) {
|
|
|
4288
4293
|
if (file.startsWith(PLUGIN_DIR + "/")) continue;
|
|
4289
4294
|
try {
|
|
4290
4295
|
const filePath = join19(targetDir, file);
|
|
4291
|
-
if (
|
|
4296
|
+
if (existsSync16(filePath)) {
|
|
4292
4297
|
rmSync2(filePath, { force: true });
|
|
4293
4298
|
removed.push(file);
|
|
4294
|
-
cleanEmptyParents(targetDir,
|
|
4299
|
+
cleanEmptyParents(targetDir, dirname9(file));
|
|
4295
4300
|
}
|
|
4296
4301
|
} catch (err) {
|
|
4297
4302
|
errors.push(`Failed to remove ${file}: ${err instanceof Error ? err.message : String(err)}`);
|
|
@@ -4335,7 +4340,7 @@ async function uninstallCommand(options) {
|
|
|
4335
4340
|
}
|
|
4336
4341
|
try {
|
|
4337
4342
|
const manifestDir = join19(targetDir, MANIFEST_DIR);
|
|
4338
|
-
if (
|
|
4343
|
+
if (existsSync16(manifestDir)) {
|
|
4339
4344
|
rmSync2(manifestDir, { recursive: true, force: true });
|
|
4340
4345
|
removed.push(`${MANIFEST_DIR}/`);
|
|
4341
4346
|
}
|
|
@@ -4382,12 +4387,12 @@ async function uninstallCommand(options) {
|
|
|
4382
4387
|
function cleanEmptyParents(targetDir, relDir) {
|
|
4383
4388
|
if (!relDir || relDir === ".") return;
|
|
4384
4389
|
const absDir = join19(targetDir, relDir);
|
|
4385
|
-
if (!
|
|
4390
|
+
if (!existsSync16(absDir)) return;
|
|
4386
4391
|
const entries = readdirSafe(absDir);
|
|
4387
4392
|
if (entries.length === 0) {
|
|
4388
4393
|
try {
|
|
4389
4394
|
rmSync2(absDir, { recursive: true, force: true });
|
|
4390
|
-
cleanEmptyParents(targetDir,
|
|
4395
|
+
cleanEmptyParents(targetDir, dirname9(relDir));
|
|
4391
4396
|
} catch {
|
|
4392
4397
|
}
|
|
4393
4398
|
}
|
|
@@ -4401,15 +4406,15 @@ function readdirSafe(dir) {
|
|
|
4401
4406
|
}
|
|
4402
4407
|
|
|
4403
4408
|
// src/commands/addon.ts
|
|
4404
|
-
import { resolve as
|
|
4405
|
-
import { existsSync as
|
|
4409
|
+
import { resolve as resolve14, join as join20, dirname as dirname10 } from "path";
|
|
4410
|
+
import { existsSync as existsSync17, unlinkSync as unlinkSync3, rmSync as rmSync3, readFileSync as readFileSync6 } from "fs";
|
|
4406
4411
|
import * as p14 from "@clack/prompts";
|
|
4407
4412
|
import chalk15 from "chalk";
|
|
4408
4413
|
function isFileBasedAddon(addonName) {
|
|
4409
4414
|
return addonName !== "orchestration";
|
|
4410
4415
|
}
|
|
4411
4416
|
async function addonCommand(action, addonName, options) {
|
|
4412
|
-
const targetDir =
|
|
4417
|
+
const targetDir = resolve14(options.path || ".");
|
|
4413
4418
|
p14.intro(introTitle(`Addon ${action}`));
|
|
4414
4419
|
const validAddons = Object.keys(ADDONS);
|
|
4415
4420
|
if (!validAddons.includes(addonName)) {
|
|
@@ -4483,7 +4488,7 @@ async function addAddon(targetDir, manifest, addonName, currentAddons) {
|
|
|
4483
4488
|
const addedFiles = [];
|
|
4484
4489
|
for (const skillDir of addon.skills) {
|
|
4485
4490
|
const sourceDir = join20(skillsSourceDir, skillDir);
|
|
4486
|
-
if (!
|
|
4491
|
+
if (!existsSync17(sourceDir)) {
|
|
4487
4492
|
spinner8.stop(`Template not found for skill: ${skillDir}`);
|
|
4488
4493
|
p14.log.warn(`Skipping ${skillDir} \u2014 template not found.`);
|
|
4489
4494
|
continue;
|
|
@@ -4493,7 +4498,7 @@ async function addAddon(targetDir, manifest, addonName, currentAddons) {
|
|
|
4493
4498
|
const content = readFile(join20(sourceDir, file));
|
|
4494
4499
|
const destRelPath = join20(pluginRoot, "skills", skillDir, file);
|
|
4495
4500
|
const destAbsPath = join20(targetDir, destRelPath);
|
|
4496
|
-
ensureDir(
|
|
4501
|
+
ensureDir(dirname10(destAbsPath));
|
|
4497
4502
|
writeFile(destAbsPath, content);
|
|
4498
4503
|
manifest.files[destRelPath] = createManifestEntry(content);
|
|
4499
4504
|
addedFiles.push(destRelPath);
|
|
@@ -4542,7 +4547,7 @@ async function removeAddon(targetDir, manifest, addonName, currentAddons) {
|
|
|
4542
4547
|
for (const [filePath, fileInfo] of Object.entries(manifest.files)) {
|
|
4543
4548
|
if (!filePath.startsWith(skillRelBase)) continue;
|
|
4544
4549
|
const absPath = join20(targetDir, filePath);
|
|
4545
|
-
if (!
|
|
4550
|
+
if (!existsSync17(absPath)) continue;
|
|
4546
4551
|
const current = calculateChecksum(readFile(absPath));
|
|
4547
4552
|
if (current !== fileInfo.originalChecksum) {
|
|
4548
4553
|
modifiedFiles.push(filePath);
|
|
@@ -4570,11 +4575,11 @@ async function removeAddon(targetDir, manifest, addonName, currentAddons) {
|
|
|
4570
4575
|
for (const filePath of Object.keys(manifest.files)) {
|
|
4571
4576
|
if (filePath.startsWith(skillRelBase)) {
|
|
4572
4577
|
const absPath = join20(targetDir, filePath);
|
|
4573
|
-
if (
|
|
4578
|
+
if (existsSync17(absPath)) unlinkSync3(absPath);
|
|
4574
4579
|
delete manifest.files[filePath];
|
|
4575
4580
|
}
|
|
4576
4581
|
}
|
|
4577
|
-
if (
|
|
4582
|
+
if (existsSync17(skillAbsDir)) {
|
|
4578
4583
|
try {
|
|
4579
4584
|
rmSync3(skillAbsDir, { recursive: true });
|
|
4580
4585
|
} catch {
|
|
@@ -4685,7 +4690,7 @@ function getAddonListInfo(targetDir) {
|
|
|
4685
4690
|
}));
|
|
4686
4691
|
}
|
|
4687
4692
|
async function addonListCommand(options) {
|
|
4688
|
-
const targetDir =
|
|
4693
|
+
const targetDir = resolve14(options.path || ".");
|
|
4689
4694
|
p14.intro(introTitle("Addon List"));
|
|
4690
4695
|
const items = getAddonListInfo(targetDir);
|
|
4691
4696
|
const lines = items.map((item) => {
|
|
@@ -4698,7 +4703,7 @@ async function addonListCommand(options) {
|
|
|
4698
4703
|
p14.outro(`Use ${chalk15.cyan("devtronic addon add <name>")} to install.`);
|
|
4699
4704
|
}
|
|
4700
4705
|
async function addonSyncCommand(options) {
|
|
4701
|
-
const targetDir =
|
|
4706
|
+
const targetDir = resolve14(options.path || ".");
|
|
4702
4707
|
p14.intro(introTitle("Addon Sync"));
|
|
4703
4708
|
const config = readAddonConfig(targetDir);
|
|
4704
4709
|
const installedNames = Object.keys(config.installed);
|
|
@@ -4739,16 +4744,16 @@ function updateDescriptors(targetDir, manifest, pluginRoot, addonSkillCount) {
|
|
|
4739
4744
|
}
|
|
4740
4745
|
|
|
4741
4746
|
// src/commands/mode.ts
|
|
4742
|
-
import { resolve as
|
|
4743
|
-
import { existsSync as
|
|
4747
|
+
import { resolve as resolve15, join as join21 } from "path";
|
|
4748
|
+
import { existsSync as existsSync18 } from "fs";
|
|
4744
4749
|
import * as p15 from "@clack/prompts";
|
|
4745
4750
|
import chalk16 from "chalk";
|
|
4746
4751
|
async function modeCommand(action, options) {
|
|
4747
|
-
const targetDir =
|
|
4752
|
+
const targetDir = resolve15(options.path || ".");
|
|
4748
4753
|
p15.intro(introTitle("Mode"));
|
|
4749
4754
|
if (action === "show") {
|
|
4750
4755
|
const configPath = join21(targetDir, ".claude", "devtronic.json");
|
|
4751
|
-
const hasConfig =
|
|
4756
|
+
const hasConfig = existsSync18(configPath);
|
|
4752
4757
|
const config = readAddonConfig(targetDir);
|
|
4753
4758
|
const currentMode = config.mode;
|
|
4754
4759
|
const isDefault = !hasConfig || currentMode === void 0;
|