@emend-ai/utim 1.43.3 → 1.43.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.
Files changed (2) hide show
  1. package/bin/utim.js +92 -38
  2. package/package.json +44 -44
package/bin/utim.js CHANGED
@@ -6,13 +6,24 @@ const os = require('os');
6
6
  const fs = require('fs');
7
7
 
8
8
  const args = process.argv.slice(2);
9
- const useShell = os.platform() === 'win32';
9
+ const isWin = os.platform() === 'win32';
10
+ const isTermux =
11
+ (process.env.PREFIX && process.env.PREFIX.includes('com.termux')) ||
12
+ fs.existsSync('/data/data/com.termux');
10
13
 
11
14
  // ── Find a working Python 3 interpreter ──────────────────────────────────────
12
15
  function findPython() {
13
- for (const candidate of ['python3', 'python']) {
16
+ const candidates = isWin
17
+ ? ['python', 'python3', 'py']
18
+ : ['python3', 'python'];
19
+
20
+ for (const candidate of candidates) {
14
21
  try {
15
- const r = spawnSync(candidate, ['--version'], { encoding: 'utf8', timeout: 3000, shell: useShell });
22
+ const r = spawnSync(candidate, ['--version'], {
23
+ encoding: 'utf8',
24
+ timeout: 4000,
25
+ shell: isWin,
26
+ });
16
27
  const out = (r.stdout || '') + (r.stderr || '');
17
28
  if (out.includes('Python 3')) return candidate;
18
29
  } catch (_) {}
@@ -20,51 +31,83 @@ function findPython() {
20
31
  return null;
21
32
  }
22
33
 
23
- // ── Attempt to launch a command, return true if successful ───────────────────
24
- function tryLaunch(cmd, launchArgs) {
34
+ // ── Check if a binary is actually available and runnable ─────────────────────
35
+ function commandExists(cmd) {
25
36
  try {
26
- const probe = spawnSync(cmd, ['--version'], { shell: useShell, timeout: 3000, encoding: 'utf8' });
27
- const out = (probe.stdout || '') + (probe.stderr || '');
28
- // accept if exit 0 OR if it printed something (some tools exit non-0 for --version)
29
- if (probe.status === 0 || out.length > 0) {
30
- const proc = spawn(cmd, launchArgs, { stdio: 'inherit', shell: useShell });
31
- proc.on('exit', (code) => process.exit(code == null ? 0 : code));
32
- return true;
33
- }
34
- } catch (_) {}
35
- return false;
37
+ // Use 'where' on Windows, 'which' on Unix to check existence
38
+ const checker = isWin ? 'where' : 'which';
39
+ const probe = spawnSync(checker, [cmd], {
40
+ encoding: 'utf8',
41
+ timeout: 3000,
42
+ shell: false,
43
+ });
44
+ return probe.status === 0 && (probe.stdout || '').trim().length > 0;
45
+ } catch (_) {
46
+ return false;
47
+ }
48
+ }
49
+
50
+ // ── Launch a command, forwarding stdio ───────────────────────────────────────
51
+ function launch(cmd, launchArgs) {
52
+ const proc = spawn(cmd, launchArgs, {
53
+ stdio: 'inherit',
54
+ shell: isWin,
55
+ });
56
+ proc.on('exit', (code) => process.exit(code == null ? 0 : code));
57
+ proc.on('error', () => {
58
+ // If spawning fails at OS level, fall through (caller handles)
59
+ });
60
+ return true;
36
61
  }
37
62
 
38
63
  // ── Try the installed console_script entry point ──────────────────────────────
39
64
  function tryEntryPoint() {
40
- return tryLaunch('utim-agent-core', args);
65
+ // Explicitly verify the binary exists before attempting to spawn it.
66
+ // This prevents the "not recognised as internal or external command" error
67
+ // from surfacing to the user when pip install was skipped.
68
+ if (!commandExists('utim-agent-core')) return false;
69
+ return launch('utim-agent-core', args);
41
70
  }
42
71
 
43
72
  // ── Try via `python -m utim_cli.utim` ───────────────────────────────────────
44
73
  function tryModule(python) {
45
74
  try {
46
- const probe = spawnSync(python, ['-m', 'utim_cli', '--help'], { shell: useShell, timeout: 5000 });
75
+ const probe = spawnSync(
76
+ python,
77
+ ['-c', 'import utim_cli'],
78
+ { shell: isWin, timeout: 5000 }
79
+ );
47
80
  if (probe.status === 0) {
48
- const proc = spawn(python, ['-m', 'utim_cli.utim', ...args], { stdio: 'inherit', shell: useShell });
49
- proc.on('exit', (code) => process.exit(code == null ? 0 : code));
50
- return true;
81
+ return launch(python, ['-m', 'utim_cli.utim', ...args]);
51
82
  }
52
83
  } catch (_) {}
53
84
  return false;
54
85
  }
55
86
 
56
- // ── Last resort: install from PyPI and retry ─────────────────────────────────
87
+ // ── Install from PyPI then retry ─────────────────────────────────────────────
57
88
  function selfInstallAndRun(python) {
58
- console.error('\n⚙ First run: installing UTIM Python engine from PyPI...');
59
- const install = spawnSync(python, ['-m', 'pip', 'install', '--upgrade', 'utim-cli'], {
60
- stdio: 'inherit',
61
- shell: useShell,
62
- });
63
- if (install.status === 0) {
64
- // Retry the entry point after install
65
- return tryEntryPoint() || tryModule(python);
89
+ console.error('\n⚙ First run: installing UTIM Python engine from PyPI...\n');
90
+
91
+ // On Termux, prebuilt packages must be installed first
92
+ if (isTermux) {
93
+ console.error(
94
+ '💡 Termux detected. Installing prebuilt dependencies first...\n' +
95
+ ' Run these commands if install fails:\n' +
96
+ ' pkg install python-cryptography python-pydantic\n' +
97
+ ' pip install utim-cli\n'
98
+ );
66
99
  }
67
- return false;
100
+
101
+ const install = spawnSync(
102
+ python,
103
+ ['-m', 'pip', 'install', '--upgrade', 'utim-cli'],
104
+ { stdio: 'inherit', shell: isWin }
105
+ );
106
+
107
+ if (install.status !== 0) return false;
108
+
109
+ // Retry both paths after install
110
+ return tryEntryPoint() || tryModule(python);
68
111
  }
69
112
 
70
113
  // ── Main ─────────────────────────────────────────────────────────────────────
@@ -76,17 +119,28 @@ const ok =
76
119
  (python && selfInstallAndRun(python));
77
120
 
78
121
  if (!ok) {
79
- console.error('\nError: UTIM Engine could not start.');
80
- const isTermux = (process.env.PREFIX && process.env.PREFIX.includes('com.termux')) || fs.existsSync('/data/data/com.termux');
122
+ console.error('\n❌ UTIM Engine could not start.\n');
81
123
  if (isTermux) {
82
- console.error('\n💡 Note for Termux Users: Precompiled binaries are required to avoid Rust compiler errors (pydantic-core).');
83
- console.error(' Please run: pkg install python-cryptography python-pydantic');
84
- console.error(' And then: pip install utim-cli');
124
+ console.error(
125
+ '💡 Termux: Prebuilt packages are required to avoid compilation errors.\n' +
126
+ ' Run:\n' +
127
+ ' pkg install python-cryptography python-pydantic\n' +
128
+ ' pip install utim-cli\n'
129
+ );
85
130
  } else if (!python) {
86
- console.error('Python 3 was not found. On Termux run: pkg install python');
131
+ console.error(
132
+ 'Python 3 was not found on this system.\n' +
133
+ 'Please install Python 3.9+ from https://python.org\n' +
134
+ 'Then run: pip install utim-cli\n'
135
+ );
87
136
  } else {
88
- console.error(`Tried Python at: ${python}`);
89
- console.error('Run manually: pip install utim-cli or pip3 install --upgrade utim-cli');
137
+ console.error(
138
+ `Python found at: ${python}\n` +
139
+ 'The UTIM Python engine is not installed. Please run:\n' +
140
+ ' pip install utim-cli\n' +
141
+ 'or:\n' +
142
+ ' pip3 install --upgrade utim-cli\n'
143
+ );
90
144
  }
91
145
  process.exit(1);
92
146
  }
package/package.json CHANGED
@@ -1,44 +1,44 @@
1
- {
2
- "name": "@emend-ai/utim",
3
- "version": "1.43.3",
4
- "description": "UTIM – Universal Terminal Intelligence Manager. An agentic AI coding assistant for your terminal.",
5
- "keywords": [
6
- "ai",
7
- "agent",
8
- "cli",
9
- "coding-assistant",
10
- "agentic",
11
- "llm",
12
- "mcp",
13
- "utim"
14
- ],
15
- "homepage": "https://utim.ai",
16
- "bugs": {
17
- "url": "https://github.com/emendai/utim/issues"
18
- },
19
- "repository": {
20
- "type": "git",
21
- "url": "https://github.com/emendai/utim.git"
22
- },
23
- "license": "MIT",
24
- "author": "Emendai <support@emendai.com>",
25
- "bin": {
26
- "utim": "bin/utim.js"
27
- },
28
- "scripts": {
29
- "postinstall": "node scripts/postinstall.js"
30
- },
31
- "files": [
32
- "bin/utim.js",
33
- "scripts/postinstall.js",
34
- "README.md",
35
- "LICENSE"
36
- ],
37
- "engines": {
38
- "node": ">=16.0.0"
39
- },
40
- "publishConfig": {
41
- "access": "public",
42
- "registry": "https://registry.npmjs.org/"
43
- }
44
- }
1
+ {
2
+ "name": "@emend-ai/utim",
3
+ "version": "1.43.6",
4
+ "description": "UTIM – Universal Terminal Intelligence Manager. An agentic AI coding assistant for your terminal.",
5
+ "keywords": [
6
+ "ai",
7
+ "agent",
8
+ "cli",
9
+ "coding-assistant",
10
+ "agentic",
11
+ "llm",
12
+ "mcp",
13
+ "utim"
14
+ ],
15
+ "homepage": "https://utim.dev",
16
+ "bugs": {
17
+ "url": "https://github.com/emendai/utim/issues"
18
+ },
19
+ "repository": {
20
+ "type": "git",
21
+ "url": "https://github.com/emendai/utim.git"
22
+ },
23
+ "license": "MIT",
24
+ "author": "Emendai <support@emendai.com>",
25
+ "bin": {
26
+ "utim": "bin/utim.js"
27
+ },
28
+ "scripts": {
29
+ "postinstall": "node scripts/postinstall.js"
30
+ },
31
+ "files": [
32
+ "bin/utim.js",
33
+ "scripts/postinstall.js",
34
+ "README.md",
35
+ "LICENSE"
36
+ ],
37
+ "engines": {
38
+ "node": ">=16.0.0"
39
+ },
40
+ "publishConfig": {
41
+ "access": "public",
42
+ "registry": "https://registry.npmjs.org/"
43
+ }
44
+ }