@unitsvc/cc-helper 1.0.6

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/install.js ADDED
@@ -0,0 +1,253 @@
1
+ #!/usr/bin/env node
2
+
3
+ const fs = require('fs');
4
+ const path = require('path');
5
+ const os = require('os');
6
+ const https = require('https');
7
+ const { execSync } = require('child_process');
8
+
9
+ const GITHUB_OWNER = 'next-bin';
10
+ const GITHUB_REPO = 'cc-helper';
11
+ const CACHE_DIR = path.join(os.homedir(), '.cache', 'cc-helper');
12
+ const VERSION_FILE = path.join(CACHE_DIR, 'version.txt');
13
+
14
+ // Read version from package.json
15
+ function getPackageVersion() {
16
+ try {
17
+ const packagePath = path.join(__dirname, 'package.json');
18
+ const pkg = JSON.parse(fs.readFileSync(packagePath, 'utf8'));
19
+ return pkg.version;
20
+ } catch (err) {
21
+ throw new Error('Cannot read package version: ' + err.message);
22
+ }
23
+ }
24
+
25
+ function getPlatform() {
26
+ const platform = os.platform();
27
+ const arch = os.arch();
28
+
29
+ const platformMap = {
30
+ 'darwin': 'darwin',
31
+ 'linux': 'linux',
32
+ 'win32': 'windows'
33
+ };
34
+
35
+ const archMap = {
36
+ 'x64': 'amd64',
37
+ 'arm64': 'arm64'
38
+ };
39
+
40
+ const mappedPlatform = platformMap[platform];
41
+ const mappedArch = archMap[arch];
42
+
43
+ if (!mappedPlatform || !mappedArch) {
44
+ console.warn(`Warning: Unsupported platform ${platform} ${arch}`);
45
+ process.exit(0);
46
+ }
47
+
48
+ if (platform === 'win32' && arch === 'arm64') {
49
+ console.warn('Warning: Windows arm64 is not supported');
50
+ process.exit(0);
51
+ }
52
+
53
+ return { platform: mappedPlatform, arch: mappedArch };
54
+ }
55
+
56
+ function getArchiveName(version, platform, arch) {
57
+ const ver = version.replace(/^v/, '');
58
+ if (platform === 'windows') {
59
+ return `cc-helper_${ver}_${platform}_${arch}.zip`;
60
+ }
61
+ return `cc-helper_${ver}_${platform}_${arch}.tar.gz`;
62
+ }
63
+
64
+ function getBinaryName(platform) {
65
+ return platform === 'windows' ? 'cc-helper.exe' : 'cc-helper';
66
+ }
67
+
68
+ function downloadFile(url, dest) {
69
+ return new Promise((resolve, reject) => {
70
+ const file = fs.createWriteStream(dest);
71
+
72
+ const requestUrl = url.startsWith('https://') ? url : 'https://github.com' + url;
73
+
74
+ const request = https.get(requestUrl, { headers: { 'User-Agent': 'cc-helper-npm-installer' } }, (response) => {
75
+ if (response.statusCode === 302 || response.statusCode === 301) {
76
+ file.close();
77
+ if (fs.existsSync(dest)) {
78
+ fs.unlinkSync(dest);
79
+ }
80
+ downloadFile(response.headers.location, dest).then(resolve).catch(reject);
81
+ return;
82
+ }
83
+
84
+ if (response.statusCode !== 200) {
85
+ file.close();
86
+ if (fs.existsSync(dest)) {
87
+ fs.unlinkSync(dest);
88
+ }
89
+ reject(new Error(`Download failed with status ${response.statusCode}: ${url}`));
90
+ return;
91
+ }
92
+
93
+ response.pipe(file);
94
+
95
+ file.on('finish', () => {
96
+ file.close();
97
+ resolve();
98
+ });
99
+ });
100
+
101
+ request.on('error', (err) => {
102
+ if (fs.existsSync(dest)) {
103
+ fs.unlinkSync(dest);
104
+ }
105
+ reject(err);
106
+ });
107
+
108
+ file.on('error', (err) => {
109
+ if (fs.existsSync(dest)) {
110
+ fs.unlinkSync(dest);
111
+ }
112
+ reject(err);
113
+ });
114
+ });
115
+ }
116
+
117
+ function extractTarGz(tarGzPath, destDir) {
118
+ try {
119
+ execSync(`tar -xzf "${tarGzPath}" -C "${destDir}"`, { stdio: 'pipe' });
120
+ } catch (err) {
121
+ throw new Error(`Failed to extract tar.gz archive: ${err.message}`);
122
+ }
123
+ }
124
+
125
+ function extractZip(zipPath, destDir) {
126
+ try {
127
+ if (process.platform === 'win32') {
128
+ const psCommand = `
129
+ try {
130
+ Expand-Archive -Path '${zipPath.replace(/'/g, "''")}' -DestinationPath '${destDir.replace(/'/g, "''")}' -Force -ErrorAction Stop
131
+ exit 0
132
+ } catch {
133
+ exit 1
134
+ }
135
+ `;
136
+ execSync(`powershell -NoProfile -ExecutionPolicy Bypass -Command "${psCommand}"`, { stdio: 'pipe' });
137
+ } else {
138
+ try {
139
+ execSync('which unzip', { stdio: 'pipe' });
140
+ } catch {
141
+ throw new Error(
142
+ 'unzip command not found. Please install unzip:\n' +
143
+ ' Ubuntu/Debian: sudo apt-get install unzip\n' +
144
+ ' macOS: brew install unzip\n' +
145
+ ' CentOS/RHEL: sudo yum install unzip'
146
+ );
147
+ }
148
+ execSync(`unzip -o "${zipPath}" -d "${destDir}"`, { stdio: 'pipe' });
149
+ }
150
+ } catch (err) {
151
+ if (err.message.includes('unzip command not found')) {
152
+ throw err;
153
+ }
154
+ throw new Error(`Failed to extract zip archive: ${err.message}`);
155
+ }
156
+ }
157
+
158
+ function extractArchive(archivePath, destDir, platform) {
159
+ if (platform === 'windows') {
160
+ extractZip(archivePath, destDir);
161
+ } else {
162
+ extractTarGz(archivePath, destDir);
163
+ }
164
+ }
165
+
166
+ function findBinary(dir, platform) {
167
+ const binaryName = getBinaryName(platform);
168
+ const files = fs.readdirSync(dir);
169
+
170
+ const rootBinary = path.join(dir, binaryName);
171
+ if (fs.existsSync(rootBinary)) {
172
+ return rootBinary;
173
+ }
174
+
175
+ for (const file of files) {
176
+ const fullPath = path.join(dir, file);
177
+ const stat = fs.statSync(fullPath);
178
+ if (stat.isDirectory()) {
179
+ const binaryInSubdir = path.join(fullPath, binaryName);
180
+ if (fs.existsSync(binaryInSubdir)) {
181
+ return binaryInSubdir;
182
+ }
183
+ }
184
+ }
185
+
186
+ throw new Error(`Binary ${binaryName} not found in archive`);
187
+ }
188
+
189
+ async function install() {
190
+ try {
191
+ const packageVersion = getPackageVersion();
192
+ const { platform, arch } = getPlatform();
193
+ const binaryName = getBinaryName(platform);
194
+ const binaryPath = path.join(CACHE_DIR, binaryName);
195
+
196
+ // Create cache directory
197
+ if (!fs.existsSync(CACHE_DIR)) {
198
+ fs.mkdirSync(CACHE_DIR, { recursive: true });
199
+ }
200
+
201
+ // Check if already exists and up to date
202
+ if (fs.existsSync(binaryPath) && fs.existsSync(VERSION_FILE)) {
203
+ const currentVersion = fs.readFileSync(VERSION_FILE, 'utf8').trim();
204
+ if (currentVersion === packageVersion) {
205
+ console.log(`cc-helper ${currentVersion} is already installed`);
206
+ process.exit(0);
207
+ }
208
+ }
209
+
210
+ // Download archive with fixed version from package.json
211
+ const archiveName = getArchiveName(packageVersion, platform, arch);
212
+ const tagVersion = packageVersion.startsWith('v') ? packageVersion : `v${packageVersion}`;
213
+ const downloadUrl = `https://github.com/${GITHUB_OWNER}/${GITHUB_REPO}/releases/download/${tagVersion}/${archiveName}`;
214
+ const archivePath = path.join(CACHE_DIR, archiveName);
215
+
216
+ console.log(`Installing cc-helper ${packageVersion} for ${platform}-${arch}...`);
217
+
218
+ await downloadFile(downloadUrl, archivePath);
219
+
220
+ // Extract archive
221
+ console.log('Extracting archive...');
222
+ const tempDir = path.join(CACHE_DIR, 'temp_extract_' + Date.now());
223
+ fs.mkdirSync(tempDir, { recursive: true });
224
+
225
+ extractArchive(archivePath, tempDir, platform);
226
+
227
+ // Find and move binary
228
+ const extractedBinaryPath = findBinary(tempDir, platform);
229
+
230
+ if (fs.existsSync(binaryPath)) {
231
+ fs.unlinkSync(binaryPath);
232
+ }
233
+
234
+ fs.copyFileSync(extractedBinaryPath, binaryPath);
235
+ fs.chmodSync(binaryPath, 0o755);
236
+
237
+ // Clean up
238
+ fs.rmSync(tempDir, { recursive: true, force: true });
239
+ fs.unlinkSync(archivePath);
240
+
241
+ // Save version
242
+ fs.writeFileSync(VERSION_FILE, packageVersion);
243
+
244
+ console.log('Installation complete!');
245
+ console.log(`Binary location: ${binaryPath}`);
246
+ } catch (err) {
247
+ console.error('Installation failed:', err.message);
248
+ console.error('The binary will be downloaded on first run instead.');
249
+ process.exit(0);
250
+ }
251
+ }
252
+
253
+ install();
package/package.json ADDED
@@ -0,0 +1,38 @@
1
+ {
2
+ "name": "@unitsvc/cc-helper",
3
+ "version": "1.0.6",
4
+ "description": "Claude Code /loop feature bypass tool",
5
+ "main": "index.js",
6
+ "bin": {
7
+ "cc-helper": "bin/cc-helper.js"
8
+ },
9
+ "scripts": {
10
+ "postinstall": "node install.js",
11
+ "preuninstall": "node uninstall.js"
12
+ },
13
+ "keywords": [
14
+ "claude-code",
15
+ "claude",
16
+ "loop",
17
+ "cli"
18
+ ],
19
+ "author": "next-bin",
20
+ "license": "AGPL-3.0",
21
+ "repository": {
22
+ "type": "git",
23
+ "url": "git+https://github.com/next-bin/cc-helper.git"
24
+ },
25
+ "bugs": {
26
+ "url": "https://github.com/next-bin/cc-helper/issues"
27
+ },
28
+ "homepage": "https://github.com/next-bin/cc-helper#readme",
29
+ "engines": {
30
+ "node": ">=14.0.0"
31
+ },
32
+ "files": [
33
+ "bin/",
34
+ "install.js",
35
+ "uninstall.js",
36
+ "index.js"
37
+ ]
38
+ }
package/uninstall.js ADDED
@@ -0,0 +1,23 @@
1
+ #!/usr/bin/env node
2
+
3
+ const fs = require('fs');
4
+ const path = require('path');
5
+ const os = require('os');
6
+
7
+ const CACHE_DIR = path.join(os.homedir(), '.cache', 'cc-helper');
8
+
9
+ function uninstall() {
10
+ try {
11
+ if (fs.existsSync(CACHE_DIR)) {
12
+ console.log('Removing cached binaries...');
13
+ fs.rmSync(CACHE_DIR, { recursive: true, force: true });
14
+ console.log('Cleanup complete!');
15
+ }
16
+ } catch (err) {
17
+ console.error('Cleanup warning:', err.message);
18
+ console.log('You can manually remove the cache directory:');
19
+ console.log(` rm -rf ${CACHE_DIR}`);
20
+ }
21
+ }
22
+
23
+ uninstall();