dex-termux-cli 0.2.3 → 0.3.0-beta.1

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.
@@ -10,6 +10,7 @@ import {
10
10
  } from '../core/config.js';
11
11
  import { printSection } from '../ui/output.js';
12
12
  import { detectProjectContext } from '../utils/project-context.js';
13
+ import { isAndroidStoragePath, resolvePlatformMode, shouldRestrictProjectToAndroidStorage } from '../utils/platform.js';
13
14
 
14
15
  const RUNTIME_CANDIDATES = {
15
16
  python: [
@@ -23,6 +24,7 @@ const RUNTIME_CANDIDATES = {
23
24
  ruby: ['ruby', '/data/data/com.termux/files/usr/bin/ruby'],
24
25
  go: ['go', '/data/data/com.termux/files/usr/bin/go'],
25
26
  rust: ['rustc', '/data/data/com.termux/files/usr/bin/rustc'],
27
+ java: ['java', '/data/data/com.termux/files/usr/bin/java'],
26
28
  };
27
29
 
28
30
  const RUNTIME_PACKAGES = {
@@ -32,6 +34,7 @@ const RUNTIME_PACKAGES = {
32
34
  ruby: ['ruby'],
33
35
  go: ['golang'],
34
36
  rust: ['rust'],
37
+ java: [],
35
38
  };
36
39
 
37
40
  const RUNTIME_SMOKE_TESTS = {
@@ -41,20 +44,31 @@ const RUNTIME_SMOKE_TESTS = {
41
44
  ruby: ['-e', 'puts "dex-ok"'],
42
45
  go: ['version'],
43
46
  rust: ['--version'],
47
+ java: ['--version'],
44
48
  };
45
49
 
46
50
  const TOOL_CANDIDATES = {
47
51
  npm: ['npm', '/data/data/com.termux/files/usr/bin/npm'],
48
52
  composer: ['composer', '/data/data/com.termux/files/usr/bin/composer'],
53
+ bundle: ['bundle', '/data/data/com.termux/files/usr/bin/bundle'],
54
+ cargo: ['cargo', '/data/data/com.termux/files/usr/bin/cargo'],
55
+ mvn: ['mvn', '/data/data/com.termux/files/usr/bin/mvn'],
56
+ gradle: ['gradle', '/data/data/com.termux/files/usr/bin/gradle'],
49
57
  };
50
58
 
51
59
  const TOOL_SMOKE_TESTS = {
52
60
  npm: ['--version'],
53
61
  composer: ['--version'],
62
+ bundle: ['--version'],
63
+ cargo: ['--version'],
64
+ mvn: ['--version'],
65
+ gradle: ['--version'],
54
66
  };
55
67
 
56
68
  const TOOL_PACKAGES = {
57
69
  composer: ['composer'],
70
+ mvn: [],
71
+ gradle: [],
58
72
  };
59
73
 
60
74
  const PYTHON_IMPORT_TO_PACKAGE = {
@@ -97,31 +111,38 @@ export async function runInstallCommand() {
97
111
  }
98
112
 
99
113
  const projectContext = await detectProjectContext();
114
+ const platformMode = resolvePlatformMode(config);
100
115
  if (!projectContext) {
101
- throw new Error('No pude detectar el lenguaje del proyecto actual.');
116
+ throw new Error('No pude detectar el lenguaje del proyecto actual. Entra al root del proyecto o a una subcarpeta que pertenezca a uno.');
102
117
  }
103
118
 
104
- const projectRoot = process.cwd();
119
+ const currentDir = process.cwd();
120
+ const projectRoot = projectContext.projectRoot || currentDir;
105
121
  const projectKey = getProjectKey(projectRoot);
106
122
  const storedProjectState = config.projects?.[projectKey] || null;
107
123
  const installMode = await detectInstallMode(projectContext.type, projectRoot);
108
- const runtime = await ensureRuntimeAvailable(projectContext.type);
124
+ const runtime = await ensureRuntimeAvailable(projectContext.type, platformMode);
109
125
 
110
126
  if (!runtime) {
111
- throw new Error(`No encontre el runtime para ${projectContext.label} y no pude instalarlo con pkg.`);
127
+ throw new Error(platformMode === 'termux'
128
+ ? `No encontre el runtime para ${projectContext.label} en este entorno y tampoco pude instalarlo con pkg.`
129
+ : `No encontre el runtime para ${projectContext.label}. En modo Linux instala el runtime manualmente y luego vuelve a correr dex -i.`);
112
130
  }
113
131
 
114
132
  if (!installMode) {
115
133
  throw new Error(
116
- `Detecte ${projectContext.label} y el runtime ya esta listo, pero Dex todavia no sabe instalar dependencias para ese lenguaje.`,
134
+ `Detecte ${projectContext.label} en ${projectRoot}, pero no encontre un archivo o patron de instalacion que Dex sepa usar todavia.`,
117
135
  );
118
136
  }
119
137
 
120
- const installCommand = await ensureInstallCommandAvailable(runtime, installMode);
121
- const preferSafeMode = shouldUseSafeMode(projectContext.type, projectRoot, storedProjectState);
138
+ const installCommand = await ensureInstallCommandAvailable(runtime, installMode, platformMode);
139
+ const preferSafeMode = shouldUseSafeMode(projectContext.type, projectRoot, storedProjectState, platformMode);
122
140
 
123
141
  printSection('Instalar Proyecto');
124
142
  console.log(`Proyecto : ${projectRoot}`);
143
+ if (currentDir !== projectRoot) {
144
+ console.log(`Desde : ${currentDir}`);
145
+ }
125
146
  console.log(`Lenguaje : ${projectContext.label}`);
126
147
  console.log(`Modo : ${installMode.label}`);
127
148
  console.log(`Runtime : ${runtime}`);
@@ -144,6 +165,7 @@ export async function runInstallCommand() {
144
165
  projectKey,
145
166
  projectContext,
146
167
  reason: storedProjectState?.lastFailureReason || 'preferencia guardada',
168
+ platformMode,
147
169
  });
148
170
  return;
149
171
  }
@@ -158,12 +180,15 @@ export async function runInstallCommand() {
158
180
  return;
159
181
  }
160
182
 
183
+ console.log('Dex nota: la instalacion normal fallo. Revisando rescate seguro...');
184
+ console.log('');
185
+
161
186
  if (!supportsSafeMode(projectContext.type)) {
162
187
  throw new Error(`La instalacion fallo y el rescate automatico aun no existe para ${projectContext.label}.`);
163
188
  }
164
189
 
165
- if (!isAndroidStoragePath(projectRoot)) {
166
- throw new Error('La instalacion fallo y el proyecto no esta en Android storage. No aplique rescate automatico.');
190
+ if (shouldRestrictProjectToAndroidStorage(platformMode) && !isAndroidStoragePath(projectRoot)) {
191
+ throw new Error('La instalacion normal fallo y el proyecto no esta en Android storage. En Termux, el rescate automatico solo se aplica a proyectos dentro de /sdcard o /storage/emulated/0.');
167
192
  }
168
193
 
169
194
  await saveProjectState(projectKey, {
@@ -185,6 +210,7 @@ export async function runInstallCommand() {
185
210
  projectKey,
186
211
  projectContext,
187
212
  reason: 'fallo instalacion normal en Android storage',
213
+ platformMode,
188
214
  });
189
215
  }
190
216
 
@@ -196,12 +222,13 @@ async function runSafeInstall({
196
222
  projectKey,
197
223
  projectContext,
198
224
  reason,
225
+ platformMode,
199
226
  }) {
200
227
  if (!supportsSafeMode(projectContext.type)) {
201
228
  throw new Error(`El modo seguro directo aun no existe para ${projectContext.label}.`);
202
229
  }
203
230
 
204
- if (!isAndroidStoragePath(projectRoot)) {
231
+ if (shouldRestrictProjectToAndroidStorage(platformMode) && !isAndroidStoragePath(projectRoot)) {
205
232
  throw new Error('El modo seguro directo solo existe para proyectos dentro de Android storage.');
206
233
  }
207
234
 
@@ -213,7 +240,7 @@ async function runSafeInstall({
213
240
  console.log(`Regreso : ${projectRoot}`);
214
241
  console.log('');
215
242
 
216
- await ensurePythonSystemPackages(installMode);
243
+ await ensurePythonSystemPackages(installMode, platformMode);
217
244
  await ensureRescueVenv(runtime, venvDir);
218
245
 
219
246
  const rescuePython = path.join(venvDir, 'bin', 'python');
@@ -260,7 +287,7 @@ async function runSafeInstall({
260
287
  console.log(`Origen : ${projectRoot}`);
261
288
  console.log('');
262
289
 
263
- await syncProjectToSafeWorkspace(projectRoot, safeProjectDir);
290
+ await syncProjectToSafeWorkspace(projectRoot, safeProjectDir, projectContext.type);
264
291
 
265
292
  const rescueExitCode = await runCommand(installCommand, installMode.args, safeProjectDir);
266
293
  if (rescueExitCode !== 0) {
@@ -305,7 +332,7 @@ async function runSafeInstall({
305
332
  console.log(`Origen : ${projectRoot}`);
306
333
  console.log('');
307
334
 
308
- await syncProjectToSafeWorkspace(projectRoot, safeProjectDir);
335
+ await syncProjectToSafeWorkspace(projectRoot, safeProjectDir, projectContext.type);
309
336
 
310
337
  const rescueExitCode = await runCommand(installCommand, installMode.args, safeProjectDir);
311
338
  if (rescueExitCode !== 0) {
@@ -342,13 +369,58 @@ async function runSafeInstall({
342
369
  return;
343
370
  }
344
371
 
372
+ if (projectContext.type === 'ruby' || projectContext.type === 'go' || projectContext.type === 'rust' || projectContext.type === 'java') {
373
+ const safeProjectDir = getSafeProjectWorkspacePath(projectRoot, projectContext.type);
374
+ console.log(`Modo Dex : entrando directo al entorno seguro (${reason}).`);
375
+ console.log(`Base HOME: ${process.env.HOME || '/data/data/com.termux/files/home'}`);
376
+ console.log(`Seguro : ${safeProjectDir}`);
377
+ console.log(`Origen : ${projectRoot}`);
378
+ console.log('');
379
+
380
+ await syncProjectToSafeWorkspace(projectRoot, safeProjectDir, projectContext.type);
381
+
382
+ const rescueExitCode = await runCommand(installCommand, installMode.args, safeProjectDir);
383
+ if (rescueExitCode !== 0) {
384
+ await saveProjectState(projectKey, {
385
+ path: projectRoot,
386
+ language: projectContext.type,
387
+ preferSafeInstall: true,
388
+ lastFailureReason: 'fallo tambien en entorno seguro',
389
+ installModeLabel: installMode.label,
390
+ packages: installMode.packages || [],
391
+ safeMode: getSafeModeKind(projectContext.type),
392
+ safeWorkspacePath: safeProjectDir,
393
+ updatedAt: new Date().toISOString(),
394
+ });
395
+
396
+ throw new Error('La instalacion tambien fallo dentro del entorno seguro.');
397
+ }
398
+
399
+ await saveProjectState(projectKey, {
400
+ path: projectRoot,
401
+ language: projectContext.type,
402
+ preferSafeInstall: true,
403
+ lastFailureReason: '',
404
+ installModeLabel: installMode.label,
405
+ packages: installMode.packages || [],
406
+ safeMode: getSafeModeKind(projectContext.type),
407
+ safeWorkspacePath: safeProjectDir,
408
+ updatedAt: new Date().toISOString(),
409
+ lastSuccessAt: new Date().toISOString(),
410
+ });
411
+
412
+ console.log(`Instalacion completada usando espacio seguro de Dex para ${projectContext.label}.`);
413
+ console.log(`Seguro : ${safeProjectDir}`);
414
+ return;
415
+ }
416
+
345
417
  throw new Error(`El modo seguro directo aun no existe para ${projectContext.label}.`);
346
418
  }
347
419
 
348
- function shouldUseSafeMode(projectType, projectRoot, projectState) {
420
+ function shouldUseSafeMode(projectType, projectRoot, projectState, platformMode) {
349
421
  return Boolean(
350
422
  supportsSafeMode(projectType)
351
- && isAndroidStoragePath(projectRoot)
423
+ && (!shouldRestrictProjectToAndroidStorage(platformMode) || isAndroidStoragePath(projectRoot))
352
424
  && projectState?.preferSafeInstall,
353
425
  );
354
426
  }
@@ -412,6 +484,105 @@ async function detectInstallMode(projectType, projectRoot) {
412
484
  }
413
485
  }
414
486
 
487
+ if (projectType === 'ruby') {
488
+ const gemfileLockPath = path.join(projectRoot, 'Gemfile.lock');
489
+ if (await pathExists(gemfileLockPath)) {
490
+ return {
491
+ label: 'Gemfile.lock',
492
+ commandType: 'tool',
493
+ tool: 'bundle',
494
+ args: ['install'],
495
+ };
496
+ }
497
+
498
+ const gemfilePath = path.join(projectRoot, 'Gemfile');
499
+ if (await pathExists(gemfilePath)) {
500
+ return {
501
+ label: 'Gemfile',
502
+ commandType: 'tool',
503
+ tool: 'bundle',
504
+ args: ['install'],
505
+ };
506
+ }
507
+ }
508
+
509
+ if (projectType === 'go') {
510
+ const goModPath = path.join(projectRoot, 'go.mod');
511
+ if (await pathExists(goModPath)) {
512
+ return {
513
+ label: 'go.mod',
514
+ commandType: 'runtime',
515
+ args: ['mod', 'download'],
516
+ };
517
+ }
518
+ }
519
+
520
+ if (projectType === 'rust') {
521
+ const cargoLockPath = path.join(projectRoot, 'Cargo.lock');
522
+ if (await pathExists(cargoLockPath)) {
523
+ return {
524
+ label: 'Cargo.lock',
525
+ commandType: 'tool',
526
+ tool: 'cargo',
527
+ args: ['fetch'],
528
+ };
529
+ }
530
+
531
+ const cargoTomlPath = path.join(projectRoot, 'Cargo.toml');
532
+ if (await pathExists(cargoTomlPath)) {
533
+ return {
534
+ label: 'Cargo.toml',
535
+ commandType: 'tool',
536
+ tool: 'cargo',
537
+ args: ['fetch'],
538
+ };
539
+ }
540
+ }
541
+
542
+ if (projectType === 'java') {
543
+ const mavenWrapper = await findJavaWrapper(projectRoot, ['mvnw']);
544
+ const gradleWrapper = await findJavaWrapper(projectRoot, ['gradlew']);
545
+ const pomPath = path.join(projectRoot, 'pom.xml');
546
+ const gradlePath = path.join(projectRoot, 'build.gradle');
547
+ const gradleKtsPath = path.join(projectRoot, 'build.gradle.kts');
548
+
549
+ if (mavenWrapper && await pathExists(pomPath)) {
550
+ return {
551
+ label: path.basename(mavenWrapper),
552
+ commandType: 'local-script',
553
+ script: mavenWrapper,
554
+ args: ['dependency:go-offline'],
555
+ };
556
+ }
557
+
558
+ if (await pathExists(pomPath)) {
559
+ return {
560
+ label: 'pom.xml',
561
+ commandType: 'tool',
562
+ tool: 'mvn',
563
+ args: ['dependency:go-offline'],
564
+ };
565
+ }
566
+
567
+ if (gradleWrapper && (await pathExists(gradlePath) || await pathExists(gradleKtsPath))) {
568
+ return {
569
+ label: path.basename(gradleWrapper),
570
+ commandType: 'local-script',
571
+ script: gradleWrapper,
572
+ args: ['dependencies'],
573
+ };
574
+ }
575
+
576
+ if (await pathExists(gradlePath) || await pathExists(gradleKtsPath)) {
577
+ return {
578
+ label: (await pathExists(gradleKtsPath)) ? 'build.gradle.kts' : 'build.gradle',
579
+ commandType: 'tool',
580
+ tool: 'gradle',
581
+ args: ['dependencies'],
582
+ };
583
+ }
584
+ }
585
+
415
586
  if (projectType !== 'python') {
416
587
  return null;
417
588
  }
@@ -456,18 +627,24 @@ async function detectInstallMode(projectType, projectRoot) {
456
627
  return null;
457
628
  }
458
629
 
459
- async function ensureInstallCommandAvailable(runtime, installMode) {
630
+ async function ensureInstallCommandAvailable(runtime, installMode, platformMode) {
460
631
  if (installMode.commandType === 'runtime') {
461
632
  return runtime;
462
633
  }
463
634
 
635
+ if (installMode.commandType === 'local-script' && installMode.script) {
636
+ return installMode.script;
637
+ }
638
+
464
639
  if (installMode.commandType === 'tool' && installMode.tool) {
465
- const tool = await ensureToolAvailable(installMode.tool);
640
+ const tool = await ensureToolAvailable(installMode.tool, platformMode);
466
641
  if (tool) {
467
642
  return tool;
468
643
  }
469
644
 
470
- throw new Error(`No encontre la herramienta ${installMode.tool} para completar la instalacion segura.`);
645
+ throw new Error(platformMode === 'termux'
646
+ ? `No encontre la herramienta ${installMode.tool} para completar la instalacion segura.`
647
+ : `No encontre la herramienta ${installMode.tool}. En modo Linux instalala manualmente y vuelve a correr dex -i.`);
471
648
  }
472
649
 
473
650
  throw new Error('Dex no pudo resolver el comando de instalacion para este proyecto.');
@@ -593,12 +770,16 @@ function extractPythonImports(source) {
593
770
  return modules;
594
771
  }
595
772
 
596
- async function ensureRuntimeAvailable(projectType) {
773
+ async function ensureRuntimeAvailable(projectType, platformMode) {
597
774
  const runtime = await findRuntimeExecutable(projectType);
598
775
  if (runtime) {
599
776
  return runtime;
600
777
  }
601
778
 
779
+ if (platformMode !== 'termux') {
780
+ return '';
781
+ }
782
+
602
783
  const installed = await installRuntimeWithPkg(projectType);
603
784
  if (!installed) {
604
785
  return '';
@@ -635,12 +816,16 @@ async function findToolExecutable(toolName) {
635
816
  return '';
636
817
  }
637
818
 
638
- async function ensureToolAvailable(toolName) {
819
+ async function ensureToolAvailable(toolName, platformMode) {
639
820
  const tool = await findToolExecutable(toolName);
640
821
  if (tool) {
641
822
  return tool;
642
823
  }
643
824
 
825
+ if (platformMode !== 'termux') {
826
+ return '';
827
+ }
828
+
644
829
  const installed = await installToolWithPkg(toolName);
645
830
  if (!installed) {
646
831
  return '';
@@ -701,7 +886,11 @@ function throwPkgInstallError(projectType, output) {
701
886
  throw new Error(`No pude instalar ${projectType} con pkg. Revisa la salida anterior para ver el motivo exacto.`);
702
887
  }
703
888
 
704
- async function ensurePythonSystemPackages(installMode) {
889
+ async function ensurePythonSystemPackages(installMode, platformMode) {
890
+ if (platformMode !== 'termux') {
891
+ return;
892
+ }
893
+
705
894
  const packages = gatherSystemPackagesForPythonInstall(installMode);
706
895
  if (!packages.length) {
707
896
  return;
@@ -868,9 +1057,37 @@ function getSafeProjectWorkspacePath(projectRoot, projectType) {
868
1057
  return path.join(home, '.dex', 'projects', safeKind, `${safeName}-${digest}`);
869
1058
  }
870
1059
 
871
- async function syncProjectToSafeWorkspace(projectRoot, safeProjectDir) {
1060
+ async function syncProjectToSafeWorkspace(projectRoot, safeProjectDir, projectType) {
872
1061
  await fs.mkdir(safeProjectDir, { recursive: true });
1062
+ await resetDirectoryContents(safeProjectDir);
873
1063
  await copyDirectoryRecursive(projectRoot, safeProjectDir);
1064
+ await writeSafeWorkspaceMeta(safeProjectDir, projectRoot, projectType);
1065
+ }
1066
+
1067
+ async function resetDirectoryContents(targetDir) {
1068
+ let entries = [];
1069
+
1070
+ try {
1071
+ entries = await fs.readdir(targetDir, { withFileTypes: true });
1072
+ } catch {
1073
+ return;
1074
+ }
1075
+
1076
+ for (const entry of entries) {
1077
+ await fs.rm(path.join(targetDir, entry.name), { recursive: true, force: true });
1078
+ }
1079
+ }
1080
+
1081
+ async function writeSafeWorkspaceMeta(safeProjectDir, projectRoot, projectType) {
1082
+ const metadataPath = path.join(safeProjectDir, '.dex-workspace.json');
1083
+ const metadata = {
1084
+ projectRoot,
1085
+ projectType,
1086
+ generatedAt: new Date().toISOString(),
1087
+ };
1088
+
1089
+ await fs.writeFile(metadataPath, `${JSON.stringify(metadata, null, 2)}
1090
+ `, 'utf8');
874
1091
  }
875
1092
 
876
1093
  async function copyDirectoryRecursive(sourceDir, targetDir) {
@@ -904,11 +1121,21 @@ async function copyDirectoryRecursive(sourceDir, targetDir) {
904
1121
 
905
1122
  function shouldSkipSafeCopy(name) {
906
1123
  return name === '.git'
907
- || name === 'node_modules'
908
- || name === 'vendor'
1124
+ || name === '.gradle'
1125
+ || name === '.idea'
1126
+ || name === '.vscode'
1127
+ || name === '.mypy_cache'
1128
+ || name === '.pytest_cache'
1129
+ || name === '.ruff_cache'
909
1130
  || name === '.venv'
910
1131
  || name === 'venv'
911
- || name === '__pycache__';
1132
+ || name === '__pycache__'
1133
+ || name === 'node_modules'
1134
+ || name === 'vendor'
1135
+ || name === 'target'
1136
+ || name === 'dist'
1137
+ || name === 'build'
1138
+ || name === 'bin';
912
1139
  }
913
1140
 
914
1141
  async function pathExists(targetPath) {
@@ -920,12 +1147,20 @@ async function pathExists(targetPath) {
920
1147
  }
921
1148
  }
922
1149
 
923
- function isAndroidStoragePath(projectRoot) {
924
- return projectRoot.startsWith('/sdcard') || projectRoot.startsWith('/storage/emulated/0');
1150
+
1151
+ async function findJavaWrapper(projectRoot, names) {
1152
+ for (const name of names) {
1153
+ const targetPath = path.join(projectRoot, name);
1154
+ if (await pathExists(targetPath)) {
1155
+ return targetPath;
1156
+ }
1157
+ }
1158
+
1159
+ return '';
925
1160
  }
926
1161
 
927
1162
  function supportsSafeMode(projectType) {
928
- return projectType === 'python' || projectType === 'node' || projectType === 'php';
1163
+ return projectType === 'python' || projectType === 'node' || projectType === 'php' || projectType === 'ruby' || projectType === 'go' || projectType === 'rust' || projectType === 'java';
929
1164
  }
930
1165
 
931
1166
  function getSafeModeKind(projectType) {
@@ -941,6 +1176,22 @@ function getSafeModeKind(projectType) {
941
1176
  return 'php-workspace';
942
1177
  }
943
1178
 
1179
+ if (projectType === 'ruby') {
1180
+ return 'ruby-workspace';
1181
+ }
1182
+
1183
+ if (projectType === 'go') {
1184
+ return 'go-workspace';
1185
+ }
1186
+
1187
+ if (projectType === 'rust') {
1188
+ return 'rust-workspace';
1189
+ }
1190
+
1191
+ if (projectType === 'java') {
1192
+ return 'java-workspace';
1193
+ }
1194
+
944
1195
  return '';
945
1196
  }
946
1197
 
@@ -1,4 +1,10 @@
1
- import { loadUserConfig, setFeatureEnabled, setPromptContextPosition } from '../core/config.js';
1
+ import {
2
+ loadUserConfig,
3
+ setFeatureEnabled,
4
+ setPlatformMode,
5
+ setPromptContextPosition,
6
+ } from '../core/config.js';
7
+ import { formatPlatformMode, resolvePlatformMode } from '../utils/platform.js';
2
8
  import { runContextCommand } from './context.js';
3
9
  import { runExplainCommand } from './explain.js';
4
10
  import { runSafeShellCommand } from './safe-shell.js';
@@ -8,6 +14,7 @@ import { runVersionCommand } from './version.js';
8
14
  import {
9
15
  chooseFeatureToggle,
10
16
  chooseMenuAction,
17
+ choosePlatformMode,
11
18
  choosePromptContextPosition,
12
19
  chooseSearchPatternFromMenu,
13
20
  chooseSettingsAction,
@@ -77,11 +84,25 @@ async function runSettingsMenu() {
77
84
  return;
78
85
  }
79
86
 
87
+ if (action === 'platform-mode') {
88
+ const currentMode = formatPlatformMode(resolvePlatformMode(config));
89
+ const mode = await choosePlatformMode(currentMode);
90
+
91
+ if (mode === 'back') {
92
+ continue;
93
+ }
94
+
95
+ await setPlatformMode(mode);
96
+ console.log('Modo de plataforma: ' + formatPlatformModeLabel(mode) + '.');
97
+ console.log('');
98
+ continue;
99
+ }
100
+
80
101
  if (action === 'toggle-android-shortcut') {
81
102
  const toggle = await chooseFeatureToggle(
82
103
  config.features.androidShortcut,
83
104
  'Acceso rapido a Android',
84
- 'permite usar dex -a o dex --android',
105
+ 'permite usar dex -a',
85
106
  );
86
107
 
87
108
  if (toggle === 'back') {
@@ -130,7 +151,7 @@ async function runSettingsMenu() {
130
151
  const toggle = await chooseFeatureToggle(
131
152
  config.features.smartProjectInstall,
132
153
  'Instalacion segura de proyectos',
133
- 'instala dependencias y si falta el runtime intenta traerlo con pkg',
154
+ 'rescata instalaciones y puede instalar runtimes con pkg en Termux',
134
155
  );
135
156
 
136
157
  if (toggle === 'back') {
@@ -156,3 +177,15 @@ function formatPromptContextPosition(position) {
156
177
 
157
178
  return 'a la derecha';
158
179
  }
180
+
181
+ function formatPlatformModeLabel(mode) {
182
+ if (mode === 'linux') {
183
+ return 'linux';
184
+ }
185
+
186
+ if (mode === 'termux') {
187
+ return 'termux';
188
+ }
189
+
190
+ return 'auto';
191
+ }