deel-local-cli 1.20.6 → 1.20.8

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/src/tools/jobs.js CHANGED
@@ -384,6 +384,35 @@ class 일감 {
384
384
  while (this.바이트 > 출력상한 && this.조각들.length > 1) {
385
385
  this.바이트 -= this.조각들.shift().length;
386
386
  }
387
+ /*
388
+ * 한 조각이 **혼자** 상한을 넘으면 그 조각의 뒤만 남긴다.
389
+ *
390
+ * 위 되풀이는 조각이 둘 이상일 때만 버린다. 그래서 한 조각이 혼자 넘치면
391
+ * **아무것도 못 버리는데 아래에서 잘렸다고 적는다.** 그 사이에 읽으면
392
+ * 멀쩡한 글에 "앞이 잘렸습니다" 가 붙고 읽은 자리도 0 으로 돌아간다 —
393
+ * 모델은 없는 앞을 찾으러 처음부터 다시 읽는다. (다음 조각이 들어오면
394
+ * 그때는 둘이 되어 버려지므로, 거짓말은 그 한 판만이다. 그래도 그 한
395
+ * 판이 되풀이를 부르는 자리다 — 읽기() 머리말 참고.)
396
+ *
397
+ * 그리고 버릴 수 있게 만들어 두는 것이 맞다. 상한 위에 남겨 두면 그
398
+ * 다음 조각 하나에 256KB 가 통째로 날아간다.
399
+ *
400
+ * 베껴 담는다. subarray 는 원래 덩이를 그대로 붙잡고 있어서, 큰 조각
401
+ * 하나가 들어온 판에서는 놓으려는 그 메모리가 안 놓인다.
402
+ */
403
+ if (this.바이트 > 출력상한 && this.조각들.length === 1) {
404
+ const 하나 = this.조각들[0];
405
+ this.조각들[0] = Buffer.from(하나.subarray(하나.length - 출력상한));
406
+ this.바이트 = this.조각들[0].length;
407
+ }
408
+ /*
409
+ * 여기 오면 **반드시 무엇인가 버렸다** — 그래서 「안 버렸으면」 갈래를
410
+ * 두지 않는다. 위에서 상한을 넘은 것을 확인했고, 조각이 둘 이상이면
411
+ * 되풀이가 버리고 하나뿐이면 그 하나를 줄였다. 늘 참인 조건을 남기면
412
+ * 어긋내기가 「그 줄을 지워도 아무 검사도 안 깨진다」 고 말하는데, 그건
413
+ * 맞는 말이라 고칠 수도 없다 — 대신 읽는 사람은 안 버리는 길이 따로
414
+ * 있는 줄로 읽는다.
415
+ */
387
416
  this.앞잘림 = true;
388
417
  this.막버렸다 = true;
389
418
  this.읽은글자 = 0;
@@ -516,10 +545,24 @@ export async function 띄우기(명령, { cwd, 설명 = null, 기다림 = 1500,
516
545
 
517
546
  kid.stdout?.on('data', (b) => j.담기(b));
518
547
  kid.stderr?.on('data', (b) => j.담기(b));
519
- kid.on('error', (err) => { j.담기(Buffer.from(`\n[띄우기 실패: ${err.message}]\n`)); j.상태 = '끝남'; j.종료코드 = -1; });
548
+ kid.on('error', (err) => {
549
+ j.담기(Buffer.from(`\n[띄우기 실패: ${err.message}]\n`));
550
+ j.상태 = '끝남';
551
+ j.종료코드 = -1;
552
+ // 왜 표를 세우나 — 바로 아래 close 머리말.
553
+ j.띄우기실패 = true;
554
+ });
520
555
  kid.on('close', (code, sig) => {
521
556
  if (j.상태 === '죽임') return;
522
557
  j.상태 = '끝남';
558
+ /*
559
+ * 띄우기 자체가 실패한 판은 **덮지 않는다.**
560
+ *
561
+ * 명령이 없으면(ENOENT) Node 는 error 를 낸 다음 close 를 code=null 로
562
+ * 부른다. 그러면 위에서 세워 둔 -1 이 null 로 덮이고, null 은 이 자리에서
563
+ * 「시그널로 죽었다」 와 구별이 안 된다. 안 뜬 까닭이 종료코드에서 지워진다.
564
+ */
565
+ if (j.띄우기실패) { 끝난것치우기(); return; }
523
566
  j.종료코드 = sig ? null : code;
524
567
  j.시그널 = sig ?? null;
525
568
  // 끝난 것이 쌓이지 않게. 도는 것은 최대일감 이 따로 막는다.
@@ -628,7 +671,17 @@ export async function 끝내기(번호) {
628
671
  */
629
672
  await 죽는말기다리기(j.kid, 죽는말기다림);
630
673
  }
631
- 파이프끊기(j.kid);
674
+ /*
675
+ * ── 안 죽은 놈의 파이프는 **끊지 않는다** ──────────────────────────────
676
+ *
677
+ * 여기서 늘 끊고 있었다. 그런데 바로 아래에서 「그러고도 안 죽었으면 목록에
678
+ * 남긴다 — 다시 시킬 수 있어야 한다」 고 한다. 파이프를 이미 끊어 놓고
679
+ * 남기면, 목록에는 `도는중` 으로 뜨는데 그놈이 뱉는 말은 다시는 안 들어온다.
680
+ * 사람은 화면을 보며 기다리고, 자식은 다음 쓰기에서 EPIPE 를 맞는다.
681
+ * 남겨 두기로 한 까닭이 「다시 볼 수 있게」 인데 정작 볼 길을 끊던 셈이다.
682
+ */
683
+ const 죽었나 = !아직사나(j.kid);
684
+ if (죽었나) 파이프끊기(j.kid);
632
685
  const 남은 = j.읽기({});
633
686
  /*
634
687
  * ★ 그러고도 안 죽었으면 **그렇다고 말한다.**
@@ -640,7 +693,7 @@ export async function 끝내기(번호) {
640
693
  *
641
694
  * 안 죽었으면 목록에 남긴다. 그래야 사람이 한 번 더 시킬 수 있다.
642
695
  */
643
- if (아직사나(j.kid)) {
696
+ if (!죽었나) {
644
697
  j.상태 = '도는중'; // 지우지 않는다 — 다시 시킬 수 있어야 한다
645
698
  return { 이미: false, 안죽음: true, 명령: j.명령, 초: j.산햇수(), 남은: 남은.글 };
646
699
  }
@@ -723,6 +776,8 @@ export function 일감인자(args) {
723
776
  };
724
777
  const 날번호 = 하나씩('번호');
725
778
  return {
779
+ // 날것을 같이 내놓는다 — 숫자가 아닐 때 **무엇을 받았는지** 적어야 한다.
780
+ 날번호,
726
781
  번호: 날번호 == null ? null : Number(날번호),
727
782
  끝내기: !!하나씩('끝내기'),
728
783
  처음부터: !!하나씩('처음부터'),
@@ -791,11 +846,34 @@ export const JOBS_TOOL = {
791
846
  + ' 번호 없이 부르면 목록입니다.',
792
847
  };
793
848
  }
849
+ /*
850
+ * 몇 개만 못 알아들은 판도 **말해 준다.**
851
+ *
852
+ * 위 갈래는 「하나도」 못 알아들었을 때만 걸린다. 그래서
853
+ * `{job: 1, action: 'stop'}` 은 걸리지 않고 — `action` 을 조용히 버린 뒤
854
+ * 출력만 읽어 **성공으로** 돌려줬다. 끄라고 시킨 모델은 껐다고 여기고
855
+ * 넘어가는데 서버는 그대로 돈다. 위 머리말이 없애겠다고 적어 둔 바로 그
856
+ * 고장이, 인자를 하나 더 붙인 판에 그대로 남아 있었다 (34차 리뷰).
857
+ *
858
+ * 오류로 막지는 않는다 — 알아들은 것은 하라고 시킨 것이 맞다. 대신 버린
859
+ * 이름을 적어 보내서, 뜻이 거기 있었으면 다음 걸음에서 고쳐 부르게 한다.
860
+ */
861
+ const 버린말 = 받은것.모르는것.length
862
+ ? `\n(못 알아들어 버린 인자: ${받은것.모르는것.join(', ')} — Jobs 는 job · stop · from_start 만 받습니다.`
863
+ + ' 끝내려던 것이면 stop: true 로 다시 불러라.)'
864
+ : '';
794
865
  const 번호 = 받은것.번호;
795
866
  // 숫자가 아닌 것을 받으면 NaN 이 되고, 그대로 두면 `NaN번 일감이 없습니다`
796
867
  // 라는 말이 모델에게 나간다. 무엇이 잘못됐는지 안 알려 주는 오류다.
797
868
  if (번호 != null && !Number.isFinite(번호)) {
798
- return { error: `번호는 숫자여야 합니다 (받은 것: ${JSON.stringify(args?.번호)}). 번호 없이 Jobs 를 불러 목록을 보세요.` };
869
+ /*
870
+ * 받은 것을 **실제로 읽은 그 칸**에서 적는다.
871
+ *
872
+ * 여기가 `args?.번호` 였다. 설명서에 실린 이름은 `job` 이라 모델은 거의
873
+ * 늘 `job` 으로 보내는데, 그러면 이 말은 `(받은 것: undefined)` 가 된다.
874
+ * 무엇을 잘못 보냈는지 알려 주려고 있는 줄이 정작 그것만 안 알려 줬다.
875
+ */
876
+ return { error: `번호는 숫자여야 합니다 (받은 것: ${JSON.stringify(받은것.날번호)}). 번호 없이 Jobs 를 불러 목록을 보세요.` };
799
877
  }
800
878
 
801
879
  if (번호 == null) {
@@ -830,7 +908,7 @@ export const JOBS_TOOL = {
830
908
  * 그러면 포트가 물려서 안 뜨고, 왜 안 되는지도 모른다.
831
909
  */
832
910
  if (치운것) 줄들.push(` (오래된 것 ${치운것}개는 자리를 위해 지웠습니다)`);
833
- return { content: 줄들.join('\n'), summary: 세말('count', ls.length), 일감수: ls.length };
911
+ return { content: 줄들.join('\n') + 버린말, summary: 세말('count', ls.length), 일감수: ls.length };
834
912
  }
835
913
 
836
914
  if (받은것.끝내기) {
@@ -854,7 +932,7 @@ export const JOBS_TOOL = {
854
932
  }
855
933
  return {
856
934
  content: `${번호}번을 끝냈습니다 (${r.초}초 돌았습니다): ${r.명령}`
857
- + (r.남은 ? `\n\n마지막 출력:\n${뒤만(r.남은, 2000).글}` : ''),
935
+ + (r.남은 ? `\n\n마지막 출력:\n${뒤만(r.남은, 2000).글}` : '') + 버린말,
858
936
  summary: 이어(말('sum.jobStopped'), 말('unit.sec', { n: r.초 })),
859
937
  };
860
938
  }
@@ -870,7 +948,7 @@ export const JOBS_TOOL = {
870
948
  ? (r.앞잘림 ? '(앞부분은 너무 길어 잘렸습니다 — 뒤쪽만 남았습니다)\n' : '') + 잘라낸.글
871
949
  : '(지난번 읽은 뒤로 새 출력이 없습니다)';
872
950
  return {
873
- content: `${머리}\n\n${몸}`,
951
+ content: `${머리}\n\n${몸}${버린말}`,
874
952
  summary: (r.상태 === '도는중' ? 이어(말('sum.jobRunning'), 말('unit.sec', { n: r.초 })) : 끝난말(r))
875
953
  + (잘라낸.줄임 ? ' · 일부만' : ''),
876
954
  // 끝난 일감이 종료코드 0 이 아니면 실패로 물들인다 — Bash 와 같은 규칙이다.