@ian2018cs/agenthub 0.1.85 → 0.1.86
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/package.json +1 -1
- package/server/routes/agents.js +98 -30
package/package.json
CHANGED
package/server/routes/agents.js
CHANGED
|
@@ -868,28 +868,62 @@ router.post('/install', async (req, res) => {
|
|
|
868
868
|
|
|
869
869
|
// Remove skills that existed in old version but are no longer in new version
|
|
870
870
|
const newSkillNames = new Set((agent.skills || []).filter(s => s.name).map(s => s.name));
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
871
|
+
if (prevAgentInfo?.installedSkills?.length > 0) {
|
|
872
|
+
// Precise diff using recorded data
|
|
873
|
+
for (const old of prevAgentInfo.installedSkills) {
|
|
874
|
+
if (!newSkillNames.has(old.name)) {
|
|
875
|
+
try {
|
|
876
|
+
await uninstallSkill(old.name, userUuid, projectDir);
|
|
877
|
+
console.log(`[AgentInstall] Removed old skill "${old.name}" (no longer in agent)`);
|
|
878
|
+
} catch (e) {
|
|
879
|
+
console.warn(`[AgentInstall] Could not remove old skill "${old.name}":`, e.message);
|
|
880
|
+
}
|
|
878
881
|
}
|
|
879
882
|
}
|
|
883
|
+
} else if (prevAgentInfo) {
|
|
884
|
+
// No recorded data — fallback: scan actual skills dir and remove anything not in new agent
|
|
885
|
+
try {
|
|
886
|
+
const skillsDir = path.join(projectDir, '.claude', 'skills');
|
|
887
|
+
const entries = await fs.readdir(skillsDir).catch(() => []);
|
|
888
|
+
for (const name of entries) {
|
|
889
|
+
if (!newSkillNames.has(name)) {
|
|
890
|
+
try {
|
|
891
|
+
await fs.unlink(path.join(skillsDir, name));
|
|
892
|
+
console.log(`[AgentInstall] Removed residual skill "${name}" (fallback cleanup)`);
|
|
893
|
+
} catch (e) {
|
|
894
|
+
console.warn(`[AgentInstall] Could not remove residual skill "${name}":`, e.message);
|
|
895
|
+
}
|
|
896
|
+
}
|
|
897
|
+
}
|
|
898
|
+
} catch {}
|
|
880
899
|
}
|
|
881
900
|
|
|
882
901
|
// Remove MCPs that existed in old version but are no longer in new version
|
|
883
902
|
const newMcpNames = new Set((agent.mcps || []).filter(m => m.name).map(m => m.name));
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
903
|
+
if (prevAgentInfo?.installedMcps?.length > 0) {
|
|
904
|
+
// Precise diff using recorded data (includes exact server keys)
|
|
905
|
+
for (const old of prevAgentInfo.installedMcps) {
|
|
906
|
+
if (!newMcpNames.has(old.name)) {
|
|
907
|
+
try {
|
|
908
|
+
await uninstallMcp(old.keys, userUuid, projectDir);
|
|
909
|
+
console.log(`[AgentInstall] Removed old MCP "${old.name}" (no longer in agent)`);
|
|
910
|
+
} catch (e) {
|
|
911
|
+
console.warn(`[AgentInstall] Could not remove old MCP "${old.name}":`, e.message);
|
|
912
|
+
}
|
|
891
913
|
}
|
|
892
914
|
}
|
|
915
|
+
} else if (prevAgentInfo) {
|
|
916
|
+
// No recorded data — fallback: remove ALL project-scoped MCP keys (will be reinstalled)
|
|
917
|
+
try {
|
|
918
|
+
const userPaths = getUserPaths(userUuid);
|
|
919
|
+
const claudeJsonPath = path.join(userPaths.claudeDir, '.claude.json');
|
|
920
|
+
const claudeConfig = JSON.parse(await fs.readFile(claudeJsonPath, 'utf-8'));
|
|
921
|
+
const projectMcpKeys = Object.keys(claudeConfig.projects?.[projectDir]?.mcpServers || {});
|
|
922
|
+
if (projectMcpKeys.length > 0) {
|
|
923
|
+
await uninstallMcp(projectMcpKeys, userUuid, projectDir);
|
|
924
|
+
console.log(`[AgentInstall] Removed ${projectMcpKeys.length} residual project MCPs (fallback cleanup)`);
|
|
925
|
+
}
|
|
926
|
+
} catch {}
|
|
893
927
|
}
|
|
894
928
|
|
|
895
929
|
// Install skills
|
|
@@ -1853,18 +1887,37 @@ router.post('/submissions/:id/approve', async (req, res) => {
|
|
|
1853
1887
|
|
|
1854
1888
|
// Update skill dependencies
|
|
1855
1889
|
const newSkills = (publishedAgent.skills || []).filter(s => s.name && s.repo);
|
|
1856
|
-
const oldSkills = entry.agentInfo.installedSkills
|
|
1890
|
+
const oldSkills = entry.agentInfo.installedSkills;
|
|
1857
1891
|
const newSkillNames = new Set(newSkills.map(s => s.name));
|
|
1858
1892
|
|
|
1859
|
-
|
|
1860
|
-
|
|
1861
|
-
|
|
1862
|
-
|
|
1863
|
-
|
|
1864
|
-
|
|
1865
|
-
|
|
1893
|
+
if (oldSkills?.length > 0) {
|
|
1894
|
+
// Precise diff using recorded data
|
|
1895
|
+
for (const old of oldSkills) {
|
|
1896
|
+
if (!newSkillNames.has(old.name)) {
|
|
1897
|
+
try {
|
|
1898
|
+
await uninstallSkill(old.name, user.uuid, projectDir);
|
|
1899
|
+
console.log(`[AgentApprove] Removed old skill "${old.name}" for user ${user.uuid}`);
|
|
1900
|
+
} catch (e) {
|
|
1901
|
+
console.warn(`[AgentApprove] Could not remove old skill "${old.name}" for user ${user.uuid}:`, e.message);
|
|
1902
|
+
}
|
|
1866
1903
|
}
|
|
1867
1904
|
}
|
|
1905
|
+
} else {
|
|
1906
|
+
// No recorded data — fallback: scan actual skills dir
|
|
1907
|
+
try {
|
|
1908
|
+
const skillsDir = path.join(projectDir, '.claude', 'skills');
|
|
1909
|
+
const entries = await fs.readdir(skillsDir).catch(() => []);
|
|
1910
|
+
for (const name of entries) {
|
|
1911
|
+
if (!newSkillNames.has(name)) {
|
|
1912
|
+
try {
|
|
1913
|
+
await fs.unlink(path.join(skillsDir, name));
|
|
1914
|
+
console.log(`[AgentApprove] Removed residual skill "${name}" for user ${user.uuid} (fallback cleanup)`);
|
|
1915
|
+
} catch (e) {
|
|
1916
|
+
console.warn(`[AgentApprove] Could not remove residual skill "${name}" for user ${user.uuid}:`, e.message);
|
|
1917
|
+
}
|
|
1918
|
+
}
|
|
1919
|
+
}
|
|
1920
|
+
} catch {}
|
|
1868
1921
|
}
|
|
1869
1922
|
|
|
1870
1923
|
const newInstalledSkills = [];
|
|
@@ -1880,18 +1933,33 @@ router.post('/submissions/:id/approve', async (req, res) => {
|
|
|
1880
1933
|
|
|
1881
1934
|
// Update MCP dependencies
|
|
1882
1935
|
const newMcps = (publishedAgent.mcps || []).filter(m => m.name && m.repo);
|
|
1883
|
-
const oldMcps = entry.agentInfo.installedMcps
|
|
1936
|
+
const oldMcps = entry.agentInfo.installedMcps;
|
|
1884
1937
|
const newMcpNames = new Set(newMcps.map(m => m.name));
|
|
1885
1938
|
|
|
1886
|
-
|
|
1887
|
-
|
|
1888
|
-
|
|
1889
|
-
|
|
1890
|
-
|
|
1891
|
-
|
|
1892
|
-
|
|
1939
|
+
if (oldMcps?.length > 0) {
|
|
1940
|
+
// Precise diff using recorded data (includes exact server keys)
|
|
1941
|
+
for (const old of oldMcps) {
|
|
1942
|
+
if (!newMcpNames.has(old.name)) {
|
|
1943
|
+
try {
|
|
1944
|
+
await uninstallMcp(old.keys, user.uuid, projectDir);
|
|
1945
|
+
console.log(`[AgentApprove] Removed old MCP "${old.name}" for user ${user.uuid}`);
|
|
1946
|
+
} catch (e) {
|
|
1947
|
+
console.warn(`[AgentApprove] Could not remove old MCP "${old.name}" for user ${user.uuid}:`, e.message);
|
|
1948
|
+
}
|
|
1893
1949
|
}
|
|
1894
1950
|
}
|
|
1951
|
+
} else {
|
|
1952
|
+
// No recorded data — fallback: remove ALL project-scoped MCP keys (will be reinstalled)
|
|
1953
|
+
try {
|
|
1954
|
+
const userPaths = getUserPaths(user.uuid);
|
|
1955
|
+
const claudeJsonPath = path.join(userPaths.claudeDir, '.claude.json');
|
|
1956
|
+
const claudeConfig = JSON.parse(await fs.readFile(claudeJsonPath, 'utf-8'));
|
|
1957
|
+
const projectMcpKeys = Object.keys(claudeConfig.projects?.[projectDir]?.mcpServers || {});
|
|
1958
|
+
if (projectMcpKeys.length > 0) {
|
|
1959
|
+
await uninstallMcp(projectMcpKeys, user.uuid, projectDir);
|
|
1960
|
+
console.log(`[AgentApprove] Removed ${projectMcpKeys.length} residual project MCPs for user ${user.uuid} (fallback cleanup)`);
|
|
1961
|
+
}
|
|
1962
|
+
} catch {}
|
|
1895
1963
|
}
|
|
1896
1964
|
|
|
1897
1965
|
const newInstalledMcps = [];
|