@vruum/skills
Advanced tools
| { | ||
| "name": "vruum", | ||
| "version": "0.6.44", | ||
| "version": "0.6.45", | ||
| "description": "Vruum AI skills + remote MCP server for B2B GTM teams. Slash commands for outreach triage, engagement triage, pipeline filling, prospect enrichment, and reply diagnosis, paired with the full Vruum MCP tool surface over OAuth 2.1.", | ||
@@ -5,0 +5,0 @@ "author": { |
| { | ||
| "name": "vruum", | ||
| "version": "0.6.44", | ||
| "version": "0.6.45", | ||
| "description": "Vruum AI skills + remote MCP server for B2B GTM teams. Skills for outreach triage, engagement triage, pipeline filling, prospect enrichment, and reply diagnosis, paired with the full Vruum MCP tool surface over OAuth 2.1.", | ||
@@ -5,0 +5,0 @@ "author": { |
+51
-17
@@ -199,2 +199,41 @@ #!/usr/bin/env node | ||
| function pathApiFor(platform) { | ||
| return platform === 'win32' ? path.win32 : path.posix; | ||
| } | ||
| function normalizePathForComparison(value, platform = process.platform) { | ||
| const pathApi = pathApiFor(platform); | ||
| let normalized = pathApi.resolve(value); | ||
| if (platform === 'win32') { | ||
| // Junction readlink results may use a \\?\ namespace prefix and different | ||
| // casing from os.homedir(). Normalize both forms for identity/ownership. | ||
| normalized = pathApi.toNamespacedPath(normalized).toLowerCase(); | ||
| } | ||
| const root = pathApi.parse(normalized).root; | ||
| while (normalized.length > root.length && normalized.endsWith(pathApi.sep)) { | ||
| normalized = normalized.slice(0, -1); | ||
| } | ||
| return normalized; | ||
| } | ||
| function pathsEqual(left, right, platform = process.platform) { | ||
| return normalizePathForComparison(left, platform) | ||
| === normalizePathForComparison(right, platform); | ||
| } | ||
| function pathIsWithin(candidate, root, platform = process.platform) { | ||
| const pathApi = pathApiFor(platform); | ||
| const normalizedCandidate = normalizePathForComparison(candidate, platform); | ||
| const normalizedRoot = normalizePathForComparison(root, platform); | ||
| return normalizedCandidate === normalizedRoot | ||
| || normalizedCandidate.startsWith(normalizedRoot + pathApi.sep); | ||
| } | ||
| function resolveLinkTarget(dst, linkTarget, platform = process.platform) { | ||
| const pathApi = pathApiFor(platform); | ||
| return pathApi.isAbsolute(linkTarget) | ||
| ? pathApi.resolve(linkTarget) | ||
| : pathApi.resolve(pathApi.dirname(dst), linkTarget); | ||
| } | ||
| // A symlink is "ours" if its target resolves into ~/.vruum/skills/. Resolve | ||
@@ -208,6 +247,3 @@ // textually from the readlink string (relative links against the link's own | ||
| function isOurLink(dst, linkTarget) { | ||
| const resolved = path.isAbsolute(linkTarget) | ||
| ? path.resolve(linkTarget) | ||
| : path.resolve(path.dirname(dst), linkTarget); | ||
| return resolved === VRUUM_SKILLS || resolved.startsWith(VRUUM_SKILLS + path.sep); | ||
| return pathIsWithin(resolveLinkTarget(dst, linkTarget), VRUUM_SKILLS); | ||
| } | ||
@@ -219,7 +255,3 @@ | ||
| function isOperatorLink(dst, linkTarget) { | ||
| const resolved = path.isAbsolute(linkTarget) | ||
| ? path.resolve(linkTarget) | ||
| : path.resolve(path.dirname(dst), linkTarget); | ||
| return resolved === VRUUM_OPERATOR_ROOT | ||
| || resolved.startsWith(VRUUM_OPERATOR_ROOT + path.sep); | ||
| return pathIsWithin(resolveLinkTarget(dst, linkTarget), VRUUM_OPERATOR_ROOT); | ||
| } | ||
@@ -303,10 +335,8 @@ | ||
| if (existing?.kind === 'symlink' && existing.target === srcAbs) { | ||
| const resolvedExistingTarget = existing?.kind === 'symlink' | ||
| ? resolveLinkTarget(dst, existing.target) | ||
| : null; | ||
| if (resolvedExistingTarget && pathsEqual(resolvedExistingTarget, srcAbs)) { | ||
| return { name, target, action: 'already-linked' }; | ||
| } | ||
| const resolvedExistingTarget = existing?.kind === 'symlink' | ||
| ? (path.isAbsolute(existing.target) | ||
| ? path.resolve(existing.target) | ||
| : path.resolve(path.dirname(dst), existing.target)) | ||
| : null; | ||
| const operatorSkillIsUsable = resolvedExistingTarget | ||
@@ -337,3 +367,5 @@ && isOperatorLink(dst, existing.target) | ||
| } | ||
| fs.symlinkSync(srcAbs, dst, 'dir'); | ||
| // Windows directory symlinks require Developer Mode or elevation. Directory | ||
| // junctions work for this absolute, same-machine target without either. | ||
| fs.symlinkSync(srcAbs, dst, process.platform === 'win32' ? 'junction' : 'dir'); | ||
| return { name, target, action: existing ? 'relinked' : 'linked' }; | ||
@@ -553,3 +585,3 @@ } | ||
| const linkTarget = fs.readlinkSync(dst); | ||
| const match = linkTarget === srcAbs; | ||
| const match = pathsEqual(resolveLinkTarget(dst, linkTarget), srcAbs); | ||
| console.log(` ${match ? 'installed' : 'other-link'.padEnd(10)} ${skillName}${match ? '' : ` -> ${linkTarget}`}`); | ||
@@ -607,2 +639,4 @@ } else { | ||
| listAvailableSkills, | ||
| pathsEqual, | ||
| pathIsWithin, | ||
| linkSkill, | ||
@@ -609,0 +643,0 @@ isOurLink, |
+3
-4
| { | ||
| "name": "@vruum/skills", | ||
| "version": "0.6.44", | ||
| "version": "0.6.45", | ||
| "description": "Vruum AI skills for Claude Code, Claude Desktop, Codex CLI, and any AI assistant with a skill directory. Slash commands for outreach triage, engagement triage, pipeline filling, prospect enrichment, and reply diagnosis. Pairs with the Vruum MCP server at https://api.vruum.ai/mcp.", | ||
@@ -8,4 +8,3 @@ "license": "MIT", | ||
| "type": "git", | ||
| "url": "https://github.com/vruum-gtm/vruum_ai.git", | ||
| "directory": ".agents" | ||
| "url": "git+https://github.com/vruum-gtm/skills.git" | ||
| }, | ||
@@ -46,3 +45,3 @@ "homepage": "https://vruum.ai", | ||
| ], | ||
| "contentHash": "dd7363b37525cb10ffce653db525fa540f3877c2fa6e72727e26b6c56e041df3" | ||
| "contentHash": "843a119196d95663bc210d5543eb53a5f48a2a2780d425afce7c713577d4b1ac" | ||
| } |
353272
0.39%1297
2.29%