@allanpk716/work-skills-setup 0.1.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/bin/setup.js +10 -0
- package/package.json +38 -0
- package/src/cli.js +44 -0
- package/src/configurators/git-ssh.js +84 -0
- package/src/configurators/git-user.js +78 -0
- package/src/configurators/index.js +78 -0
- package/src/configurators/pushover.js +195 -0
- package/src/detectors/git.js +37 -0
- package/src/detectors/index.js +56 -0
- package/src/detectors/pip-package.js +43 -0
- package/src/detectors/python.js +48 -0
- package/src/detectors/ssh-tools.js +94 -0
- package/src/i18n/en.json +112 -0
- package/src/i18n/index.js +70 -0
- package/src/i18n/zh.json +112 -0
- package/src/index.js +61 -0
- package/src/installers/index.js +92 -0
- package/src/installers/pip-installer.js +63 -0
- package/src/marketplace/config-manager.js +87 -0
- package/src/marketplace/index.js +157 -0
- package/src/marketplace/plugin-discovery.js +68 -0
- package/src/marketplace/plugin-installer.js +144 -0
- package/src/platform.js +34 -0
- package/src/verification/formatter.js +64 -0
- package/src/verification/index.js +79 -0
- package/src/verification/parser.js +53 -0
- package/src/verification/runner.js +72 -0
- package/src/welcome.js +50 -0
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const execa = require('execa');
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Detect Python installation and version
|
|
7
|
+
* @returns {Promise<{name: string, installed: boolean, version: string|null, meetsMinimum: boolean, command: string|null, guidance: string}>}
|
|
8
|
+
*/
|
|
9
|
+
async function detectPython() {
|
|
10
|
+
const commands = ['python', 'python3', 'py'];
|
|
11
|
+
|
|
12
|
+
for (const cmd of commands) {
|
|
13
|
+
try {
|
|
14
|
+
const { stdout } = await execa(cmd, ['--version'], { reject: false });
|
|
15
|
+
|
|
16
|
+
if (stdout && stdout.includes('Python')) {
|
|
17
|
+
const versionMatch = stdout.match(/Python (\d+\.\d+\.\d+)/i);
|
|
18
|
+
|
|
19
|
+
if (versionMatch) {
|
|
20
|
+
const version = versionMatch[1];
|
|
21
|
+
const [major, minor] = version.split('.').map(Number);
|
|
22
|
+
|
|
23
|
+
return {
|
|
24
|
+
name: 'Python',
|
|
25
|
+
command: cmd,
|
|
26
|
+
installed: true,
|
|
27
|
+
version,
|
|
28
|
+
meetsMinimum: major > 3 || (major === 3 && minor >= 8),
|
|
29
|
+
guidance: 'guidance.installPython'
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
} catch {
|
|
34
|
+
// Try next command
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
return {
|
|
39
|
+
name: 'Python',
|
|
40
|
+
command: null,
|
|
41
|
+
installed: false,
|
|
42
|
+
version: null,
|
|
43
|
+
meetsMinimum: false,
|
|
44
|
+
guidance: 'guidance.installPython'
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
module.exports = { detectPython };
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SSH Tools Detector
|
|
3
|
+
* Detects TortoiseGit and PuTTY via Windows registry
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
const Registry = require('winreg');
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Check if TortoiseGit is installed via registry
|
|
10
|
+
* @returns {Promise<{installed: boolean}>}
|
|
11
|
+
*/
|
|
12
|
+
async function detectTortoiseGit() {
|
|
13
|
+
return new Promise((resolve) => {
|
|
14
|
+
const regKey = new Registry({
|
|
15
|
+
hive: Registry.HKLM,
|
|
16
|
+
key: '\\Software\\TortoiseGit'
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
regKey.valueExists('', (err, exists) => {
|
|
20
|
+
if (err || !exists) {
|
|
21
|
+
// Try 32-bit path on 64-bit Windows
|
|
22
|
+
const regKey32 = new Registry({
|
|
23
|
+
hive: Registry.HKLM,
|
|
24
|
+
key: '\\Software\\Wow6432Node\\TortoiseGit'
|
|
25
|
+
});
|
|
26
|
+
regKey32.valueExists('', (err2, exists2) => {
|
|
27
|
+
resolve({ installed: !err2 && exists2 });
|
|
28
|
+
});
|
|
29
|
+
} else {
|
|
30
|
+
resolve({ installed: true });
|
|
31
|
+
}
|
|
32
|
+
});
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Check if PuTTY is installed via registry
|
|
38
|
+
* @returns {Promise<{installed: boolean}>}
|
|
39
|
+
*/
|
|
40
|
+
async function detectPuTTY() {
|
|
41
|
+
return new Promise((resolve) => {
|
|
42
|
+
const regKey = new Registry({
|
|
43
|
+
hive: Registry.HKCU,
|
|
44
|
+
key: '\\Software\\SimonTatham\\PuTTY'
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
regKey.keyExists((err, exists) => {
|
|
48
|
+
resolve({ installed: !err && exists });
|
|
49
|
+
});
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Check if any SSH tool (TortoiseGit or PuTTY) is installed
|
|
55
|
+
* @returns {Promise<{name: string, installed: boolean, version: null, meetsMinimum: boolean, details: object, message: string, guidance: string}>}
|
|
56
|
+
*/
|
|
57
|
+
async function detectSSHTools() {
|
|
58
|
+
const [tortoiseGit, putty] = await Promise.all([
|
|
59
|
+
detectTortoiseGit(),
|
|
60
|
+
detectPuTTY()
|
|
61
|
+
]);
|
|
62
|
+
|
|
63
|
+
const installed = tortoiseGit.installed || putty.installed;
|
|
64
|
+
|
|
65
|
+
let message;
|
|
66
|
+
if (tortoiseGit.installed && putty.installed) {
|
|
67
|
+
message = 'Both TortoiseGit and PuTTY installed';
|
|
68
|
+
} else if (tortoiseGit.installed) {
|
|
69
|
+
message = 'TortoiseGit installed';
|
|
70
|
+
} else if (putty.installed) {
|
|
71
|
+
message = 'PuTTY installed';
|
|
72
|
+
} else {
|
|
73
|
+
message = 'Neither TortoiseGit nor PuTTY found';
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
return {
|
|
77
|
+
name: 'SSH Tools',
|
|
78
|
+
installed,
|
|
79
|
+
version: null,
|
|
80
|
+
meetsMinimum: installed,
|
|
81
|
+
details: {
|
|
82
|
+
tortoiseGit: tortoiseGit.installed,
|
|
83
|
+
putty: putty.installed
|
|
84
|
+
},
|
|
85
|
+
message,
|
|
86
|
+
guidance: installed ? null : 'guidance.installSSHTools'
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
module.exports = {
|
|
91
|
+
detectSSHTools,
|
|
92
|
+
detectTortoiseGit,
|
|
93
|
+
detectPuTTY
|
|
94
|
+
};
|
package/src/i18n/en.json
ADDED
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
{
|
|
2
|
+
"welcome.title": "Work Skills Setup",
|
|
3
|
+
"welcome.subtitle": "Claude Code skills installer for Windows developers",
|
|
4
|
+
"welcome.version": "Version",
|
|
5
|
+
"welcome.features": "Features",
|
|
6
|
+
"welcome.feature1": "Auto-configure environment",
|
|
7
|
+
"welcome.feature2": "Install required dependencies",
|
|
8
|
+
"welcome.feature3": "Setup Claude Code integration",
|
|
9
|
+
"error.windowsOnly": "This installer is designed for Windows only.",
|
|
10
|
+
"error.currentPlatform": "Current platform",
|
|
11
|
+
"cli.help.language": "Language (en/zh)",
|
|
12
|
+
"cli.help.noColor": "Disable colored output",
|
|
13
|
+
"detection.title": "Environment Detection",
|
|
14
|
+
"detection.checking": "Checking environment dependencies...",
|
|
15
|
+
"detection.summary": "Detection complete: {passed}/{total} passed",
|
|
16
|
+
"guidance.installPython": "Install Python 3.8+ from https://www.python.org/downloads/",
|
|
17
|
+
"guidance.installGit": "Install Git from https://git-scm.com/download/win",
|
|
18
|
+
"guidance.installTortoiseGit": "Install TortoiseGit from https://tortoisegit.org/download/",
|
|
19
|
+
"guidance.installPuTTY": "Install PuTTY from https://www.putty.org/",
|
|
20
|
+
"guidance.installSSHTools": "Install TortoiseGit or PuTTY for SSH authentication",
|
|
21
|
+
"guidance.installRequests": "Run: pip install requests",
|
|
22
|
+
"ssh.tortoiseGitFound": "TortoiseGit installed",
|
|
23
|
+
"ssh.puttyFound": "PuTTY installed",
|
|
24
|
+
"ssh.noneFound": "Neither TortoiseGit nor PuTTY found",
|
|
25
|
+
"install.missingFound": "Found {count} missing Python package(s):",
|
|
26
|
+
"install.promptInstall": "Install {package}?",
|
|
27
|
+
"install.installing": "Installing {package}...",
|
|
28
|
+
"install.success": "{package} installed successfully",
|
|
29
|
+
"install.failed": "Failed to install {package}",
|
|
30
|
+
"install.summary": "Installation Summary:",
|
|
31
|
+
"install.installed": "Installed",
|
|
32
|
+
"install.skipped": "Skipped",
|
|
33
|
+
"guidance.installPermission": "Run Command Prompt as Administrator, or use: pip install {package} --user",
|
|
34
|
+
"guidance.installNetwork": "Check your internet connection and try again",
|
|
35
|
+
"guidance.installPipNotFound": "pip not found. Reinstall Python with pip included",
|
|
36
|
+
"guidance.installUnknown": "Manual install: pip install {package}",
|
|
37
|
+
"config.summary": "Configuration Summary",
|
|
38
|
+
"config.status.configured": "Configured",
|
|
39
|
+
"config.status.skipped": "Skipped",
|
|
40
|
+
"config.status.failed": "Failed",
|
|
41
|
+
"config.section.pushover": "Pushover Notifications",
|
|
42
|
+
"config.section.gitSSH": "Git SSH Configuration",
|
|
43
|
+
"config.section.gitUser": "Git User Information",
|
|
44
|
+
"pushover.alreadyConfigured": "Pushover credentials already configured",
|
|
45
|
+
"pushover.promptReconfigure": "Reconfigure Pushover credentials?",
|
|
46
|
+
"pushover.promptConfigure": "Configure Pushover notifications?",
|
|
47
|
+
"pushover.promptToken": "Enter your Pushover application token:",
|
|
48
|
+
"pushover.promptUser": "Enter your Pushover user key:",
|
|
49
|
+
"pushover.validating": "Validating Pushover credentials...",
|
|
50
|
+
"pushover.validationFailed": "Pushover validation failed",
|
|
51
|
+
"pushover.retryPrompt": "Retry ({attempt}/{max})",
|
|
52
|
+
"pushover.saving": "Saving Pushover credentials...",
|
|
53
|
+
"pushover.saveFailed": "Failed to save Pushover credentials",
|
|
54
|
+
"pushover.configured": "Pushover configured successfully",
|
|
55
|
+
"pushover.currentSessionSet": "✓ Environment variables set for current session (immediate effect)",
|
|
56
|
+
"pushover.skipped": "Pushover configuration skipped",
|
|
57
|
+
"pushover.restartReminder": "Note: Restart your terminal for environment variables to persist in future sessions",
|
|
58
|
+
"guidance.pushoverManual": "Manually set environment variables:\n setx PUSHOVER_TOKEN \"your-token\"\n setx PUSHOVER_USER \"your-user\"",
|
|
59
|
+
"gitSSH.configured": "Git SSH is configured",
|
|
60
|
+
"gitSSH.notConfigured": "Git SSH is not configured",
|
|
61
|
+
"gitSSH.recommended": "SSH is recommended for Git remote operations",
|
|
62
|
+
"gitSSH.guidance": "Configuration steps:",
|
|
63
|
+
"gitSSH.step1": "1. Install TortoiseGit (includes Pageant)",
|
|
64
|
+
"gitSSH.step2": "2. Generate SSH key (e.g., using PuTTYgen)",
|
|
65
|
+
"gitSSH.step3": "3. Add public key to remote repository (GitHub/GitLab)",
|
|
66
|
+
"gitSSH.step4": "4. Configure Git to use TortoiseGit SSH:",
|
|
67
|
+
"gitSSH.command": " git config --global core.sshCommand \"C:/Program Files/TortoiseGit/bin/TortoisePlink.exe\"",
|
|
68
|
+
"gitSSH.docs": "Documentation: https://work-skills.example.com/docs/git-ssh-setup",
|
|
69
|
+
"gitSSH.promptSkip": "Skip Git SSH configuration? (You can use HTTPS instead)",
|
|
70
|
+
"gitSSH.skipped": "Git SSH configuration skipped",
|
|
71
|
+
"gitUser.alreadyConfigured": "Git user information already configured",
|
|
72
|
+
"gitUser.required": "Git user information is required for commits",
|
|
73
|
+
"gitUser.promptName": "Enter your Git username (for commits):",
|
|
74
|
+
"gitUser.promptEmail": "Enter your Git email address:",
|
|
75
|
+
"gitUser.configured": "Git user information configured",
|
|
76
|
+
"gitUser.failed": "Failed to configure Git user information",
|
|
77
|
+
"marketplace.title": "Plugin Marketplace",
|
|
78
|
+
"marketplace.registering": "Registering work-skills marketplace source...",
|
|
79
|
+
"marketplace.registered": "Marketplace source 'work-skills' added successfully",
|
|
80
|
+
"marketplace.fetching": "Fetching available plugins...",
|
|
81
|
+
"marketplace.available": "Available Plugins:",
|
|
82
|
+
"marketplace.select_plugins": "Which plugins would you like to install?",
|
|
83
|
+
"marketplace.none_selected": "No plugins selected. You can install them later.",
|
|
84
|
+
"marketplace.checking": "Checking installed plugins...",
|
|
85
|
+
"marketplace.already_installed": "{name} (already installed, will skip)",
|
|
86
|
+
"marketplace.installing": "Installing {name}...",
|
|
87
|
+
"marketplace.install_success": "{name} installed successfully",
|
|
88
|
+
"marketplace.install_skipped": "{name} skipped (already installed)",
|
|
89
|
+
"marketplace.install_failed": "{name} installation failed",
|
|
90
|
+
"marketplace.summary": "Plugin Installation Summary:",
|
|
91
|
+
"marketplace.summary_installed": "Installed: {count}",
|
|
92
|
+
"marketplace.summary_skipped": "Skipped: {count}",
|
|
93
|
+
"marketplace.summary_failed": "Failed: {count}",
|
|
94
|
+
"marketplace.complete": "Plugin installation complete. Run Claude Code to use them.",
|
|
95
|
+
"marketplace.error.network": "Failed to fetch plugin list. Check your network connection.",
|
|
96
|
+
"marketplace.error.git": "Git is required to install plugins.",
|
|
97
|
+
"marketplace.error.unknown": "An error occurred during marketplace integration.",
|
|
98
|
+
"installation.complete": "=== Installation Complete ===",
|
|
99
|
+
"installation.verificationStarting": "Running verification to check your setup...",
|
|
100
|
+
"verification.title": "Installation Verification",
|
|
101
|
+
"verification.summary": "Summary: {passed}/{total} checks passed",
|
|
102
|
+
"verification.rerunCommand": "To re-run verification: npx github:allanpk716/work-skills#main --verify",
|
|
103
|
+
"verification.error.pythonNotFound": "Error: Python is required for verification",
|
|
104
|
+
"verification.error.scriptNotFound": "Error: Verification script not found",
|
|
105
|
+
"verification.error.timeout": "Error: Verification timeout (30s)",
|
|
106
|
+
"verification.error.executionFailed": "Error: Verification failed",
|
|
107
|
+
"verification.nextSteps": "Next Steps",
|
|
108
|
+
"verification.nextStep1": "1. If this is your first time: Close and reopen your terminal",
|
|
109
|
+
"verification.nextStep2": "2. Start Claude Code in any project directory",
|
|
110
|
+
"verification.nextStep3": "3. Available skills: /windows-git-commit, /notify-test",
|
|
111
|
+
"verification.nextStep4": "4. Or just say: 'Use windows-git-commit to commit my changes'"
|
|
112
|
+
}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const en = require('./en.json');
|
|
4
|
+
const zh = require('./zh.json');
|
|
5
|
+
|
|
6
|
+
const translations = { en, zh };
|
|
7
|
+
|
|
8
|
+
let currentLang = null;
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Detect system language
|
|
12
|
+
* @returns {'en'|'zh'}
|
|
13
|
+
*/
|
|
14
|
+
function detectLanguage() {
|
|
15
|
+
const langEnv = process.env.LANG || process.env.LC_ALL || '';
|
|
16
|
+
const languageEnv = process.env.LANGUAGE || '';
|
|
17
|
+
const lcCtype = process.env.LC_CTYPE || '';
|
|
18
|
+
|
|
19
|
+
// Check for Chinese language environment
|
|
20
|
+
if (langEnv.toLowerCase().startsWith('zh') ||
|
|
21
|
+
languageEnv.toLowerCase().includes('zh') ||
|
|
22
|
+
lcCtype.toLowerCase().startsWith('zh')) {
|
|
23
|
+
return 'zh';
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
return 'en';
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Get current language (auto-detect or manually set)
|
|
31
|
+
* @returns {'en'|'zh'}
|
|
32
|
+
*/
|
|
33
|
+
function getLanguage() {
|
|
34
|
+
return currentLang || detectLanguage();
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Set language manually (overrides auto-detection)
|
|
39
|
+
* @param {'en'|'zh'|null} lang
|
|
40
|
+
*/
|
|
41
|
+
function setLanguage(lang) {
|
|
42
|
+
if (lang === 'en' || lang === 'zh' || lang === null) {
|
|
43
|
+
currentLang = lang;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Translate a key
|
|
49
|
+
* @param {string} key - Translation key
|
|
50
|
+
* @param {Object} params - Parameters to replace in translation string
|
|
51
|
+
* @returns {string} - Translated string with parameters replaced
|
|
52
|
+
*/
|
|
53
|
+
function t(key, params = {}) {
|
|
54
|
+
const lang = getLanguage();
|
|
55
|
+
let translation = translations[lang]?.[key] || translations['en'][key] || key;
|
|
56
|
+
|
|
57
|
+
// Replace {param} with actual values
|
|
58
|
+
Object.keys(params).forEach(param => {
|
|
59
|
+
translation = translation.replace(new RegExp(`\\{${param}\\}`, 'g'), params[param]);
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
return translation;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
module.exports = {
|
|
66
|
+
t,
|
|
67
|
+
detectLanguage,
|
|
68
|
+
getLanguage,
|
|
69
|
+
setLanguage
|
|
70
|
+
};
|
package/src/i18n/zh.json
ADDED
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
{
|
|
2
|
+
"welcome.title": "Work Skills 安装器",
|
|
3
|
+
"welcome.subtitle": "为 Windows 开发者准备的 Claude Code 技能安装工具",
|
|
4
|
+
"welcome.version": "版本",
|
|
5
|
+
"welcome.features": "功能特性",
|
|
6
|
+
"welcome.feature1": "自动配置环境",
|
|
7
|
+
"welcome.feature2": "安装必需依赖",
|
|
8
|
+
"welcome.feature3": "配置 Claude Code 集成",
|
|
9
|
+
"error.windowsOnly": "此安装器仅支持 Windows 系统。",
|
|
10
|
+
"error.currentPlatform": "当前系统",
|
|
11
|
+
"cli.help.language": "语言 (en/zh)",
|
|
12
|
+
"cli.help.noColor": "禁用彩色输出",
|
|
13
|
+
"detection.title": "环境检测",
|
|
14
|
+
"detection.checking": "正在检查环境依赖...",
|
|
15
|
+
"detection.summary": "检测完成: {passed}/{total} 项通过",
|
|
16
|
+
"guidance.installPython": "从 https://www.python.org/downloads/ 安装 Python 3.8+",
|
|
17
|
+
"guidance.installGit": "从 https://git-scm.com/download/win 安装 Git",
|
|
18
|
+
"guidance.installTortoiseGit": "从 https://tortoisegit.org/download/ 安装 TortoiseGit",
|
|
19
|
+
"guidance.installPuTTY": "从 https://www.putty.org/ 安装 PuTTY",
|
|
20
|
+
"guidance.installSSHTools": "安装 TortoiseGit 或 PuTTY 用于 SSH 认证",
|
|
21
|
+
"guidance.installRequests": "运行: pip install requests",
|
|
22
|
+
"ssh.tortoiseGitFound": "已安装 TortoiseGit",
|
|
23
|
+
"ssh.puttyFound": "已安装 PuTTY",
|
|
24
|
+
"ssh.noneFound": "未找到 TortoiseGit 或 PuTTY",
|
|
25
|
+
"install.missingFound": "发现 {count} 个缺失的 Python 包:",
|
|
26
|
+
"install.promptInstall": "是否安装 {package}?",
|
|
27
|
+
"install.installing": "正在安装 {package}...",
|
|
28
|
+
"install.success": "{package} 安装成功",
|
|
29
|
+
"install.failed": "{package} 安装失败",
|
|
30
|
+
"install.summary": "安装摘要:",
|
|
31
|
+
"install.installed": "已安装",
|
|
32
|
+
"install.skipped": "已跳过",
|
|
33
|
+
"guidance.installPermission": "以管理员身份运行命令提示符,或使用: pip install {package} --user",
|
|
34
|
+
"guidance.installNetwork": "请检查网络连接后重试",
|
|
35
|
+
"guidance.installPipNotFound": "pip 未找到。请重新安装包含 pip 的 Python",
|
|
36
|
+
"guidance.installUnknown": "手动安装: pip install {package}",
|
|
37
|
+
"config.summary": "配置摘要",
|
|
38
|
+
"config.status.configured": "已配置",
|
|
39
|
+
"config.status.skipped": "已跳过",
|
|
40
|
+
"config.status.failed": "失败",
|
|
41
|
+
"config.section.pushover": "Pushover 通知",
|
|
42
|
+
"config.section.gitSSH": "Git SSH 配置",
|
|
43
|
+
"config.section.gitUser": "Git 用户信息",
|
|
44
|
+
"pushover.alreadyConfigured": "Pushover 凭证已配置",
|
|
45
|
+
"pushover.promptReconfigure": "是否重新配置 Pushover 凭证?",
|
|
46
|
+
"pushover.promptConfigure": "是否配置 Pushover 通知?",
|
|
47
|
+
"pushover.promptToken": "请输入 Pushover 应用 token:",
|
|
48
|
+
"pushover.promptUser": "请输入 Pushover 用户 key:",
|
|
49
|
+
"pushover.validating": "正在验证 Pushover 凭证...",
|
|
50
|
+
"pushover.validationFailed": "Pushover 验证失败",
|
|
51
|
+
"pushover.retryPrompt": "重试 ({attempt}/{max})",
|
|
52
|
+
"pushover.saving": "正在保存 Pushover 凭证...",
|
|
53
|
+
"pushover.saveFailed": "Pushover 凭证保存失败",
|
|
54
|
+
"pushover.configured": "Pushover 配置成功",
|
|
55
|
+
"pushover.currentSessionSet": "✓ 已为当前会话设置环境变量,立即生效",
|
|
56
|
+
"pushover.skipped": "Pushover 配置已跳过",
|
|
57
|
+
"pushover.restartReminder": "注意: 需要重启终端才能使环境变量在后续会话中生效",
|
|
58
|
+
"guidance.pushoverManual": "手动设置环境变量:\n setx PUSHOVER_TOKEN \"your-token\"\n setx PUSHOVER_USER \"your-user\"",
|
|
59
|
+
"gitSSH.configured": "Git SSH 已配置",
|
|
60
|
+
"gitSSH.notConfigured": "Git SSH 未配置",
|
|
61
|
+
"gitSSH.recommended": "建议配置 SSH 以使用 Git 远程操作",
|
|
62
|
+
"gitSSH.guidance": "配置 Git SSH 步骤:",
|
|
63
|
+
"gitSSH.step1": "1. 安装 TortoiseGit (包含 Pageant)",
|
|
64
|
+
"gitSSH.step2": "2. 生成 SSH 密钥 (如使用 PuTTYgen)",
|
|
65
|
+
"gitSSH.step3": "3. 将公钥添加到远程仓库 (GitHub/GitLab)",
|
|
66
|
+
"gitSSH.step4": "4. 配置 Git 使用 TortoiseGit 的 SSH:",
|
|
67
|
+
"gitSSH.command": " git config --global core.sshCommand \"C:/Program Files/TortoiseGit/bin/TortoisePlink.exe\"",
|
|
68
|
+
"gitSSH.docs": "详细文档: https://work-skills.example.com/docs/git-ssh-setup",
|
|
69
|
+
"gitSSH.promptSkip": "跳过 Git SSH 配置? (可使用 HTTPS)",
|
|
70
|
+
"gitSSH.skipped": "Git SSH 配置已跳过",
|
|
71
|
+
"gitUser.alreadyConfigured": "Git 用户信息已配置",
|
|
72
|
+
"gitUser.required": "Git 提交需要用户信息",
|
|
73
|
+
"gitUser.promptName": "请输入 Git 用户名 (用于提交记录):",
|
|
74
|
+
"gitUser.promptEmail": "请输入 Git 邮箱地址:",
|
|
75
|
+
"gitUser.configured": "Git 用户信息配置成功",
|
|
76
|
+
"gitUser.failed": "Git 用户信息配置失败",
|
|
77
|
+
"marketplace.title": "插件市场",
|
|
78
|
+
"marketplace.registering": "正在注册 work-skills 市场源...",
|
|
79
|
+
"marketplace.registered": "市场源 'work-skills' 添加成功",
|
|
80
|
+
"marketplace.fetching": "正在获取可用插件列表...",
|
|
81
|
+
"marketplace.available": "可用插件:",
|
|
82
|
+
"marketplace.select_plugins": "请选择要安装的插件:",
|
|
83
|
+
"marketplace.none_selected": "未选择任何插件。您可以稍后安装。",
|
|
84
|
+
"marketplace.checking": "正在检查已安装插件...",
|
|
85
|
+
"marketplace.already_installed": "{name} (已安装,将跳过)",
|
|
86
|
+
"marketplace.installing": "正在安装 {name}...",
|
|
87
|
+
"marketplace.install_success": "{name} 安装成功",
|
|
88
|
+
"marketplace.install_skipped": "{name} 已跳过 (已安装)",
|
|
89
|
+
"marketplace.install_failed": "{name} 安装失败",
|
|
90
|
+
"marketplace.summary": "插件安装摘要:",
|
|
91
|
+
"marketplace.summary_installed": "已安装: {count}",
|
|
92
|
+
"marketplace.summary_skipped": "已跳过: {count}",
|
|
93
|
+
"marketplace.summary_failed": "失败: {count}",
|
|
94
|
+
"marketplace.complete": "插件安装完成。运行 Claude Code 即可使用。",
|
|
95
|
+
"marketplace.error.network": "获取插件列表失败。请检查网络连接。",
|
|
96
|
+
"marketplace.error.git": "安装插件需要 Git。",
|
|
97
|
+
"marketplace.error.unknown": "市场集成过程中发生错误。",
|
|
98
|
+
"installation.complete": "=== 安装完成 ===",
|
|
99
|
+
"installation.verificationStarting": "正在运行验证以检查您的配置...",
|
|
100
|
+
"verification.title": "安装验证",
|
|
101
|
+
"verification.summary": "摘要: {passed}/{total} 项检查通过",
|
|
102
|
+
"verification.rerunCommand": "重新验证命令: npx github:allanpk716/work-skills#main --verify",
|
|
103
|
+
"verification.error.pythonNotFound": "错误: 验证需要 Python 环境",
|
|
104
|
+
"verification.error.scriptNotFound": "错误: 验证脚本未找到",
|
|
105
|
+
"verification.error.timeout": "错误: 验证超时 (30秒)",
|
|
106
|
+
"verification.error.executionFailed": "错误: 验证失败",
|
|
107
|
+
"verification.nextSteps": "后续步骤",
|
|
108
|
+
"verification.nextStep1": "1. 如果是首次安装: 关闭并重新打开终端",
|
|
109
|
+
"verification.nextStep2": "2. 在任意项目目录中启动 Claude Code",
|
|
110
|
+
"verification.nextStep3": "3. 可用技能: /windows-git-commit, /notify-test",
|
|
111
|
+
"verification.nextStep4": "4. 或直接说: '使用 windows-git-commit 提交我的修改'"
|
|
112
|
+
}
|
package/src/index.js
ADDED
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const { checkPlatform } = require('./platform.js');
|
|
4
|
+
const { parseArgs } = require('./cli.js');
|
|
5
|
+
const { showWelcome } = require('./welcome.js');
|
|
6
|
+
const { runAllDetectors } = require('./detectors/index.js');
|
|
7
|
+
const { runInstaller } = require('./installers/index.js');
|
|
8
|
+
const { runAllConfigurators } = require('./configurators/index.js');
|
|
9
|
+
const { runMarketplaceIntegration } = require('./marketplace/index.js');
|
|
10
|
+
const { runVerification } = require('./verification/index.js');
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Main entry point for the installer
|
|
14
|
+
*/
|
|
15
|
+
async function main() {
|
|
16
|
+
// Step 1: Check platform (exits if not Windows)
|
|
17
|
+
checkPlatform();
|
|
18
|
+
|
|
19
|
+
// Step 2: Parse command line arguments
|
|
20
|
+
const options = parseArgs();
|
|
21
|
+
|
|
22
|
+
// Handle --verify flag (skip to verification only)
|
|
23
|
+
if (options.verifyOnly) {
|
|
24
|
+
const result = await runVerification();
|
|
25
|
+
process.exit(result.success ? 0 : 1);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
// Step 3: Show welcome banner
|
|
29
|
+
showWelcome({ useColors: options.useColors });
|
|
30
|
+
|
|
31
|
+
// Step 4: Run environment detection
|
|
32
|
+
const { results, allPassed } = await runAllDetectors();
|
|
33
|
+
|
|
34
|
+
// Step 5: Offer to install missing dependencies
|
|
35
|
+
if (!allPassed) {
|
|
36
|
+
const pipResults = results.filter(r =>
|
|
37
|
+
r.name && r.name !== 'Python' && r.name !== 'Git' &&
|
|
38
|
+
!r.name.includes('TortoiseGit') && !r.name.includes('PuTTY') && !r.name.includes('SSH')
|
|
39
|
+
);
|
|
40
|
+
|
|
41
|
+
if (pipResults.some(r => !r.installed)) {
|
|
42
|
+
await runInstaller(results);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
// Step 6: Interactive configuration (Phase 17)
|
|
47
|
+
await runAllConfigurators();
|
|
48
|
+
|
|
49
|
+
// Step 7: Marketplace integration (Phase 18)
|
|
50
|
+
await runMarketplaceIntegration();
|
|
51
|
+
|
|
52
|
+
// Step 8: Installation verification (Phase 19)
|
|
53
|
+
const chalk = require('chalk');
|
|
54
|
+
console.log(chalk.cyan('\n=== Installation Complete ===\n'));
|
|
55
|
+
console.log(chalk.gray('Running verification to check your setup...\n'));
|
|
56
|
+
await runVerification();
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
module.exports = {
|
|
60
|
+
main
|
|
61
|
+
};
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const { Confirm } = require('enquirer');
|
|
4
|
+
const chalk = require('chalk');
|
|
5
|
+
const { t } = require('../i18n/index.js');
|
|
6
|
+
const { installPipPackage, getErrorGuidance } = require('./pip-installer.js');
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Prompt user and install missing packages
|
|
10
|
+
* @param {Array} packages - Array of detection results
|
|
11
|
+
* @param {string} pythonCmd - Python command to use (default: 'python')
|
|
12
|
+
* @returns {Promise<{installed: Array, failed: Array, skipped: Array}>}
|
|
13
|
+
*/
|
|
14
|
+
async function promptAndInstall(packages, pythonCmd = 'python') {
|
|
15
|
+
const toInstall = packages.filter(p => !p.installed);
|
|
16
|
+
|
|
17
|
+
if (toInstall.length === 0) {
|
|
18
|
+
return { installed: [], failed: [], skipped: [] };
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
console.log(chalk.yellow('\n' + t('install.missingFound', { count: toInstall.length })));
|
|
22
|
+
toInstall.forEach(pkg => console.log(` - ${pkg.name}`));
|
|
23
|
+
|
|
24
|
+
const installed = [];
|
|
25
|
+
const failed = [];
|
|
26
|
+
const skipped = [];
|
|
27
|
+
|
|
28
|
+
for (const pkg of toInstall) {
|
|
29
|
+
const prompt = new Confirm({
|
|
30
|
+
name: 'install',
|
|
31
|
+
message: t('install.promptInstall', { package: pkg.name }),
|
|
32
|
+
initial: true
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
const shouldInstall = await prompt.run();
|
|
36
|
+
|
|
37
|
+
if (shouldInstall) {
|
|
38
|
+
console.log(chalk.gray(t('install.installing', { package: pkg.name })));
|
|
39
|
+
const result = await installPipPackage(pkg.name, pythonCmd);
|
|
40
|
+
|
|
41
|
+
if (result.success) {
|
|
42
|
+
console.log(chalk.green('[OK] ' + result.message));
|
|
43
|
+
installed.push(pkg.name);
|
|
44
|
+
} else {
|
|
45
|
+
console.log(chalk.red('[FAIL] ' + result.message));
|
|
46
|
+
console.log(chalk.gray(' -> ' + t(getErrorGuidance(result.error))));
|
|
47
|
+
failed.push(pkg.name);
|
|
48
|
+
}
|
|
49
|
+
} else {
|
|
50
|
+
skipped.push(pkg.name);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
return { installed, failed, skipped };
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Run installer flow
|
|
59
|
+
* @param {Array} detectionResults - Results from environment detection
|
|
60
|
+
* @param {string} pythonCmd - Python command to use (default: 'python')
|
|
61
|
+
* @returns {Promise<{installed: Array, failed: Array, skipped: Array}>}
|
|
62
|
+
*/
|
|
63
|
+
async function runInstaller(detectionResults, pythonCmd = 'python') {
|
|
64
|
+
// Find Python detection result to get pythonCmd
|
|
65
|
+
const pythonResult = detectionResults.find(r => r.name === 'Python');
|
|
66
|
+
const cmd = pythonResult?.path || pythonCmd;
|
|
67
|
+
|
|
68
|
+
// Filter to get only pip packages (exclude system tools)
|
|
69
|
+
const pipPackages = detectionResults.filter(r =>
|
|
70
|
+
r.name &&
|
|
71
|
+
r.name !== 'Python' &&
|
|
72
|
+
r.name !== 'Git' &&
|
|
73
|
+
!r.name.includes('TortoiseGit') &&
|
|
74
|
+
!r.name.includes('PuTTY') &&
|
|
75
|
+
!r.name.includes('SSH')
|
|
76
|
+
);
|
|
77
|
+
|
|
78
|
+
const results = await promptAndInstall(pipPackages, cmd);
|
|
79
|
+
|
|
80
|
+
// Print summary
|
|
81
|
+
console.log('\n' + t('install.summary'));
|
|
82
|
+
console.log(chalk.green(' ' + t('install.installed') + ': ' + results.installed.length));
|
|
83
|
+
console.log(chalk.red(' ' + t('install.failed') + ': ' + results.failed.length));
|
|
84
|
+
console.log(chalk.gray(' ' + t('install.skipped') + ': ' + results.skipped.length));
|
|
85
|
+
|
|
86
|
+
return results;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
module.exports = {
|
|
90
|
+
runInstaller,
|
|
91
|
+
promptAndInstall
|
|
92
|
+
};
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const execa = require('execa');
|
|
4
|
+
const chalk = require('chalk');
|
|
5
|
+
const { t } = require('../i18n/index.js');
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Install a Python package using pip
|
|
9
|
+
* @param {string} packageName - Name of the package to install
|
|
10
|
+
* @param {string} pythonCmd - Python command to use (default: 'python')
|
|
11
|
+
* @returns {Promise<{success: boolean, message: string, output?: string, error?: string, errorDetails?: string}>}
|
|
12
|
+
*/
|
|
13
|
+
async function installPipPackage(packageName, pythonCmd = 'python') {
|
|
14
|
+
try {
|
|
15
|
+
const { stdout } = await execa(pythonCmd, ['-m', 'pip', 'install', packageName, '--user']);
|
|
16
|
+
|
|
17
|
+
return {
|
|
18
|
+
success: true,
|
|
19
|
+
message: t('install.success', { package: packageName }),
|
|
20
|
+
output: stdout
|
|
21
|
+
};
|
|
22
|
+
} catch (error) {
|
|
23
|
+
const stderr = error.stderr || error.message || '';
|
|
24
|
+
let errorType = 'unknown';
|
|
25
|
+
|
|
26
|
+
// Detect error type from stderr
|
|
27
|
+
if (stderr.includes('Permission denied') || stderr.includes('Access is denied')) {
|
|
28
|
+
errorType = 'permission';
|
|
29
|
+
} else if (stderr.toLowerCase().includes('network') || stderr.toLowerCase().includes('connection')) {
|
|
30
|
+
errorType = 'network';
|
|
31
|
+
} else if (stderr.includes('not found') || stderr.includes('ENOENT')) {
|
|
32
|
+
errorType = 'pipNotFound';
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
return {
|
|
36
|
+
success: false,
|
|
37
|
+
message: t('install.failed', { package: packageName }),
|
|
38
|
+
error: errorType,
|
|
39
|
+
errorDetails: stderr
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Get guidance message key for an error type
|
|
46
|
+
* @param {string} errorType - Type of error
|
|
47
|
+
* @returns {string} - i18n key for guidance message
|
|
48
|
+
*/
|
|
49
|
+
function getErrorGuidance(errorType) {
|
|
50
|
+
const guidanceMap = {
|
|
51
|
+
'permission': 'guidance.installPermission',
|
|
52
|
+
'network': 'guidance.installNetwork',
|
|
53
|
+
'pipNotFound': 'guidance.installPipNotFound',
|
|
54
|
+
'unknown': 'guidance.installUnknown'
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
return guidanceMap[errorType] || guidanceMap['unknown'];
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
module.exports = {
|
|
61
|
+
installPipPackage,
|
|
62
|
+
getErrorGuidance
|
|
63
|
+
};
|