deel-local-cli 2.0.0 → 2.0.3
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/README.ko.md +14 -5
- package/README.md +14 -5
- package/package.json +1 -1
- package/src/acp/serve.js +49 -12
- package/src/agent/commit.js +2 -2
- package/src/agent/compact.js +4 -4
- package/src/agent/grade.js +1 -1
- package/src/agent/loop.js +2 -2
- package/src/agent/memory.js +1 -1
- package/src/agent/models.js +1 -1
- package/src/agent/outschema.js +1 -1
- package/src/agent/pins.js +7 -2
- package/src/agent/project.js +1 -1
- package/src/agent/recall.js +1 -1
- package/src/agent/store.js +13 -26
- package/src/backend/ctxsize.js +2 -2
- package/src/backend/http.js +1 -1
- package/src/backend/learn.js +27 -1
- package/src/backend/mcp.js +97 -16
- package/src/backend/proxy.js +1 -1
- package/src/backend/quota.js +2 -2
- package/src/commands/common.js +2 -2
- package/src/commands/extend.js +0 -1
- package/src/commands/model.js +1 -2
- package/src/commands.js +4 -2
- package/src/completion.js +13 -3
- package/src/config.js +35 -13
- package/src/configexplain.js +3 -2
- package/src/doctor.js +1 -2
- package/src/jsonl.js +42 -0
- package/src/lsp/client.js +6 -46
- package/src/oneshot.js +22 -0
- package/src/pack/selfpack.js +2 -2
- package/src/pack/zip.js +18 -1
- package/src/plugins/manage.js +81 -14
- package/src/reap.js +70 -0
- package/src/report.js +1 -1
- package/src/safety/audit.js +4 -19
- package/src/safety/authcmd.js +1 -1
- package/src/safety/guard.js +81 -7
- package/src/safety/hooks.js +1 -1
- package/src/safety/keystore.js +18 -3
- package/src/safety/shellenv.js +1 -1
- package/src/safety/undo.js +44 -20
- package/src/skills/discover.js +1 -1
- package/src/tools/doc2md.js +25 -3
- package/src/tools/docs.js +3 -3
- package/src/tools/edit-match.js +1 -1
- package/src/tools/encoding.js +1 -1
- package/src/tools/excel-com.js +56 -30
- package/src/tools/fastgrep.js +65 -10
- package/src/tools/fsutil.js +8 -4
- package/src/tools/ignore.js +21 -1
- package/src/tools/index.js +77 -7
- package/src/tools/jobs.js +27 -5
- package/src/tools/pdf.js +1 -3
- package/src/tools/shell.js +27 -0
- package/src/tools/todo.js +1 -1
- package/src/tools/verify.js +17 -3
- package/src/tools/webfetch.js +12 -2
- package/src/tools/xlsx.js +4 -4
- package/src/ui/banner.js +1 -1
- package/src/ui/inputbox.js +1 -1
- package/src/ui/md.js +1 -1
- package/src/ui/motion.js +1 -1
package/src/tools/jobs.js
CHANGED
|
@@ -25,9 +25,10 @@
|
|
|
25
25
|
*/
|
|
26
26
|
import { spawn } from 'node:child_process';
|
|
27
27
|
import { decode as decodeBytes, consoleCodepage } from './encoding.js';
|
|
28
|
-
import {
|
|
28
|
+
import { 셸명령, 셸한계넘나 } from './shell.js';
|
|
29
29
|
import { 셸환경 } from '../safety/shellenv.js';
|
|
30
30
|
import { 말, 세말 } from '../i18n/index.js';
|
|
31
|
+
import { 신호에거두기 } from '../reap.js';
|
|
31
32
|
|
|
32
33
|
/* 결과 한 줄을 잇는다 — 빈 조각은 버린다(tools/index.js 의 이어 와 같은 것). */
|
|
33
34
|
const 이어 = (...조각들) => 조각들.filter((x) => x != null && String(x) !== '').join(' · ');
|
|
@@ -313,10 +314,13 @@ export function 무리끊기(pid, { 곧장 = false, 늦게 = 800 } = {}) {
|
|
|
313
314
|
* 기다림은 최선이 아니라 모두가 내는 값**이라 짧게 못 박는다. SIGKILL 은
|
|
314
315
|
* 그대로 나가므로, 신호를 무시하는 손자를 살려 보내는 일은 없다.
|
|
315
316
|
*/
|
|
316
|
-
|
|
317
|
+
// 검사도 이 값을 쓴다 (test/jobs.test.js 의 「상한이 유닉스 갈래에서도
|
|
318
|
+
// 지켜진다」). 거기서 400 을 손으로 적어 두면, 이 값을 고친 날 그 검사는
|
|
319
|
+
// **조용히 아무것도 안 가르는 검사**가 된다.
|
|
320
|
+
export const 못재고기다릴최대 = 400;
|
|
317
321
|
|
|
318
322
|
/** 무리끊기 의 **기다릴 수 있는** 판. 까닭은 바로 위 머리말에. */
|
|
319
|
-
|
|
323
|
+
async function 무리끊기기다려(pid, { 곧장 = false, 늦게 = 800 } = {}) {
|
|
320
324
|
if (process.platform === 'win32' || !pid) return;
|
|
321
325
|
if (곧장) { 신호주기(pid, 'SIGKILL'); return; }
|
|
322
326
|
신호주기(pid, 'SIGTERM');
|
|
@@ -347,6 +351,19 @@ export async function 무리끊기기다려(pid, { 곧장 = false, 늦게 = 800
|
|
|
347
351
|
export function 나무죽이기(kid, { 파이프끊기: 끊을까 = true, 곧장 = false, 상한 = 1500, 뿌리살리기 = true } = {}) {
|
|
348
352
|
if (!kid) return true;
|
|
349
353
|
let 나무끊었나 = true;
|
|
354
|
+
/*
|
|
355
|
+
* ── 끝난 것으로 본 아이에게는 taskkill 을 안 보낸다 (2.0.2 · 28회차 flake) ──────────
|
|
356
|
+
*
|
|
357
|
+
* Node 는 아이가 끝났다고 알리는 그 자리에서 프로세스 손잡이를 닫는다. 손잡이가 닫히면 윈도는
|
|
358
|
+
* 그 번호를 **곧바로 딴 프로세스에게 준다.** 그 뒤의 `taskkill /pid N /t` 는 우리 아이가 아니라
|
|
359
|
+
* 그 번호를 새로 받은 **남의 나무**를 끊는다 — 윈도 CI 에서 옆 대조군이 말없이 멈춘 것(28회차)이
|
|
360
|
+
* 이 모양이다. 상한에 잘려 다시 오는 길(뿌리살리기)에서 특히 그렇다: 첫 taskkill 이 뿌리를
|
|
361
|
+
* 죽이고 나서 두 번째가 같은 번호로 간다.
|
|
362
|
+
*
|
|
363
|
+
* 잃는 것은 없다. 뿌리가 끝난 뒤에는 /t 가 어차피 그 아래를 못 훑는다(남은무리끊기 머리말).
|
|
364
|
+
* 아직 안 끝난 아이는 손잡이가 열려 있어 번호가 안 바뀐다 — 그때만 보낸다.
|
|
365
|
+
*/
|
|
366
|
+
const 끝난아이 = typeof kid.exitCode === 'number' || typeof kid.signalCode === 'string';
|
|
350
367
|
if (process.platform === 'win32' && kid.pid) {
|
|
351
368
|
/*
|
|
352
369
|
* 상한은 부르는 쪽이 정한다. 여기는 끝날 때도 지나가는 자리라
|
|
@@ -354,7 +371,7 @@ export function 나무죽이기(kid, { 파이프끊기: 끊을까 = true, 곧장
|
|
|
354
371
|
* 그래서 기본은 짧다. 사람이 「끝내」 라고 시킨 자리에서는 길게 준다 —
|
|
355
372
|
* 거기서는 몇백 ms 늦는 것보다 안 죽는 것이 훨씬 나쁘다.
|
|
356
373
|
*/
|
|
357
|
-
나무끊었나 = 나무끊기(kid.pid, 상한);
|
|
374
|
+
if (!끝난아이) 나무끊었나 = 나무끊기(kid.pid, 상한);
|
|
358
375
|
/*
|
|
359
376
|
* 나무를 다 못 훑었으면 뿌리를 살려 둔다. 부르는 쪽이 다시 온다.
|
|
360
377
|
*
|
|
@@ -672,8 +689,11 @@ export async function 띄우기(명령, { cwd, 설명 = null, 기다림 = 1500,
|
|
|
672
689
|
return { error: `뒤에서 도는 명령이 이미 ${도는것.length}개입니다. Jobs 로 안 쓰는 것을 끝내고 다시 하세요.` };
|
|
673
690
|
}
|
|
674
691
|
|
|
675
|
-
const j = new 일감(다음번호++, 명령, 설명);
|
|
676
692
|
const shell = 셸명령(명령);
|
|
693
|
+
// cmd 의 한 줄 한계를 넘으면 띄우기 전에 말한다 (tools/shell.js 셸한계넘나 · 2.0.2 S6). 번호를 받기 전이다.
|
|
694
|
+
const 한계 = 셸한계넘나(명령, shell);
|
|
695
|
+
if (한계) return { error: 한계 };
|
|
696
|
+
const j = new 일감(다음번호++, 명령, 설명);
|
|
677
697
|
let kid;
|
|
678
698
|
try {
|
|
679
699
|
kid = spawn(shell.file, shell.args, {
|
|
@@ -915,6 +935,8 @@ export function 비우기() { 모두끝내기(); 다음번호 = 1; 치운것 = 0
|
|
|
915
935
|
|
|
916
936
|
// 어떤 길로 끝나든 남기지 않는다. repl·oneshot 이 부르는 것과 겹쳐도 무해하다.
|
|
917
937
|
process.once('exit', () => { try { 모두끝내기(); } catch { /* 끝나는 중이라 할 수 있는 게 없다 */ } });
|
|
938
|
+
// 신호(SIGINT·SIGTERM)로 끝나면 'exit' 이 안 돈다 — 그 길도 거둔다 (reap.js 머리말 · 2.0.2 M3).
|
|
939
|
+
신호에거두기(모두끝내기);
|
|
918
940
|
|
|
919
941
|
/*
|
|
920
942
|
* ── 도구 ──────────────────────────────────────────────────────────────
|
package/src/tools/pdf.js
CHANGED
|
@@ -1070,16 +1070,14 @@ function 글꼴만들기(문, 글꼴사전) {
|
|
|
1070
1070
|
const 너비 = 너비표읽기(문, 안, 두바이트);
|
|
1071
1071
|
|
|
1072
1072
|
// ① /ToUnicode 가 있으면 그것이 가장 정확하다.
|
|
1073
|
-
let 표 = new Map();
|
|
1074
1073
|
let 폭 = 두바이트 ? 2 : 1;
|
|
1075
1074
|
const 투 = 문.풀기(안.ToUnicode);
|
|
1076
1075
|
if (투?.날것) {
|
|
1077
1076
|
const r = 흐름풀기(투, (x) => 문.풀기(x));
|
|
1078
1077
|
if (r.ok) {
|
|
1079
1078
|
const 읽은것 = 유니코드표읽기(r.자료.toString('latin1'));
|
|
1080
|
-
표 = 읽은것.표;
|
|
1081
1079
|
if (읽은것.폭) 폭 = 읽은것.폭;
|
|
1082
|
-
if (
|
|
1080
|
+
if (읽은것.표.size) return { 폭, 표: 읽은것.표, 읽나: true, 너비 };
|
|
1083
1081
|
}
|
|
1084
1082
|
}
|
|
1085
1083
|
|
package/src/tools/shell.js
CHANGED
|
@@ -100,6 +100,33 @@ export function 정한셸() {
|
|
|
100
100
|
/** 검사용 — 다음 정한셸() 이 다시 고르게. */
|
|
101
101
|
export function 셸지우기() { 지금 = null; }
|
|
102
102
|
|
|
103
|
+
/*
|
|
104
|
+
* ── cmd.exe 는 한 줄에 8,191자까지다 (2.0.2 · S6) ─────────────────────────────
|
|
105
|
+
*
|
|
106
|
+
* cmd 자체의 한계라 우리가 늘릴 수 없다. 넘기면 cmd 가 「The command line is too long.」 한 줄을
|
|
107
|
+
* 내고 **아무것도 안 돌린다** — 그런데 한국어 윈도에서는 그 줄이 코드페이지째 깨져 오고, 모델은
|
|
108
|
+
* 제 명령이 왜 안 돌았는지 모른 채 같은 긴 명령을 또 낸다. 넘길 것이면 넘기기 전에 사람 말로
|
|
109
|
+
* 멈추고, 어떻게 하면 되는지(파일로 써서 돌리기)를 같이 말한다. Git Bash·파워셸은 이 한계가 없다.
|
|
110
|
+
*
|
|
111
|
+
* 8,191자는 명령만이 아니라 **cmd 가 받은 한 줄 전체**다 — `"C:\WINDOWS\system32\cmd.exe" /d /s /c "…"`.
|
|
112
|
+
* 재 보니 이 PC 에서 명령에 쓸 수 있는 것은 8,152자였다(cmd 자리 27자 + 앞뒤 붙이는 것). 그래서 cmd 자리와
|
|
113
|
+
* 붙이는 글자만큼 빼고 잰다. 붙이는 것은 ` /d /s /c ` 10자 · 명령을 싸는 따옴표 2자에 2자를 더 둔다.
|
|
114
|
+
*/
|
|
115
|
+
const cmd한줄최대 = 8191;
|
|
116
|
+
|
|
117
|
+
/** 이 cmd 로 명령에 쓸 수 있는 글자 수. */
|
|
118
|
+
export function cmd명령최대(file = 'cmd.exe') { return cmd한줄최대 - (String(file).length + 14); }
|
|
119
|
+
|
|
120
|
+
/** cmd 로 넘기면 한 줄 한계를 넘나. 넘으면 모델에게 줄 말, 아니면 null. */
|
|
121
|
+
export function 셸한계넘나(cmd, { id, file } = 정한셸()) {
|
|
122
|
+
if (id !== 'cmd') return null;
|
|
123
|
+
const n = String(cmd ?? '').length;
|
|
124
|
+
const 최대 = cmd명령최대(file);
|
|
125
|
+
if (n <= 최대) return null;
|
|
126
|
+
return `명령이 ${n.toLocaleString('en-US')}자입니다 — cmd.exe 는 한 줄에 ${cmd한줄최대.toLocaleString('en-US')}자까지만 받습니다(cmd 자리를 빼면 명령에는 ${최대.toLocaleString('en-US')}자 · cmd 자체 한계라 돌리지 않았습니다).`
|
|
127
|
+
+ ' 긴 내용은 Write 로 파일(.bat · .ps1 · .js 등)에 쓰고 그 파일을 돌리세요. Git Bash 를 깔면 이 한계가 없습니다.';
|
|
128
|
+
}
|
|
129
|
+
|
|
103
130
|
/** 명령 하나를 셸에 넘길 모양. Bash 도구와 Jobs 가 둘 다 이걸 쓴다. */
|
|
104
131
|
export function 셸명령(cmd) {
|
|
105
132
|
const s = 정한셸();
|
package/src/tools/todo.js
CHANGED
|
@@ -13,7 +13,7 @@ import { 말 } from '../i18n/index.js';
|
|
|
13
13
|
|
|
14
14
|
/* 결과 한 줄을 잇는다 — 빈 조각은 버린다(tools/index.js 의 이어 와 같은 것). */
|
|
15
15
|
const 이어 = (...조각들) => 조각들.filter((x) => x != null && String(x) !== '').join(' · ');
|
|
16
|
-
|
|
16
|
+
const STATES = ['todo', 'doing', 'done'];
|
|
17
17
|
|
|
18
18
|
const 표시 = { todo: '☐', doing: '▶', done: '☑' };
|
|
19
19
|
|
package/src/tools/verify.js
CHANGED
|
@@ -97,10 +97,16 @@ export function html보기(글, { 있는파일 = () => true } = {}) {
|
|
|
97
97
|
const 탈 = [];
|
|
98
98
|
const 쌓임 = [];
|
|
99
99
|
|
|
100
|
-
|
|
100
|
+
/*
|
|
101
|
+
* 주석과 script/style 안엣것은 빼고 본다 — 그 안의 `<` 는 태그가 아니다.
|
|
102
|
+
*
|
|
103
|
+
* 닫는 태그 무늬는 아래 참조 훑기와 **같은 잣대**여야 한다. 한쪽만 넓히면
|
|
104
|
+
* 같은 글을 두 자리가 다르게 읽는다 — 19회차에 아래만 고치고 여기를 지나칠
|
|
105
|
+
* 뻔했다. 한 자리를 고칠 때 같은 파일에 같은 병이 또 있나를 먼저 본다.
|
|
106
|
+
*/
|
|
101
107
|
const 뼈 = String(글)
|
|
102
108
|
.replace(/<!--[\s\S]*?-->/g, '')
|
|
103
|
-
.replace(/<(script|style)\b[^>]*>[\s\S]*?<\/\1\s
|
|
109
|
+
.replace(/<(script|style)\b[^>]*>[\s\S]*?<\/\1(?:[\s/][^>]*)?>/gi, '<$1></$1>');
|
|
104
110
|
|
|
105
111
|
for (const m of 뼈.matchAll(/<(\/?)([a-zA-Z!][a-zA-Z0-9-]*)([^>]*)>/g)) {
|
|
106
112
|
const 닫는가 = m[1] === '/';
|
|
@@ -165,7 +171,15 @@ export function html보기(글, { 있는파일 = () => true } = {}) {
|
|
|
165
171
|
*/
|
|
166
172
|
const 참조볼글 = String(글)
|
|
167
173
|
.replace(/<!--[\s\S]*?-->/g, '')
|
|
168
|
-
|
|
174
|
+
/*
|
|
175
|
+
* 닫는 태그에 속성이 붙어도 브라우저는 닫는 것으로 본다 — webfetch.js 와 같은 잣대.
|
|
176
|
+
*
|
|
177
|
+
* 그런데 그 닫는 태그를 **그대로 남기면** 안 된다. `</script src="x.js">`
|
|
178
|
+
* 의 src 가 아래 참조 훑기에 걸려 「x.js 가 없습니다」 라는 **거짓 탈**이
|
|
179
|
+
* 된다(2차 눈이 재현해 줬다). 여는 태그는 진짜 참조라 남기고, 닫는
|
|
180
|
+
* 태그는 이름만 남겨 껍데기로 적는다.
|
|
181
|
+
*/
|
|
182
|
+
.replace(/(<(script|style)\b[^>]*>)[\s\S]*?<\/\2(?:[\s/][^>]*)?>/gi, '$1</$2>');
|
|
169
183
|
for (const m of 참조볼글
|
|
170
184
|
.matchAll(/(?<![-\w.])(?:src|href)\s*=\s*(?:"([^"]*)"|'([^']*)')/gi)) {
|
|
171
185
|
const 곳 = m[1] ?? m[2];
|
package/src/tools/webfetch.js
CHANGED
|
@@ -213,7 +213,17 @@ function 태그벗기기(html) {
|
|
|
213
213
|
* 진짜 `</script>` 까지 본문을 통째로 먹고 `<!--` 만 남겼다. 브라우저는 **먼저 열린 쪽**을
|
|
214
214
|
* 따른다 — 한 무늬의 갈래로 두면 정규식도 왼쪽에서 먼저 걸리는 쪽을 따른다.
|
|
215
215
|
*/
|
|
216
|
-
|
|
216
|
+
/*
|
|
217
|
+
* 닫는 태그는 `</script>` 만이 아니다 (2.0.0 CodeQL js/bad-tag-filter).
|
|
218
|
+
* 브라우저는 `</script foo>` 도, 줄바꿈이 낀 `</script\n>` 도, 빗금으로
|
|
219
|
+
* 바로 닫는 `</script/>` 도 닫는 것으로 본다. `\s*>` 로만 두면 그런 꼴을
|
|
220
|
+
* 못 잡고 **스크립트 속이 글로 새어** 모델에게 그대로 간다.
|
|
221
|
+
*
|
|
222
|
+
* 빗금 갈래를 빼먹었더니 아래 「안 닫힌 것은 끝까지」 가 그 뒤를 통째로
|
|
223
|
+
* 먹어 **본문이 통째로 사라졌다**(2차 눈이 재현해 줬다). 못 걸러 새는
|
|
224
|
+
* 것만 흠이 아니라, 멀쩡한 글을 지우는 것도 같은 무게의 흠이다.
|
|
225
|
+
*/
|
|
226
|
+
글 = 글.replace(/<!--[\s\S]*?-->|<script\b[\s\S]*?<\/script(?:[\s/][^>]*)?>|<style\b[\s\S]*?<\/style(?:[\s/][^>]*)?>/gi, ' ');
|
|
217
227
|
if (글 === 전) break;
|
|
218
228
|
}
|
|
219
229
|
/*
|
|
@@ -293,7 +303,7 @@ export function 웹되돌림(다음, { allowPrivate = false } = {}) {
|
|
|
293
303
|
* 첫 주소만 이름을 풀어 보면 소용이 없다. 공개 주소로 시작해 302 한 번으로
|
|
294
304
|
* 사내로 들어가는 것이 가장 흔한 길이라, 홉마다 같은 것을 물어야 한다.
|
|
295
305
|
*/
|
|
296
|
-
|
|
306
|
+
async function 웹되돌림검사(다음, { allowPrivate = false } = {}) {
|
|
297
307
|
웹되돌림(다음, { allowPrivate });
|
|
298
308
|
if (allowPrivate) return;
|
|
299
309
|
const 푼것 = await 사설로풀리나(다음.hostname);
|
package/src/tools/xlsx.js
CHANGED
|
@@ -232,12 +232,12 @@ function 날짜로(n) {
|
|
|
232
232
|
* 이 밖을 가리키는 주소는 엑셀이 만든 파일에서 나올 수 없다. 나왔다면 누가
|
|
233
233
|
* 손으로 적은 바이트다.
|
|
234
234
|
*/
|
|
235
|
-
|
|
236
|
-
|
|
235
|
+
const 엑셀최대행 = 1048576;
|
|
236
|
+
const 엑셀최대열 = 16384;
|
|
237
237
|
/** 빈 줄·빈 열이 이만큼 넘게 이어지면 자리를 안 지키고 건너뛰었다고 말한다. */
|
|
238
|
-
|
|
238
|
+
const 빈틈상한 = 1000;
|
|
239
239
|
/** 펼친 표(줄 × 폭)의 칸 수 상한. 넘는 아래쪽 줄은 빼고 뺐다고 말한다. */
|
|
240
|
-
|
|
240
|
+
const 칸수상한 = 1_000_000;
|
|
241
241
|
|
|
242
242
|
const 천단위 = (n) => String(n).replace(/\B(?=(\d{3})+(?!\d))/g, ',');
|
|
243
243
|
|
package/src/ui/banner.js
CHANGED
|
@@ -95,7 +95,7 @@ const 들여 = ' ';
|
|
|
95
95
|
const 채움 = '█';
|
|
96
96
|
|
|
97
97
|
/** 글자 하나가 몇 칸인가 (한 배 기준). */
|
|
98
|
-
|
|
98
|
+
const 글자폭 = (ch) => (글꼴[ch]?.[0]?.length ?? 0);
|
|
99
99
|
|
|
100
100
|
/** 이름 전체가 몇 칸인가. @param 배 가로 배율(1 또는 2) */
|
|
101
101
|
export function 이름폭(배 = 1, 글자수 = 이름.length) {
|
package/src/ui/inputbox.js
CHANGED
package/src/ui/md.js
CHANGED
|
@@ -304,7 +304,7 @@ export function 표그리기(줄들, 폭 = 80, 어떻게 = {}) {
|
|
|
304
304
|
* 상한에 걸려 표를 나눠 그릴 때, 뒤 묶음에 앞 묶음의 너비를 그대로 물려 주려고
|
|
305
305
|
* 쓴다. 묶음마다 제 폭을 다시 재면 같은 표인데 위아래의 세로줄이 안 맞는다.
|
|
306
306
|
*/
|
|
307
|
-
|
|
307
|
+
function 표칸너비(줄들, 폭 = 80) {
|
|
308
308
|
return 짜기(줄들, 폭)?.너비 ?? null;
|
|
309
309
|
}
|
|
310
310
|
|
package/src/ui/motion.js
CHANGED
|
@@ -231,7 +231,7 @@ export const 틀 = Object.fromEntries(
|
|
|
231
231
|
* 상자 높이와 커서 셈이 통째로 달라진다. 그래서 **가로로 누운 옆모습**으로
|
|
232
232
|
* 그린다 — 세로로 선 정면 모습은 4점 안에서 절대 안 읽힌다.
|
|
233
233
|
*/
|
|
234
|
-
|
|
234
|
+
const 넓은칸수 = 6; // 점자 여섯 칸
|
|
235
235
|
|
|
236
236
|
/*
|
|
237
237
|
* 중세 기사 — 옆모습. 왼쪽에 몸이 서 있고 오른쪽에서 칼이 움직인다.
|