@ytspar/sweetlink 1.10.0 → 1.11.0
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/README.md +32 -23
- package/claude-skills/screenshot/SKILL.md +381 -0
- package/dist/browser/commands/outline.js.map +1 -1
- package/dist/browser/commands/screenshot.d.ts.map +1 -1
- package/dist/browser/commands/screenshot.js +21 -3
- package/dist/browser/commands/screenshot.js.map +1 -1
- package/dist/browser.js +2 -3
- package/dist/browser.js.map +1 -1
- package/dist/cdp.d.ts +1 -1
- package/dist/cdp.d.ts.map +1 -1
- package/dist/cdp.js +1 -1
- package/dist/cdp.js.map +1 -1
- package/dist/cli/sweetlink.js +390 -244
- package/dist/cli/sweetlink.js.map +1 -1
- package/dist/playwright.js.map +1 -1
- package/dist/server/index.js.map +1 -1
- package/dist/viewportUtils.js.map +1 -1
- package/package.json +12 -3
- package/scripts/setup-claude-context.mjs +93 -68
|
@@ -1,14 +1,17 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
/**
|
|
3
|
-
* Setup script to symlink shared Claude context
|
|
3
|
+
* Setup script to symlink shared Claude context and skills to the consuming project.
|
|
4
4
|
*
|
|
5
|
-
*
|
|
6
|
-
* .claude/context/ directory to the shared context files in this package.
|
|
5
|
+
* Can be run directly (`node scripts/setup-claude-context.mjs`) or via CLI (`pnpm sweetlink setup`).
|
|
7
6
|
*
|
|
8
|
-
*
|
|
7
|
+
* Creates relative symlinks so they work across different environments.
|
|
8
|
+
*
|
|
9
|
+
* What gets linked:
|
|
10
|
+
* - .claude/context/ ← context files from this package's claude-context/
|
|
11
|
+
* - .claude/skills/ ← skill directories from this package's claude-skills/
|
|
9
12
|
*/
|
|
10
13
|
|
|
11
|
-
import { existsSync, mkdirSync, readlinkSync, symlinkSync, unlinkSync } from 'fs';
|
|
14
|
+
import { existsSync, lstatSync, mkdirSync, readdirSync, readlinkSync, symlinkSync, unlinkSync } from 'fs';
|
|
12
15
|
import { dirname, join, relative } from 'path';
|
|
13
16
|
import { fileURLToPath } from 'url';
|
|
14
17
|
|
|
@@ -20,82 +23,104 @@ const packageRoot = join(__dirname, '..');
|
|
|
20
23
|
const nodeModules = join(packageRoot, '..', '..', '..');
|
|
21
24
|
const projectRoot = join(nodeModules, '..');
|
|
22
25
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
const filesToLink = [
|
|
31
|
-
'ui-verification-mandate.md',
|
|
32
|
-
'debugging-protocol.md',
|
|
33
|
-
'sweetlink-architecture.md',
|
|
34
|
-
'component-development-guide.md',
|
|
35
|
-
];
|
|
26
|
+
/**
|
|
27
|
+
* Create a relative symlink, skipping if already correct.
|
|
28
|
+
* Won't overwrite non-symlink files.
|
|
29
|
+
*/
|
|
30
|
+
function linkOne(sourcePath, targetPath, label) {
|
|
31
|
+
const targetDir = dirname(targetPath);
|
|
32
|
+
const relativePath = relative(targetDir, sourcePath);
|
|
36
33
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
34
|
+
if (existsSync(targetPath) || lstatSync(targetPath, { throwIfNoEntry: false })) {
|
|
35
|
+
try {
|
|
36
|
+
const currentLink = readlinkSync(targetPath);
|
|
37
|
+
if (currentLink === relativePath) {
|
|
38
|
+
return; // Already correct
|
|
39
|
+
}
|
|
40
|
+
// Remove incorrect symlink
|
|
41
|
+
unlinkSync(targetPath);
|
|
42
|
+
} catch {
|
|
43
|
+
// Not a symlink — don't overwrite user's files
|
|
44
|
+
console.log(` [skip] ${label} — file exists (not a symlink)`);
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
41
47
|
}
|
|
42
48
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
49
|
+
try {
|
|
50
|
+
symlinkSync(relativePath, targetPath);
|
|
51
|
+
console.log(` [link] ${label}`);
|
|
52
|
+
} catch (err) {
|
|
53
|
+
console.error(` [error] ${label} — ${err.message}`);
|
|
47
54
|
}
|
|
55
|
+
}
|
|
48
56
|
|
|
49
|
-
|
|
50
|
-
const
|
|
51
|
-
if (!existsSync(
|
|
52
|
-
// Not a Claude Code project, skip silently
|
|
53
|
-
return;
|
|
54
|
-
}
|
|
57
|
+
function setupContext(claudeDir) {
|
|
58
|
+
const sourceDir = join(packageRoot, 'claude-context');
|
|
59
|
+
if (!existsSync(sourceDir)) return;
|
|
55
60
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
61
|
+
const targetDir = join(claudeDir, 'context');
|
|
62
|
+
mkdirSync(targetDir, { recursive: true });
|
|
63
|
+
|
|
64
|
+
const files = readdirSync(sourceDir).filter(f => f.endsWith('.md'));
|
|
65
|
+
if (files.length === 0) return;
|
|
60
66
|
|
|
61
67
|
console.log('[@ytspar/sweetlink] Setting up Claude context symlinks...');
|
|
68
|
+
for (const file of files) {
|
|
69
|
+
linkOne(join(sourceDir, file), join(targetDir, file), file);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
62
72
|
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
73
|
+
function setupSkills(claudeDir) {
|
|
74
|
+
const sourceDir = join(packageRoot, 'claude-skills');
|
|
75
|
+
if (!existsSync(sourceDir)) return;
|
|
66
76
|
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
continue;
|
|
70
|
-
}
|
|
77
|
+
const targetDir = join(claudeDir, 'skills');
|
|
78
|
+
mkdirSync(targetDir, { recursive: true });
|
|
71
79
|
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
if (existsSync(targetPath)) {
|
|
77
|
-
try {
|
|
78
|
-
const currentLink = readlinkSync(targetPath);
|
|
79
|
-
if (currentLink === relativePath) {
|
|
80
|
-
continue; // Already correct
|
|
81
|
-
}
|
|
82
|
-
// Remove incorrect symlink
|
|
83
|
-
unlinkSync(targetPath);
|
|
84
|
-
} catch {
|
|
85
|
-
// Not a symlink - don't overwrite user's files
|
|
86
|
-
console.log(` [skip] ${file} - file exists (not a symlink)`);
|
|
87
|
-
continue;
|
|
88
|
-
}
|
|
89
|
-
}
|
|
80
|
+
// Each subdirectory in claude-skills/ is a skill
|
|
81
|
+
const skills = readdirSync(sourceDir, { withFileTypes: true })
|
|
82
|
+
.filter(d => d.isDirectory())
|
|
83
|
+
.map(d => d.name);
|
|
90
84
|
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
85
|
+
if (skills.length === 0) return;
|
|
86
|
+
|
|
87
|
+
console.log('[@ytspar/sweetlink] Setting up Claude skill symlinks...');
|
|
88
|
+
|
|
89
|
+
// If .claude/skills is itself a symlink (e.g. to a shared tools repo),
|
|
90
|
+
// we can't add entries inside it. Warn and provide instructions.
|
|
91
|
+
try {
|
|
92
|
+
const stat = lstatSync(targetDir);
|
|
93
|
+
if (stat.isSymbolicLink()) {
|
|
94
|
+
const linkTarget = readlinkSync(targetDir);
|
|
95
|
+
console.log(` [info] .claude/skills is a symlink → ${linkTarget}`);
|
|
96
|
+
console.log(` [info] Skills from @ytspar/sweetlink should be symlinked inside that directory.`);
|
|
97
|
+
console.log(` [info] Run: cd ${linkTarget} && ln -sf ${relative(linkTarget, sourceDir)}/<skill> .`);
|
|
98
|
+
return;
|
|
97
99
|
}
|
|
100
|
+
} catch {
|
|
101
|
+
// Doesn't exist yet, will be created above
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
for (const skill of skills) {
|
|
105
|
+
linkOne(join(sourceDir, skill), join(targetDir, skill), `skills/${skill}`);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
function setup() {
|
|
110
|
+
// Skip if running inside the devbar repo itself (development)
|
|
111
|
+
if (projectRoot.includes('ytspar/devbar')) {
|
|
112
|
+
console.log('[@ytspar/sweetlink] Skipping setup (running inside devbar repo)');
|
|
113
|
+
return;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
const claudeDir = join(projectRoot, '.claude');
|
|
117
|
+
if (!existsSync(claudeDir)) {
|
|
118
|
+
// Not a Claude Code project, skip silently
|
|
119
|
+
return;
|
|
98
120
|
}
|
|
121
|
+
|
|
122
|
+
setupContext(claudeDir);
|
|
123
|
+
setupSkills(claudeDir);
|
|
99
124
|
}
|
|
100
125
|
|
|
101
|
-
|
|
126
|
+
setup();
|