obsidian-dev-skills 1.0.0 ā 1.0.2
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/obsidian-dev-plugins/SKILL.md +35 -0
- package/obsidian-dev-plugins/references/agent-dos-donts.md +57 -0
- package/obsidian-dev-plugins/references/code-patterns.md +852 -0
- package/obsidian-dev-plugins/references/coding-conventions.md +21 -0
- package/obsidian-dev-plugins/references/commands-settings.md +24 -0
- package/obsidian-dev-plugins/references/common-tasks.md +429 -0
- package/obsidian-dev-themes/SKILL.md +34 -0
- package/obsidian-dev-themes/references/theme-best-practices.md +50 -0
- package/obsidian-dev-themes/references/theme-coding-conventions.md +45 -0
- package/package.json +11 -3
- package/scripts/init.mjs +134 -0
- package/scripts/setup-local.ps1 +52 -0
package/scripts/init.mjs
ADDED
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import fs from 'fs';
|
|
4
|
+
import path from 'path';
|
|
5
|
+
import { fileURLToPath } from 'url';
|
|
6
|
+
|
|
7
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
8
|
+
const __dirname = path.dirname(__filename);
|
|
9
|
+
|
|
10
|
+
// The package root is one level up from scripts/
|
|
11
|
+
const packageRoot = path.join(__dirname, '..');
|
|
12
|
+
|
|
13
|
+
// Find the real project root where the package is being installed
|
|
14
|
+
function getProjectRoot() {
|
|
15
|
+
// INIT_CWD is set by npm/pnpm/yarn to the directory where the command was run
|
|
16
|
+
if (process.env.INIT_CWD) {
|
|
17
|
+
return process.env.INIT_CWD;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
// Fallback: traverse up from process.cwd() to find the first package.json
|
|
21
|
+
// that isn't the one in this package
|
|
22
|
+
let current = process.cwd();
|
|
23
|
+
while (current !== path.parse(current).root) {
|
|
24
|
+
const pkgPath = path.join(current, 'package.json');
|
|
25
|
+
if (fs.existsSync(pkgPath)) {
|
|
26
|
+
try {
|
|
27
|
+
const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf8'));
|
|
28
|
+
if (pkg.name !== 'obsidian-dev-skills') {
|
|
29
|
+
return current;
|
|
30
|
+
}
|
|
31
|
+
} catch (e) {}
|
|
32
|
+
}
|
|
33
|
+
current = path.dirname(current);
|
|
34
|
+
}
|
|
35
|
+
return process.cwd();
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
const projectRoot = getProjectRoot();
|
|
39
|
+
|
|
40
|
+
let agentDir = path.join(projectRoot, '.agent');
|
|
41
|
+
// If .agents exists but .agent doesn't, use .agents
|
|
42
|
+
if (!fs.existsSync(agentDir) && fs.existsSync(path.join(projectRoot, '.agents'))) {
|
|
43
|
+
agentDir = path.join(projectRoot, '.agents');
|
|
44
|
+
}
|
|
45
|
+
const skillsDir = path.join(agentDir, 'skills');
|
|
46
|
+
|
|
47
|
+
const skillMappings = {
|
|
48
|
+
'obsidian-dev': 'obsidian-dev-plugins',
|
|
49
|
+
'obsidian-theme-dev': 'obsidian-dev-themes',
|
|
50
|
+
'obsidian-ops': 'obsidian-ops',
|
|
51
|
+
'obsidian-ref': 'obsidian-ref'
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
function copyRecursiveSync(src, dest) {
|
|
55
|
+
const exists = fs.existsSync(src);
|
|
56
|
+
const stats = exists && fs.statSync(src);
|
|
57
|
+
const isDirectory = exists && stats.isDirectory();
|
|
58
|
+
if (isDirectory) {
|
|
59
|
+
if (!fs.existsSync(dest)) {
|
|
60
|
+
fs.mkdirSync(dest, { recursive: true });
|
|
61
|
+
}
|
|
62
|
+
fs.readdirSync(src).forEach((childItemName) => {
|
|
63
|
+
copyRecursiveSync(path.join(src, childItemName), path.join(dest, childItemName));
|
|
64
|
+
});
|
|
65
|
+
} else {
|
|
66
|
+
fs.copyFileSync(src, dest);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
async function init() {
|
|
71
|
+
// Determine if we are running in the package's own directory (development)
|
|
72
|
+
const isDevelopment = projectRoot === packageRoot ||
|
|
73
|
+
(fs.existsSync(path.join(packageRoot, 'obsidian-dev-plugins')) &&
|
|
74
|
+
!fs.existsSync(path.join(projectRoot, 'node_modules', 'obsidian-dev-skills')));
|
|
75
|
+
|
|
76
|
+
if (isDevelopment && !process.env.FORCE_INIT) {
|
|
77
|
+
console.log('š ļø Development mode detected (or forced skip), skipping initialization.');
|
|
78
|
+
return;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
console.log(`š Initializing Obsidian Dev Skills in: ${projectRoot}`);
|
|
82
|
+
try {
|
|
83
|
+
// Create .agent/skills directory if it doesn't exist
|
|
84
|
+
if (!fs.existsSync(skillsDir)) {
|
|
85
|
+
console.log(`š Creating directory: ${skillsDir}`);
|
|
86
|
+
fs.mkdirSync(skillsDir, { recursive: true });
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
for (const [targetName, sourceName] of Object.entries(skillMappings)) {
|
|
90
|
+
const sourcePath = path.join(packageRoot, sourceName);
|
|
91
|
+
const targetPath = path.join(skillsDir, targetName);
|
|
92
|
+
|
|
93
|
+
if (fs.existsSync(sourcePath)) {
|
|
94
|
+
console.log(`⨠Copying skill: ${targetName}...`);
|
|
95
|
+
// Remove existing if it exists to ensure fresh copy
|
|
96
|
+
if (fs.existsSync(targetPath)) {
|
|
97
|
+
fs.rmSync(targetPath, { recursive: true, force: true });
|
|
98
|
+
}
|
|
99
|
+
copyRecursiveSync(sourcePath, targetPath);
|
|
100
|
+
} else {
|
|
101
|
+
console.warn(`ā ļø Warning: Source skill not found at ${sourcePath}`);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
// Update or create sync-status.json
|
|
106
|
+
const syncStatusPath = path.join(agentDir, 'sync-status.json');
|
|
107
|
+
const today = new Date().toISOString().split('T')[0];
|
|
108
|
+
|
|
109
|
+
let syncStatus = {
|
|
110
|
+
lastFullSync: today,
|
|
111
|
+
lastSyncSource: 'obsidian-dev-skills initialization'
|
|
112
|
+
};
|
|
113
|
+
|
|
114
|
+
if (fs.existsSync(syncStatusPath)) {
|
|
115
|
+
try {
|
|
116
|
+
const existingStatus = JSON.parse(fs.readFileSync(syncStatusPath, 'utf8'));
|
|
117
|
+
syncStatus = { ...existingStatus, ...syncStatus };
|
|
118
|
+
} catch (e) {
|
|
119
|
+
// Ignore JSON parse errors and overwrite
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
fs.writeFileSync(syncStatusPath, JSON.stringify(syncStatus, null, 2), 'utf8');
|
|
124
|
+
console.log('ā
Updated .agent/sync-status.json');
|
|
125
|
+
|
|
126
|
+
console.log('\nš Successfully installed Obsidian Dev Skills!');
|
|
127
|
+
console.log('Your Cursor agent now has access to specialized Obsidian development knowledge.');
|
|
128
|
+
} catch (error) {
|
|
129
|
+
console.error('ā Error during initialization:', error.message);
|
|
130
|
+
process.exit(1);
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
init();
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
# Setup skills symlinks for Obsidian Sample Plugin Plus
|
|
2
|
+
# This script creates symlinks to the obsidian-dev-skills repository
|
|
3
|
+
|
|
4
|
+
param(
|
|
5
|
+
[string]$SkillsRepoPath = "$PSScriptRoot\..\obsidian-dev-skills"
|
|
6
|
+
)
|
|
7
|
+
|
|
8
|
+
$ErrorActionPreference = "Stop"
|
|
9
|
+
|
|
10
|
+
Write-Host "Setting up skills symlinks..." -ForegroundColor Cyan
|
|
11
|
+
|
|
12
|
+
# Check if skills repo exists
|
|
13
|
+
if (-not (Test-Path $SkillsRepoPath)) {
|
|
14
|
+
Write-Host "Skills repository not found at: $SkillsRepoPath" -ForegroundColor Red
|
|
15
|
+
Write-Host "Please clone obsidian-dev-skills to a sibling directory." -ForegroundColor Yellow
|
|
16
|
+
Write-Host "Example: git clone https://github.com/davidvkimball/obsidian-dev-skills.git obsidian-dev-skills" -ForegroundColor Yellow
|
|
17
|
+
exit 1
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
$skillsDir = "$PSScriptRoot\..\.agent\skills"
|
|
21
|
+
|
|
22
|
+
# Create skills directory if it doesn't exist
|
|
23
|
+
if (-not (Test-Path $skillsDir)) {
|
|
24
|
+
New-Item -ItemType Directory -Path $skillsDir -Force | Out-Null
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
$skills = @("obsidian-dev", "obsidian-ops", "obsidian-ref")
|
|
28
|
+
|
|
29
|
+
foreach ($skill in $skills) {
|
|
30
|
+
$targetPath = Join-Path $skillsDir $skill
|
|
31
|
+
$sourcePath = Join-Path $SkillsRepoPath $skill
|
|
32
|
+
|
|
33
|
+
# Remove existing symlink/directory if it exists
|
|
34
|
+
if (Test-Path $targetPath) {
|
|
35
|
+
$item = Get-Item $targetPath
|
|
36
|
+
if ($item.LinkType -eq "Junction" -or $item.LinkType -eq "SymbolicLink") {
|
|
37
|
+
Remove-Item $targetPath -Force
|
|
38
|
+
} else {
|
|
39
|
+
Remove-Item $targetPath -Recurse -Force
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
# Create symlink
|
|
44
|
+
Write-Host "Creating symlink: $skill" -ForegroundColor Green
|
|
45
|
+
cmd /c mklink /J "$targetPath" "$sourcePath" | Out-Null
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
Write-Host "Skills setup complete!" -ForegroundColor Cyan
|
|
49
|
+
Write-Host "The following skills are now available:" -ForegroundColor Gray
|
|
50
|
+
Write-Host " - obsidian-dev (core development)" -ForegroundColor Gray
|
|
51
|
+
Write-Host " - obsidian-ops (operations & workflows)" -ForegroundColor Gray
|
|
52
|
+
Write-Host " - obsidian-ref (technical references)" -ForegroundColor Gray
|