project-compass 2.6.0 → 2.7.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.
Files changed (2) hide show
  1. package/package.json +1 -1
  2. package/src/cli.js +69 -16
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "project-compass",
3
- "version": "2.6.0",
3
+ "version": "2.7.1",
4
4
  "description": "Ink-based project explorer that detects local repos and lets you build/test/run them without memorizing commands.",
5
5
  "main": "src/cli.js",
6
6
  "type": "module",
package/src/cli.js CHANGED
@@ -142,9 +142,9 @@ function Studio() {
142
142
  {flexDirection: 'column'},
143
143
  ...runtimes.map(r => create(
144
144
  Box,
145
- {key: r.name, marginBottom: 1},
146
- create(Text, {width: 15, color: r.status === 'ok' ? 'green' : 'red'}, `${r.status === 'ok' ? '✓' : '✗'} ${r.name}`),
147
- create(Text, {dimColor: r.status !== 'ok'}, r.version)
145
+ {key: r.name, marginBottom: 0},
146
+ create(Text, {width: 20, color: r.status === 'ok' ? 'green' : 'red'}, `${r.status === 'ok' ? '✓' : '✗'} ${r.name}`),
147
+ create(Text, {dimColor: r.status !== 'ok'}, `: ${r.version}`)
148
148
  )),
149
149
  create(Text, {marginTop: 1, color: 'yellow'}, '🛠️ Interactive Project Creator coming soon in v3.0'),
150
150
  create(Text, {dimColor: true}, 'Press Shift+A to return to Navigator.')
@@ -152,6 +152,20 @@ function Studio() {
152
152
  );
153
153
  }
154
154
 
155
+ function CursorText({value, cursorIndex, active = true}) {
156
+ const before = value.slice(0, cursorIndex);
157
+ const charAt = value[cursorIndex] || ' ';
158
+ const after = value.slice(cursorIndex + 1);
159
+
160
+ return create(
161
+ Text,
162
+ null,
163
+ before,
164
+ active ? create(Text, {backgroundColor: 'white', color: 'black'}, charAt) : charAt,
165
+ after
166
+ );
167
+ }
168
+
155
169
  function Compass({rootPath, initialView = 'navigator'}) {
156
170
  const {exit} = useApp();
157
171
  const {projects, loading, error} = useScanner(rootPath);
@@ -164,10 +178,12 @@ function Compass({rootPath, initialView = 'navigator'}) {
164
178
  const [lastAction, setLastAction] = useState(null);
165
179
  const [customMode, setCustomMode] = useState(false);
166
180
  const [customInput, setCustomInput] = useState('');
181
+ const [customCursor, setCustomCursor] = useState(0);
167
182
  const [config, setConfig] = useState(() => loadConfig());
168
183
  const [showHelpCards, setShowHelpCards] = useState(false);
169
184
  const [showStructureGuide, setShowStructureGuide] = useState(false);
170
185
  const [stdinBuffer, setStdinBuffer] = useState('');
186
+ const [stdinCursor, setStdinCursor] = useState(0);
171
187
  const [showHelp, setShowHelp] = useState(false);
172
188
  const [recentRuns, setRecentRuns] = useState([]);
173
189
  const selectedProject = projects[selectedIndex] || null;
@@ -241,6 +257,7 @@ function Compass({rootPath, initialView = 'navigator'}) {
241
257
  } finally {
242
258
  setRunning(false);
243
259
  setStdinBuffer('');
260
+ setStdinCursor(0);
244
261
  runningProcessRef.current = null;
245
262
  }
246
263
  }, [addLog, running, selectedProject]);
@@ -276,6 +293,7 @@ function Compass({rootPath, initialView = 'navigator'}) {
276
293
  addLog(kleur.gray('Canceled custom command (empty).'));
277
294
  setCustomMode(false);
278
295
  setCustomInput('');
296
+ setCustomCursor(0);
279
297
  return;
280
298
  }
281
299
  const [labelPart, commandPart] = raw.split('|');
@@ -284,12 +302,14 @@ function Compass({rootPath, initialView = 'navigator'}) {
284
302
  addLog(kleur.red('Custom command needs at least one token.'));
285
303
  setCustomMode(false);
286
304
  setCustomInput('');
305
+ setCustomCursor(0);
287
306
  return;
288
307
  }
289
308
  const label = commandPart ? labelPart.trim() : `Custom ${selectedProject.name}`;
290
309
  handleAddCustomCommand(label || 'Custom', commandTokens);
291
310
  setCustomMode(false);
292
311
  setCustomInput('');
312
+ setCustomCursor(0);
293
313
  }, [customInput, selectedProject, handleAddCustomCommand, addLog]);
294
314
 
295
315
  const exportLogs = useCallback(() => {
@@ -314,14 +334,27 @@ function Compass({rootPath, initialView = 'navigator'}) {
314
334
  if (key.escape) {
315
335
  setCustomMode(false);
316
336
  setCustomInput('');
337
+ setCustomCursor(0);
338
+ return;
339
+ }
340
+ if (key.backspace || key.delete) {
341
+ if (customCursor > 0) {
342
+ setCustomInput((prev) => prev.slice(0, customCursor - 1) + prev.slice(customCursor));
343
+ setCustomCursor(c => Math.max(0, c - 1));
344
+ }
345
+ return;
346
+ }
347
+ if (key.leftArrow) {
348
+ setCustomCursor(c => Math.max(0, c - 1));
317
349
  return;
318
350
  }
319
- if (key.backspace) {
320
- setCustomInput((prev) => prev.slice(0, -1));
351
+ if (key.rightArrow) {
352
+ setCustomCursor(c => Math.min(customInput.length, c + 1));
321
353
  return;
322
354
  }
323
355
  if (input) {
324
- setCustomInput((prev) => prev + input);
356
+ setCustomInput((prev) => prev.slice(0, customCursor) + input + prev.slice(customCursor));
357
+ setCustomCursor(c => c + input.length);
325
358
  }
326
359
  return;
327
360
  }
@@ -363,31 +396,43 @@ function Compass({rootPath, initialView = 'navigator'}) {
363
396
  if (key.ctrl && input === 'c') {
364
397
  runningProcessRef.current.kill('SIGINT');
365
398
  setStdinBuffer('');
399
+ setStdinCursor(0);
366
400
  return;
367
401
  }
368
402
  if (key.return) {
369
- runningProcessRef.current.stdin?.write('\n');
403
+ runningProcessRef.current.stdin?.write(stdinBuffer + '\n');
370
404
  setStdinBuffer('');
405
+ setStdinCursor(0);
406
+ return;
407
+ }
408
+ if (key.backspace || key.delete) {
409
+ if (stdinCursor > 0) {
410
+ setStdinBuffer(prev => prev.slice(0, stdinCursor - 1) + prev.slice(stdinCursor));
411
+ setStdinCursor(c => Math.max(0, c - 1));
412
+ }
413
+ return;
414
+ }
415
+ if (key.leftArrow) {
416
+ setStdinCursor(c => Math.max(0, c - 1));
371
417
  return;
372
418
  }
373
- if (key.backspace) {
374
- runningProcessRef.current.stdin?.write('\x08');
375
- setStdinBuffer((prev) => prev.slice(0, -1));
419
+ if (key.rightArrow) {
420
+ setStdinCursor(c => Math.min(stdinBuffer.length, c + 1));
376
421
  return;
377
422
  }
378
423
  if (input) {
379
- runningProcessRef.current.stdin?.write(input);
380
- setStdinBuffer((prev) => prev + input);
424
+ setStdinBuffer(prev => prev.slice(0, stdinCursor) + input + prev.slice(stdinCursor));
425
+ setStdinCursor(c => c + input.length);
381
426
  }
382
427
  return;
383
428
  }
384
429
 
385
430
  if (key.shift && key.upArrow) {
386
- scrollLogs(1);
431
+ scrollLogs(-1);
387
432
  return;
388
433
  }
389
434
  if (key.shift && key.downArrow) {
390
- scrollLogs(-1);
435
+ scrollLogs(1);
391
436
  return;
392
437
  }
393
438
 
@@ -422,6 +467,7 @@ function Compass({rootPath, initialView = 'navigator'}) {
422
467
  if (shiftCombo('c') && viewMode === 'detail' && selectedProject) {
423
468
  setCustomMode(true);
424
469
  setCustomInput('');
470
+ setCustomCursor(0);
425
471
  return;
426
472
  }
427
473
  const actionKey = normalizedInput && ACTION_MAP[normalizedInput];
@@ -529,7 +575,14 @@ function Compass({rootPath, initialView = 'navigator'}) {
529
575
  }
530
576
 
531
577
  if (customMode) {
532
- detailContent.push(create(Text, {key: 'custom-input', color: 'cyan'}, `Type label|cmd (Enter to save, Esc to cancel): ${customInput}`));
578
+ detailContent.push(
579
+ create(
580
+ Box,
581
+ {key: 'custom-input-box', flexDirection: 'row'},
582
+ create(Text, {color: 'cyan'}, 'Type label|cmd (Enter: save, Esc: cancel): '),
583
+ create(CursorText, {value: customInput, cursorIndex: customCursor})
584
+ )
585
+ );
533
586
  }
534
587
 
535
588
  const artTileNodes = useMemo(() => {
@@ -818,7 +871,7 @@ function Compass({rootPath, initialView = 'navigator'}) {
818
871
  paddingX: 1
819
872
  },
820
873
  create(Text, {bold: true, color: running ? 'green' : 'white'}, running ? ' Stdin buffer ' : ' Input ready '),
821
- create(Text, {dimColor: true, marginLeft: 1}, running ? (stdinBuffer || '(type to send)') : 'Start a command to feed stdin')
874
+ create(Box, {marginLeft: 1}, create(CursorText, {value: stdinBuffer || (running ? '' : 'Start a command to feed stdin'), cursorIndex: stdinCursor, active: running}))
822
875
  )
823
876
  ),
824
877
  helpSection,