claude-code-termux 1.0.6 → 1.0.9
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/.github/workflows/auto-update.yml +113 -0
- package/bin/claude-termux.js +14 -3
- package/package.json +2 -2
- package/src/auto-update.js +214 -0
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
name: Auto-update and publish
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
schedule:
|
|
5
|
+
- cron: '0 6 * * *' # 6 AM UTC daily
|
|
6
|
+
workflow_dispatch:
|
|
7
|
+
inputs:
|
|
8
|
+
force_publish:
|
|
9
|
+
description: 'Force publish (skip upstream check)'
|
|
10
|
+
required: false
|
|
11
|
+
default: false
|
|
12
|
+
type: boolean
|
|
13
|
+
version_bump:
|
|
14
|
+
description: 'Version bump type (only for force publish)'
|
|
15
|
+
required: false
|
|
16
|
+
default: 'patch'
|
|
17
|
+
type: choice
|
|
18
|
+
options:
|
|
19
|
+
- patch
|
|
20
|
+
- minor
|
|
21
|
+
- major
|
|
22
|
+
|
|
23
|
+
permissions:
|
|
24
|
+
contents: write # For pushing version bump commits
|
|
25
|
+
id-token: write # Required for npm OIDC trusted publishing
|
|
26
|
+
|
|
27
|
+
jobs:
|
|
28
|
+
check-and-publish:
|
|
29
|
+
runs-on: ubuntu-latest
|
|
30
|
+
steps:
|
|
31
|
+
- uses: actions/checkout@v4
|
|
32
|
+
|
|
33
|
+
- uses: actions/setup-node@v4
|
|
34
|
+
with:
|
|
35
|
+
node-version: '24' # Node 24+ required for OIDC (npm >=11.5)
|
|
36
|
+
registry-url: 'https://registry.npmjs.org'
|
|
37
|
+
|
|
38
|
+
- name: Check for upstream updates
|
|
39
|
+
id: check
|
|
40
|
+
if: ${{ !inputs.force_publish }}
|
|
41
|
+
run: |
|
|
42
|
+
# Get current dependency version (strip ^ prefix)
|
|
43
|
+
CURRENT=$(node -p "require('./package.json').dependencies['@anthropic-ai/claude-code'].replace('^', '')")
|
|
44
|
+
echo "Current version: $CURRENT"
|
|
45
|
+
|
|
46
|
+
# Get latest version from npm
|
|
47
|
+
LATEST=$(npm view @anthropic-ai/claude-code version)
|
|
48
|
+
echo "Latest version: $LATEST"
|
|
49
|
+
|
|
50
|
+
if [ "$CURRENT" != "$LATEST" ]; then
|
|
51
|
+
echo "Update needed: $CURRENT -> $LATEST"
|
|
52
|
+
echo "update_needed=true" >> $GITHUB_OUTPUT
|
|
53
|
+
echo "new_version=$LATEST" >> $GITHUB_OUTPUT
|
|
54
|
+
else
|
|
55
|
+
echo "Already up to date"
|
|
56
|
+
echo "update_needed=false" >> $GITHUB_OUTPUT
|
|
57
|
+
fi
|
|
58
|
+
|
|
59
|
+
- name: Update dependency and bump version (auto)
|
|
60
|
+
if: ${{ !inputs.force_publish && steps.check.outputs.update_needed == 'true' }}
|
|
61
|
+
run: |
|
|
62
|
+
npm pkg set "dependencies.@anthropic-ai/claude-code=^${{ steps.check.outputs.new_version }}"
|
|
63
|
+
npm version patch --no-git-tag-version
|
|
64
|
+
echo "Updated package.json:"
|
|
65
|
+
cat package.json | head -35
|
|
66
|
+
|
|
67
|
+
- name: Bump version (manual)
|
|
68
|
+
if: ${{ inputs.force_publish }}
|
|
69
|
+
run: |
|
|
70
|
+
npm version ${{ inputs.version_bump }} --no-git-tag-version
|
|
71
|
+
NEW_VERSION=$(node -p "require('./package.json').version")
|
|
72
|
+
echo "New version: $NEW_VERSION"
|
|
73
|
+
|
|
74
|
+
- name: Commit and push changes
|
|
75
|
+
if: ${{ inputs.force_publish || steps.check.outputs.update_needed == 'true' }}
|
|
76
|
+
run: |
|
|
77
|
+
git config user.name "github-actions[bot]"
|
|
78
|
+
git config user.email "github-actions[bot]@users.noreply.github.com"
|
|
79
|
+
VERSION=$(node -p "require('./package.json').version")
|
|
80
|
+
git add -A
|
|
81
|
+
if [ "${{ inputs.force_publish }}" == "true" ]; then
|
|
82
|
+
git commit -m "Release v${VERSION}"
|
|
83
|
+
git tag "v${VERSION}"
|
|
84
|
+
git push --tags
|
|
85
|
+
else
|
|
86
|
+
git commit -m "Bump @anthropic-ai/claude-code to ${{ steps.check.outputs.new_version }}"
|
|
87
|
+
fi
|
|
88
|
+
git push
|
|
89
|
+
|
|
90
|
+
- name: Install dependencies
|
|
91
|
+
if: ${{ inputs.force_publish || steps.check.outputs.update_needed == 'true' }}
|
|
92
|
+
run: npm install
|
|
93
|
+
|
|
94
|
+
- name: Publish to npm (OIDC)
|
|
95
|
+
if: ${{ inputs.force_publish || steps.check.outputs.update_needed == 'true' }}
|
|
96
|
+
run: npm publish --access public
|
|
97
|
+
|
|
98
|
+
- name: Summary
|
|
99
|
+
run: |
|
|
100
|
+
VERSION=$(node -p "require('./package.json').version")
|
|
101
|
+
if [ "${{ inputs.force_publish }}" == "true" ]; then
|
|
102
|
+
echo "## Published v${VERSION}" >> $GITHUB_STEP_SUMMARY
|
|
103
|
+
echo "" >> $GITHUB_STEP_SUMMARY
|
|
104
|
+
echo "Manual release published." >> $GITHUB_STEP_SUMMARY
|
|
105
|
+
elif [ "${{ steps.check.outputs.update_needed }}" == "true" ]; then
|
|
106
|
+
echo "## Update Published" >> $GITHUB_STEP_SUMMARY
|
|
107
|
+
echo "" >> $GITHUB_STEP_SUMMARY
|
|
108
|
+
echo "Updated @anthropic-ai/claude-code to version ${{ steps.check.outputs.new_version }}" >> $GITHUB_STEP_SUMMARY
|
|
109
|
+
else
|
|
110
|
+
echo "## No Update Needed" >> $GITHUB_STEP_SUMMARY
|
|
111
|
+
echo "" >> $GITHUB_STEP_SUMMARY
|
|
112
|
+
echo "Already using the latest version of @anthropic-ai/claude-code" >> $GITHUB_STEP_SUMMARY
|
|
113
|
+
fi
|
package/bin/claude-termux.js
CHANGED
|
@@ -78,9 +78,20 @@ if (!claudeCodePath) {
|
|
|
78
78
|
process.exit(1);
|
|
79
79
|
}
|
|
80
80
|
|
|
81
|
-
//
|
|
82
|
-
//
|
|
83
|
-
|
|
81
|
+
// Auto-update check (runs before loading Claude Code)
|
|
82
|
+
// This checks for updates and may restart the process if an update is found
|
|
83
|
+
const { checkAndUpdate } = require('../src/auto-update');
|
|
84
|
+
|
|
85
|
+
checkAndUpdate().then(updated => {
|
|
86
|
+
if (updated) {
|
|
87
|
+
// Process will exit and restart with new version
|
|
88
|
+
return;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
// Import and run Claude Code
|
|
92
|
+
// Use dynamic import since cli.js is an ES module
|
|
93
|
+
return import(claudeCodePath);
|
|
94
|
+
}).catch(err => {
|
|
84
95
|
console.error('[claude-code-termux] Error loading Claude Code:', err.message);
|
|
85
96
|
|
|
86
97
|
if (err.message.includes('sharp')) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "claude-code-termux",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.9",
|
|
4
4
|
"description": "Claude Code CLI with Termux/Android compatibility fixes - a wrapper that patches issues with Sharp, ripgrep, and path resolution on ARM64 Android",
|
|
5
5
|
"author": "Jimoh Ovbiagele <findingjimoh@gmail.com>",
|
|
6
6
|
"license": "MIT",
|
|
@@ -28,7 +28,7 @@
|
|
|
28
28
|
"test": "node scripts/verify-install.js"
|
|
29
29
|
},
|
|
30
30
|
"dependencies": {
|
|
31
|
-
"@anthropic-ai/claude-code": "^2.1.
|
|
31
|
+
"@anthropic-ai/claude-code": "^2.1.27"
|
|
32
32
|
},
|
|
33
33
|
"engines": {
|
|
34
34
|
"node": ">=18.0.0 <25.0.0"
|
|
@@ -0,0 +1,214 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const { execSync, spawn } = require('child_process');
|
|
4
|
+
const fs = require('fs');
|
|
5
|
+
const path = require('path');
|
|
6
|
+
const https = require('https');
|
|
7
|
+
|
|
8
|
+
const PACKAGE_NAME = 'claude-code-termux';
|
|
9
|
+
const CACHE_FILE = path.join(process.env.HOME || '', '.claude', '.auto-update-cache');
|
|
10
|
+
const CACHE_DURATION_MS = 24 * 60 * 60 * 1000; // 24 hours
|
|
11
|
+
const FETCH_TIMEOUT_MS = 10000; // 10 seconds
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Check if auto-update is disabled via flag or environment variable
|
|
15
|
+
*/
|
|
16
|
+
function isAutoUpdateDisabled() {
|
|
17
|
+
if (process.env.CLAUDE_NO_AUTO_UPDATE === '1') {
|
|
18
|
+
return true;
|
|
19
|
+
}
|
|
20
|
+
if (process.argv.includes('--no-auto-update')) {
|
|
21
|
+
return true;
|
|
22
|
+
}
|
|
23
|
+
return false;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Get the installed version of claude-code-termux
|
|
28
|
+
*/
|
|
29
|
+
function getInstalledVersion() {
|
|
30
|
+
try {
|
|
31
|
+
const packageJsonPath = path.join(__dirname, '..', 'package.json');
|
|
32
|
+
const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8'));
|
|
33
|
+
return packageJson.version;
|
|
34
|
+
} catch (err) {
|
|
35
|
+
return null;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Fetch the latest version from npm registry
|
|
41
|
+
*/
|
|
42
|
+
function fetchLatestVersion() {
|
|
43
|
+
return new Promise((resolve, reject) => {
|
|
44
|
+
const req = https.get(`https://registry.npmjs.org/${PACKAGE_NAME}/latest`, {
|
|
45
|
+
timeout: FETCH_TIMEOUT_MS,
|
|
46
|
+
headers: {
|
|
47
|
+
'Accept': 'application/json',
|
|
48
|
+
'User-Agent': 'claude-code-termux-auto-update'
|
|
49
|
+
}
|
|
50
|
+
}, (res) => {
|
|
51
|
+
let data = '';
|
|
52
|
+
res.on('data', chunk => data += chunk);
|
|
53
|
+
res.on('end', () => {
|
|
54
|
+
try {
|
|
55
|
+
const json = JSON.parse(data);
|
|
56
|
+
resolve(json.version);
|
|
57
|
+
} catch (err) {
|
|
58
|
+
reject(new Error('Failed to parse npm registry response'));
|
|
59
|
+
}
|
|
60
|
+
});
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
req.on('error', reject);
|
|
64
|
+
req.on('timeout', () => {
|
|
65
|
+
req.destroy();
|
|
66
|
+
reject(new Error('Request timed out'));
|
|
67
|
+
});
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* Check if we should skip the update check based on cache
|
|
73
|
+
*/
|
|
74
|
+
function shouldSkipCheck() {
|
|
75
|
+
try {
|
|
76
|
+
if (!fs.existsSync(CACHE_FILE)) {
|
|
77
|
+
return false;
|
|
78
|
+
}
|
|
79
|
+
const cacheContent = fs.readFileSync(CACHE_FILE, 'utf8');
|
|
80
|
+
const cache = JSON.parse(cacheContent);
|
|
81
|
+
const lastCheck = new Date(cache.lastCheck).getTime();
|
|
82
|
+
const now = Date.now();
|
|
83
|
+
return (now - lastCheck) < CACHE_DURATION_MS;
|
|
84
|
+
} catch (err) {
|
|
85
|
+
return false;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* Update the cache file with current timestamp
|
|
91
|
+
*/
|
|
92
|
+
function updateCache() {
|
|
93
|
+
try {
|
|
94
|
+
const cacheDir = path.dirname(CACHE_FILE);
|
|
95
|
+
if (!fs.existsSync(cacheDir)) {
|
|
96
|
+
fs.mkdirSync(cacheDir, { recursive: true });
|
|
97
|
+
}
|
|
98
|
+
fs.writeFileSync(CACHE_FILE, JSON.stringify({
|
|
99
|
+
lastCheck: new Date().toISOString()
|
|
100
|
+
}));
|
|
101
|
+
} catch (err) {
|
|
102
|
+
// Silently ignore cache write errors
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* Compare semantic versions
|
|
108
|
+
* Returns true if latestVersion > installedVersion
|
|
109
|
+
*/
|
|
110
|
+
function isNewerVersion(installedVersion, latestVersion) {
|
|
111
|
+
const installed = installedVersion.split('.').map(Number);
|
|
112
|
+
const latest = latestVersion.split('.').map(Number);
|
|
113
|
+
|
|
114
|
+
for (let i = 0; i < 3; i++) {
|
|
115
|
+
if ((latest[i] || 0) > (installed[i] || 0)) return true;
|
|
116
|
+
if ((latest[i] || 0) < (installed[i] || 0)) return false;
|
|
117
|
+
}
|
|
118
|
+
return false;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
/**
|
|
122
|
+
* Run npm install to install the latest version
|
|
123
|
+
*/
|
|
124
|
+
function runUpdate(latestVersion) {
|
|
125
|
+
return new Promise((resolve, reject) => {
|
|
126
|
+
console.log(`[claude-code-termux] Updating to ${latestVersion}...`);
|
|
127
|
+
|
|
128
|
+
try {
|
|
129
|
+
// Use npm install with --force to bypass platform checks for sharp-wasm32
|
|
130
|
+
execSync(`npm install -g ${PACKAGE_NAME}@${latestVersion} --force`, {
|
|
131
|
+
stdio: 'inherit',
|
|
132
|
+
timeout: 120000 // 2 minute timeout for update
|
|
133
|
+
});
|
|
134
|
+
resolve(true);
|
|
135
|
+
} catch (err) {
|
|
136
|
+
reject(err);
|
|
137
|
+
}
|
|
138
|
+
});
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
/**
|
|
142
|
+
* Re-execute the current process with the same arguments
|
|
143
|
+
*/
|
|
144
|
+
function relaunchProcess() {
|
|
145
|
+
console.log('[claude-code-termux] Update complete, restarting...\n');
|
|
146
|
+
|
|
147
|
+
// Filter out any auto-update related args to prevent infinite loops
|
|
148
|
+
const args = process.argv.slice(2).filter(arg => arg !== '--no-auto-update');
|
|
149
|
+
|
|
150
|
+
// Spawn a new process
|
|
151
|
+
const child = spawn(process.argv[0], [process.argv[1], '--no-auto-update', ...args], {
|
|
152
|
+
stdio: 'inherit',
|
|
153
|
+
detached: false
|
|
154
|
+
});
|
|
155
|
+
|
|
156
|
+
child.on('exit', (code) => {
|
|
157
|
+
process.exit(code || 0);
|
|
158
|
+
});
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
/**
|
|
162
|
+
* Main auto-update check function
|
|
163
|
+
* Returns true if an update was performed and process should restart
|
|
164
|
+
*/
|
|
165
|
+
async function checkAndUpdate() {
|
|
166
|
+
// Check if disabled
|
|
167
|
+
if (isAutoUpdateDisabled()) {
|
|
168
|
+
return false;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
// Check cache
|
|
172
|
+
if (shouldSkipCheck()) {
|
|
173
|
+
return false;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
try {
|
|
177
|
+
// Get installed version
|
|
178
|
+
const installedVersion = getInstalledVersion();
|
|
179
|
+
if (!installedVersion) {
|
|
180
|
+
return false;
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
// Fetch latest version from npm
|
|
184
|
+
const latestVersion = await fetchLatestVersion();
|
|
185
|
+
|
|
186
|
+
// Update cache regardless of whether update is needed
|
|
187
|
+
updateCache();
|
|
188
|
+
|
|
189
|
+
// Check if update is needed
|
|
190
|
+
if (!isNewerVersion(installedVersion, latestVersion)) {
|
|
191
|
+
return false;
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
// Perform update
|
|
195
|
+
await runUpdate(latestVersion);
|
|
196
|
+
|
|
197
|
+
// Relaunch with new version
|
|
198
|
+
relaunchProcess();
|
|
199
|
+
return true;
|
|
200
|
+
|
|
201
|
+
} catch (err) {
|
|
202
|
+
// Fail silently on any errors - don't block Claude from starting
|
|
203
|
+
// Uncomment for debugging: console.error('[claude-code-termux] Auto-update check failed:', err.message);
|
|
204
|
+
return false;
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
module.exports = {
|
|
209
|
+
checkAndUpdate,
|
|
210
|
+
isAutoUpdateDisabled,
|
|
211
|
+
getInstalledVersion,
|
|
212
|
+
fetchLatestVersion,
|
|
213
|
+
isNewerVersion
|
|
214
|
+
};
|