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.
@@ -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
@@ -78,9 +78,20 @@ if (!claudeCodePath) {
78
78
  process.exit(1);
79
79
  }
80
80
 
81
- // Import and run Claude Code
82
- // Use dynamic import since cli.js is an ES module
83
- import(claudeCodePath).catch(err => {
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.6",
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.7"
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
+ };