leerness 1.36.95 โ 1.36.97
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/CHANGELOG.md +134 -0
- package/README.md +4 -4
- package/bin/leerness.js +531 -27
- package/lib/graph.js +287 -5
- package/lib/pure-utils.js +112 -2
- package/package.json +1 -1
- package/scripts/e2e.js +509 -0
package/lib/graph.js
CHANGED
|
@@ -8,6 +8,11 @@
|
|
|
8
8
|
'use strict';
|
|
9
9
|
const path = require('path');
|
|
10
10
|
const { absRoot, exists, read, writeUtf8, log } = require('./io');
|
|
11
|
+
// 1.36.96 (P-0010): ๐ ๋ฌธ์ ํญ์ ์ํฌ๋ฆฟ ๋ง์คํน์ dashboard ์ **๊ฐ์ ์ ์ด**๋ฅผ ์ด๋ค.
|
|
12
|
+
// ํ๋ฉด๋ง๋ค ๋ค์ ๊ตฌํํ๋ฉด ํ์ชฝ๋ง ๊ณ ์ณ์ง๋ ๋ถ์ผ์น๊ฐ ์๊ธด๋ค(1.36.88โ1.36.90 ์์ ์ด๋ฏธ ๊ฒช์ ํด๋์ค).
|
|
13
|
+
const _redact = require('./pure-utils').redactSecrets;
|
|
14
|
+
// 1.36.96: ๋ง์คํน์ด **์๋ฒฝํด์ผ ํ๋ ๊ตฌ์กฐ๋ฅผ ๋ฒ๋ ธ๋ค** โ ์๊ฒฉ์ฆ๋ช
ํ์ง๊ฐ ์๋ ๋ฌธ์๋ ๋ณธ๋ฌธ์ ์ฃ์ง ์๋๋ค.
|
|
15
|
+
const _hasCred = require('./pure-utils').hasCredentialMarker;
|
|
11
16
|
|
|
12
17
|
// ๊ฒ์ฆ๋ ํ๋กํ ํ์
ํ
ํ๋ฆฟ(Claude Preview ๋ ๋+ํด๋ฆญ์กฐํ ํ์ธ). `/*__DATA__*/null` ์๋ฆฌํ์์์ JSON ์ฃผ์
.
|
|
13
18
|
// String.raw ํ์: ๋ด๋ถ JS ์ `\'` ๊ฐ์ escape ๊ฐ ์๋ฌธ ๊ทธ๋๋ก ์ถ๋ ฅ๋ผ ๋ธ๋ผ์ฐ์ JS ์์ง์ด ํด์ํ๋๋ก ๋ณด์กด.
|
|
@@ -62,10 +67,36 @@ canvas{position:fixed;inset:0;top:46px}
|
|
|
62
67
|
.cmd.show{display:flex;align-items:center;gap:10px}
|
|
63
68
|
.cmd button{background:#1a2230;border:1px solid var(--line);color:var(--txt);border-radius:5px;padding:3px 9px;cursor:pointer;font:inherit;font-size:10px}
|
|
64
69
|
.note{color:var(--mut);font-size:11px;margin:14px 0 18px;line-height:1.6}
|
|
70
|
+
/* ๐ ๋ฌธ์ ํญ (1.36.96, P-0010) */
|
|
71
|
+
.dwrap{display:flex;gap:16px;align-items:flex-start}
|
|
72
|
+
.dnav{flex:0 0 190px;position:sticky;top:70px}
|
|
73
|
+
.dnav div{padding:7px 10px;border-radius:7px;cursor:pointer;font-size:12px;color:var(--mut);user-select:none}
|
|
74
|
+
.dnav div.on{background:#1a2230;color:#fff}
|
|
75
|
+
.dbody{flex:1;min-width:0;border:1px solid var(--line);border-radius:10px;padding:16px 22px;background:var(--panel)}
|
|
76
|
+
.md h1,.md h2,.md h3,.md h4,.md h5,.md h6{color:#fff;line-height:1.35;margin:18px 0 10px}
|
|
77
|
+
.md h1{font-size:20px}.md h2{font-size:17px}.md h3{font-size:15px}.md h4,.md h5,.md h6{font-size:13px}
|
|
78
|
+
.md p{margin:0 0 10px;line-height:1.7;word-break:break-word}
|
|
79
|
+
.md ul,.md ol{margin:0 0 10px;padding-left:22px}
|
|
80
|
+
.md li{margin:3px 0;line-height:1.65}
|
|
81
|
+
.md pre{background:#0b0f14;border:1px solid var(--line);border-radius:8px;padding:12px 14px;overflow:auto;margin:0 0 12px}
|
|
82
|
+
.md code{font-family:var(--mono);font-size:12px;color:#7ee787}
|
|
83
|
+
.md pre code{color:#c9d1d9}
|
|
84
|
+
.md table{border-collapse:collapse;margin:0 0 12px;display:block;overflow-x:auto}
|
|
85
|
+
.md th,.md td{border:1px solid var(--line);padding:6px 10px;font-size:12px;text-align:left}
|
|
86
|
+
.md th{background:#141b23;color:#fff}
|
|
87
|
+
.md a{color:#58a6ff}
|
|
88
|
+
/* ์ข์ ํ๋ฉด์์ 190px ๊ณ ์ ๋ด๋น๊ฐ ์๋ฆฌ๋ฅผ ๋ค ๋จน์ด ๋ณธ๋ฌธ์ด ํ ๊ธ์์ฉ ์ธ๋ก๋ก ํ๋ ๋ค(์ค์ ๋ธ๋ผ์ฐ์ ์์ ํ์ธ).
|
|
89
|
+
ํ
์คํธ๋ก๋ ์ ๋ณด์ด๋ ์ข
๋ฅ๋ผ ๋์ผ๋ก ๋ด์ผ ์กํ๋ค. ์ข์์ง๋ฉด ๋ด๋น๋ฅผ ๊ฐ๋ก ์นฉ์ผ๋ก ์ ๋๋ค. */
|
|
90
|
+
@media (max-width:760px){
|
|
91
|
+
.dwrap{flex-direction:column}
|
|
92
|
+
.dnav{position:static;flex:0 0 auto;display:flex;flex-wrap:wrap;gap:4px;width:100%}
|
|
93
|
+
.dnav div{border:1px solid var(--line)}
|
|
94
|
+
.dbody{width:100%;padding:14px 16px}
|
|
95
|
+
}
|
|
65
96
|
</style></head><body>
|
|
66
97
|
<div id="bar">
|
|
67
98
|
<div class="ttl"><span class="dot"></span><span id="proj">leerness</span><span style="color:var(--mut);font-weight:400">/ ontology</span></div>
|
|
68
|
-
<div id="tabs"><span class="tab on" data-v="graph">๊ทธ๋ํ</span><span class="tab" data-v="roadmap">๋ก๋๋งต</span><span class="tab" data-v="tech">๐ ๊ธฐ์ </span></div>
|
|
99
|
+
<div id="tabs"><span class="tab on" data-v="graph">๊ทธ๋ํ</span><span class="tab" data-v="roadmap">๋ก๋๋งต</span><span class="tab" data-v="tech">๐ ๊ธฐ์ </span><span class="tab" data-v="docs">๐ ๋ฌธ์</span></div>
|
|
69
100
|
<span class="stat" id="stat"></span>
|
|
70
101
|
<input id="search" placeholder="search nodesโฆ" autocomplete="off">
|
|
71
102
|
<div id="chips"></div>
|
|
@@ -76,6 +107,7 @@ canvas{position:fixed;inset:0;top:46px}
|
|
|
76
107
|
<div id="hint">drag node ยท scroll zoom ยท drag bg pan ยท click node โ details ยท search+Enter jump ยท f / dblclick fit ยท p export PNG ยท Esc close</div>
|
|
77
108
|
<div id="vroadmap" class="view"></div>
|
|
78
109
|
<div id="vtech" class="view"></div>
|
|
110
|
+
<div id="vdocs" class="view"></div>
|
|
79
111
|
<script>
|
|
80
112
|
var DATA = /*__DATA__*/null;
|
|
81
113
|
var COLORS={task:'#58a6ff',plan:'#d29922',decision:'#39d0d8',lesson:'#e3b341',rule:'#bc8cff',skill:'#2dd4bf',feature:'#6e7681'};
|
|
@@ -172,7 +204,7 @@ window.addEventListener('keydown',function(ev){ if(ev.target&&ev.target.tagName=
|
|
|
172
204
|
cv.addEventListener('dblclick',function(ev){ if(!hit(ev.offsetX,ev.offsetY)){_fit=true;fitView();} });
|
|
173
205
|
|
|
174
206
|
// โโ ํญ (1.36.53, UR-0062): ๊ทธ๋ํ | ๋ก๋๋งต | ๐ ๊ธฐ์ (ํ ๊ธ ์ค์์น UI ์ ๊ฑฐ โ CLI ๊ฐ์ด๋๋ก ๋์ฒด) โโ
|
|
175
|
-
var _views={roadmap:document.getElementById('vroadmap'),tech:document.getElementById('vtech')};
|
|
207
|
+
var _views={roadmap:document.getElementById('vroadmap'),tech:document.getElementById('vtech'),docs:document.getElementById('vdocs')};
|
|
176
208
|
document.querySelectorAll('.tab').forEach(function(t){t.onclick=function(){
|
|
177
209
|
document.querySelectorAll('.tab').forEach(function(x){x.classList.toggle('on',x===t);});
|
|
178
210
|
var v=t.getAttribute('data-v');
|
|
@@ -234,10 +266,222 @@ document.querySelectorAll('.tab').forEach(function(t){t.onclick=function(){
|
|
|
234
266
|
+'ยท ์ด ํ์ผ์ ์ ์ HTML โ ์ํ ๋ณ๊ฒฝ์ ํฐ๋ฏธ๋(๋๋ AI)์๊ฒ ์ ๋ช
๋ น์ ์คํ์ํค์ธ์. AI ๋ ํ ๊ธ ์ํ๋ฅผ ์๋ ์ค์ํฉ๋๋ค.</div></div>';
|
|
235
267
|
el.innerHTML=h;
|
|
236
268
|
})();
|
|
269
|
+
|
|
270
|
+
// โโ ๐ ๋ฌธ์ ํญ (1.36.96, P-0010) โ .harness ํต์ฌ ๋ฌธ์ 7์ข
์ ์ด ํ์ผ ์์์ ๊ทธ๋๋ก ์ฝ๋๋ค.
|
|
271
|
+
// ๋ ๋๋ฌ๋ **์ต์ ๋ถ๋ถ์งํฉ**๋ง ํด์ํ๋ค: ์ ๋ชฉ ยท ๋ชฉ๋ก ยท ์ฝ๋ํ์ค ยท ํ ยท ๋งํฌ ยท ๊ฐ์กฐ.
|
|
272
|
+
// ๊ทธ ๋ฐ์ ๋ชจ๋ ๊ฒ(์์ HTML ํฌํจ)์ ์ด์ค์ผ์ดํ๋ ํ๋ฌธ์ผ๋ก ๋จ๋๋ค โ ํ์๋ฅผ ๋ํ์๋ก XSS ๋ฉด์ด ๋์ด์ง๋ค.
|
|
273
|
+
// ์ด ํ
ํ๋ฆฟ์ String.raw ๋ผ ๋ฆฌํฐ๋ด ๋ฐฑํฑ์ ์ธ ์ ์๋ค(ํ
ํ๋ฆฟ์ด ๋๊ธด๋ค) โ ์ ๊ท์/๋ฌธ์์ด์์ \x60 ์ ์ด๋ค.
|
|
274
|
+
function mdEsc(s){return String(s==null?'':s).replace(/&/g,'&').replace(/</g,'<').replace(/>/g,'>').replace(/"/g,'"');}
|
|
275
|
+
// URL ํ์ฉ: http(s) ยท mailto ยท ํ์ด์ง์ต์ปค ยท ์๋๊ฒฝ๋ก. ๊ทธ ์ธ **์คํด์ด ๋ถ์ ๊ฒ์ ์ ๋ถ ๊ฑฐ๋ถ**(javascript:, data:, vbscript: โฆ).
|
|
276
|
+
// ๋ธ๋ผ์ฐ์ URL ํ์๋ ํญ/๊ฐํ/CR ์ **์ ๊ฑฐํ ๋ค** ์คํด์ ์ฝ๋๋ค โ ์ค์ธก์ผ๋ก ํ์ธํ๋ค(java + ํญ + script:
|
|
277
|
+
// ๋ฅผ href ์ ๋ฃ์ผ๋ฉด protocol ์ด javascript: ๋ก ๋์จ๋ค). ์ง๊ธ์ ๋งํฌ ํ ํฌ๋์ด์ ๊ฐ ๊ณต๋ฐฑ๋ฅ๋ฅผ ๋ฐฐ์ ํด ๊ทธ๋ฐ
|
|
278
|
+
// ์
๋ ฅ์ด ์ ์ด์ ๋งํฌ๊ฐ ๋์ง ์์ง๋ง ๊ทธ๊ฑด **์ฐ์ฐํ ์์ **์ด๋ค. ํ ํฌ๋์ด์ ๋ฅผ ๋์ค์ ๋ํ๋ฉด ๋์ด์๋๋ค.
|
|
279
|
+
// (์ด ์ฃผ์์ ๋ฐฑํฑ์ ์ฐ๋ฉด String.raw ํ
ํ๋ฆฟ์ด ๊ฑฐ๊ธฐ์ ๋๊ธด๋ค โ ๋ฐ๋ก ์์ ์ ์ด ๋๊ณ ํ ๋ฒ ์ด๊ฒผ๋ค.)
|
|
280
|
+
// ํ์ ์ ์ ๋ธ๋ผ์ฐ์ ์ ๊ฐ์ ๋ฌธ์๋ฅผ ์ ๊ฑฐํด, ์ฐ๋ฆฌ๊ฐ ๋ณด๋ ๊ฒ๊ณผ ๋ธ๋ผ์ฐ์ ๊ฐ ๋ณด๋ ๊ฒ์ ์ผ์น์ํจ๋ค.
|
|
281
|
+
// ํญยท๊ฐํ๋ฟ ์๋๋ผ **C0 ์ ์ด๋ฌธ์์ DEL ์ ๋ถ**๋ฅผ ์ ๊ฑฐํ๋ค โ ๊ฒ์ ์ค์ธก์์ \x03ยท\x01ยท\x00ยท\x1Fยท\x7F ๋ฅผ
|
|
282
|
+
// ์์ด๋ ์ค๊ฐ์ ๋ผ์ฐ๋ฉด ์คํด ํ์ ์ ๋น ์ ธ๋๊ฐ๋ค. ๋ธ๋ผ์ฐ์ ๋ ๊ทธ๋ฐ ๋ฌธ์๋ฅผ URL ์์ ๋ฌด์ํ๊ฑฐ๋ ์ ๊ฑฐํ๋ค.
|
|
283
|
+
function mdUrl(u){var t=String(u||'').replace(/[\x00-\x1F\x7F]/g,'').trim();
|
|
284
|
+
// ๋ธ๋ผ์ฐ์ ๋ ์ญ์ฌ๋์๋ฅผ ์ฌ๋์์ฒ๋ผ ์ฝ๋๋ค โ ์ญ์ฌ๋์ 2๊ฐ๋ก ์์ํ๋ ๊ฐ์ ํ๋กํ ์ฝ ์๋ URL ๋ก ํด์๋๋ค
|
|
285
|
+
// (๊ฒ์ ์ค์ธก: file://host/share, HTTPS ํ์ด์ง์์๋ https://host/share). ์ข
์ ์ ์ฌ๋์ 2๊ฐ๋ง ๋ง์๋ค.
|
|
286
|
+
if(/^[\\/]{2}/.test(t))return null;
|
|
287
|
+
if(/^(https?:\/\/|mailto:|#)/i.test(t))return t;
|
|
288
|
+
if(/^[a-z][a-z0-9+.\-]*:/i.test(t))return null;
|
|
289
|
+
return t;}
|
|
290
|
+
function mdInline(s){
|
|
291
|
+
// ์ฝ๋์คํฌ์ **๋จผ์ ** ๋ฝ์ ์๋ฆฌํ์์๋ก ์นํํ๋ค โ ์์ชฝ์ * ๋ [](โฆ) ๊ฐ ๊ฐ์กฐ/๋งํฌ๋ก ํด์๋๋ฉด ์ ๋๋ค.
|
|
292
|
+
// ์๋ฆฌํ์์๋ U+0001 ๋ก ๊ฐ์ผ๋ค(์ด์ค์ผ์ดํ๋ ๋ณธ๋ฌธ์ ์ ๋ ๋ํ๋์ง ์๋ ๋ฌธ์). ๊ฐ์ธ๋ ๋ฌธ์๋ฅผ ๋น ๋จ๋ฆฌ๋ฉด
|
|
293
|
+
// ๋ณต์ ์ ๊ท์์ด ๋ณธ๋ฌธ์ **๋ชจ๋ ์ซ์**๋ฅผ ์ผํจ๋ค โ ์ด์์์ ์ค์ ๋ก ๊ทธ๋ฌ๋ค.
|
|
294
|
+
// ๋ฌธ์์ U+0001 ์ด ์ค์ ๋ก ๋ค์ด ์์ผ๋ฉด ์๋ฆฌํ์์์ ์ถฉ๋ํ๋ค โ ๋จผ์ ์ง์ด๋ค(ํ์์ฉ ํ
์คํธ๋ผ ๋ฌดํด).
|
|
295
|
+
var out=mdEsc(s).replace(/[\x01\x02]/g,''),codes=[],links=[];
|
|
296
|
+
out=out.replace(/\x60([^\x60]+)\x60/g,function(m,c){codes.push(c);return '\x01'+(codes.length-1)+'\x01';});
|
|
297
|
+
// ์๋์๋ฅผ **์ ๊ณ**๋ก ๋๋ค. ์ข
์ [^\]]* ๋ ๋ซํ์ง ์์ ๋๊ดํธ๋ง๋ค ๋จ์ ๋ฌธ์์ด ์ ์ฒด๋ฅผ ๋ค์ ํ์ด O(nยฒ) ์๋ค
|
|
298
|
+
// (์ค์ธก: 64KB ์
๋ ฅ 1,825ms ยท ์ต์
2,730ms โ ๊ทธ๋งํผ ๋ธ๋ผ์ฐ์ ๋ฉ์ธ ์ค๋ ๋๊ฐ ๋ฉ์ถ๋ค).
|
|
299
|
+
// ์ํ์ ๋๋ ๋งํฌ๋ ๋งํฌ๊ฐ ๋์ง ์๊ณ ๊ธ์๋ก ๋จ๋๋ค(๊ณ์ฝ์ ์์ ํ ์ชฝ์ผ๋ก ์คํจํ๋ค).
|
|
300
|
+
// URL ์ํ์ **์ด์ค์ผ์ดํ ํ** ๊ธธ์ด์ ๊ฑธ๋ฆฐ๋ค โ ์๋ฌธ 796์์ง๋ฆฌ ์ ์ ์ฟผ๋ฆฌ URL ์ด & โ & ํฝ์ฐฝ์ผ๋ก
|
|
301
|
+
// 1,192์๊ฐ ๋์ด ๊ฑฐ๋ถ๋๋ค(๊ฒ์ ์ค์ธก). ์ค์ธก ๋น๊ต๋ก ๋ผ๋ฒจ 300 / URL 4000 ์ ๊ณจ๋๋ค:
|
|
302
|
+
// ์ต์
115ms(๋ฌด๊ณ๋ 1,747ms)์ด๊ณ ๊ทธ URL ์ ๋งํฌ๋๋ค.
|
|
303
|
+
out=out.replace(/\[([^\]\n]{0,300})\]\(([^)\s]{1,4000})\)/g,function(m,t,u){var v=mdUrl(u);
|
|
304
|
+
if(v===null)return m;
|
|
305
|
+
// ์์ฑ๋ <a> ๋ ์๋ฆฌํ์์๋ก ๋นผ ๋๋ค โ ๋ค๋ฐ๋ฅด๋ ๊ฐ์กฐ ์ ๊ท์์ด href ์๊น์ง ๋ค์ ํด์ํด
|
|
306
|
+
// href="https://a/<b>b</b>/c" ์ฒ๋ผ URL ์ ํผ์ํ๋ค(๊ฒ์ ์ค์ธก).
|
|
307
|
+
links.push('<a href="'+v+'" target="_blank" rel="noopener noreferrer">'+t+'</a>');
|
|
308
|
+
return '\x02'+(links.length-1)+'\x02';});
|
|
309
|
+
out=out.replace(/\*\*([^*]+)\*\*/g,'<b>$1</b>');
|
|
310
|
+
out=out.replace(/(^|[^*])\*([^*\n]+)\*/g,'$1<i>$2</i>');
|
|
311
|
+
out=out.replace(/\x02(\d+)\x02/g,function(m,i){return links[i];});
|
|
312
|
+
out=out.replace(/\x01(\d+)\x01/g,function(m,i){return '<code>'+codes[i]+'</code>';});
|
|
313
|
+
return out;}
|
|
314
|
+
function mdRender(src){
|
|
315
|
+
var ls=String(src||'').split(/\r?\n/),h='',i=0,list=null,olNext=0;
|
|
316
|
+
function endList(){if(list){h+='</'+list+'>';list=null;}}
|
|
317
|
+
function cells(r){return r.replace(/^\s*\|/,'').replace(/\|\s*$/,'').split('|').map(function(c){return c.trim();});}
|
|
318
|
+
while(i<ls.length){
|
|
319
|
+
var l=ls[i];
|
|
320
|
+
if(/^\s*\x60{3,}/.test(l)){ // ์ฝ๋ํ์ค โ ์์ชฝ์ ์ด๋ค ๊ท์น๋ ์ ์ฉํ์ง ์๋๋ค
|
|
321
|
+
endList();var buf=[];i++;
|
|
322
|
+
while(i<ls.length&&!/^\s*\x60{3,}\s*$/.test(ls[i])){buf.push(ls[i]);i++;}
|
|
323
|
+
i++;h+='<pre><code>'+mdEsc(buf.join('\n'))+'</code></pre>';continue;}
|
|
324
|
+
var hd=l.match(/^(#{1,6})\s+(.*)$/);
|
|
325
|
+
if(hd){endList();var n=hd[1].length;h+='<h'+n+'>'+mdInline(hd[2])+'</h'+n+'>';i++;continue;}
|
|
326
|
+
if(l.indexOf('|')>=0&&i+1<ls.length&&ls[i+1].indexOf('|')>=0&&/^[\s:|\-]*-[\s:|\-]*$/.test(ls[i+1])){
|
|
327
|
+
endList();
|
|
328
|
+
// ๊ตฌ๋ถํ์ ์ฝ๋ก ์ ๋ฌธ๋ฒ์ผ๋ก๋ ๋ฐ์ผ๋ฉด์ ์ ๋ ฌ์ ๋ฒ๋ฆฌ๋ฉด ์ฌ์ฉ์๊ฐ ์ง์ ํ ์๋ฏธ๊ฐ ์กฐ์ฉํ ์ฌ๋ผ์ง๋ค(๊ฒ์ ์ค์ธก).
|
|
329
|
+
// ๋ฐ์ ์ด์ ๋ฐ์ํ๋ค โ ์ผ์ชฝ/๊ฐ์ด๋ฐ/์ค๋ฅธ์ชฝ. (์ด ํ
ํ๋ฆฟ ์ ์ฃผ์์๋ ๋ฐฑํฑ์ ์ธ ์ ์๋ค.)
|
|
330
|
+
var al=cells(ls[i+1]).map(function(c){
|
|
331
|
+
var lft=c.charAt(0)===':',rgt=c.charAt(c.length-1)===':';
|
|
332
|
+
return lft&&rgt?' style="text-align:center"':(rgt?' style="text-align:right"':(lft?' style="text-align:left"':''));});
|
|
333
|
+
var A=function(k){return al[k]||'';};
|
|
334
|
+
h+='<table><thead><tr>'+cells(l).map(function(c,k){return '<th'+A(k)+'>'+mdInline(c)+'</th>';}).join('')+'</tr></thead><tbody>';
|
|
335
|
+
i+=2;
|
|
336
|
+
while(i<ls.length&&ls[i].indexOf('|')>=0&&ls[i].trim()!==''){
|
|
337
|
+
h+='<tr>'+cells(ls[i]).map(function(c,k){return '<td'+A(k)+'>'+mdInline(c)+'</td>';}).join('')+'</tr>';i++;}
|
|
338
|
+
h+='</tbody></table>';continue;}
|
|
339
|
+
var ul=l.match(/^\s*[-*+]\s+(.*)$/),ol=l.match(/^\s*(\d+)[.)]\s+(.*)$/);
|
|
340
|
+
if(ul||ol){var want=ul?'ul':'ol';
|
|
341
|
+
// ์๋ฌธ ๋ฒํธ๋ฅผ ์งํค์ง ์์ผ๋ฉด "2. two" ๊ฐ ๋ธ๋ผ์ฐ์ ์์ "1. two" ๋ก, 1ยท3 ์ด 1ยท2 ๋ก ํ์๋๋ค
|
|
342
|
+
// โ ๋ฌธ์์ ์๋ฏธ๊ฐ ์กฐ์ฉํ ๋ฐ๋๋ค(๊ฒ์ ์ค์ธก). ์์๊ฐ์ ol start, ๊ฑด๋๋ด ๋ฒํธ๋ li value ๋ก ๋ณด์กดํ๋ค.
|
|
343
|
+
if(list!==want){endList();h+=want==='ol'?('<ol start="'+ol[1]+'">'):'<ul>';list=want;olNext=ol?parseInt(ol[1],10):0;}
|
|
344
|
+
if(ul){h+='<li>'+mdInline(ul[1])+'</li>';}
|
|
345
|
+
else{var num=parseInt(ol[1],10);h+=(num===olNext?'<li>':'<li value="'+num+'">')+mdInline(ol[2])+'</li>';olNext=num+1;}
|
|
346
|
+
i++;continue;}
|
|
347
|
+
if(!l.trim()){endList();i++;continue;}
|
|
348
|
+
endList();h+='<p>'+mdInline(l)+'</p>';i++;}
|
|
349
|
+
endList();return h;}
|
|
350
|
+
|
|
351
|
+
(function(){
|
|
352
|
+
var dd=(DATA&&DATA.docs)||{files:[]},el=_views.docs,fl=dd.files||[];
|
|
353
|
+
if(!fl.length){el.innerHTML='<div class="note">๋ฌธ์ ์์ โ leerness handoff . ๋ก .harness ๋ฅผ ์ฑ์ฐ๊ณ ์ฌ์์ฑํ์ธ์.</div>';return;}
|
|
354
|
+
var kb=function(n){return Math.round((n||0)/1024)+'KB';};
|
|
355
|
+
el.innerHTML='<div class="note">์ค๋
์ท '+esc(String(dd.at||'').slice(0,19).replace('T',' '))+' UTC ยท ์ด ํ์ผ์ <b>์ ์ ์ฌ๋ณธ</b>์
๋๋ค โ ์ต์ ๋ด์ฉ์ <b>leerness graph --html</b> ๋ก ์ฌ์์ฑํ์ธ์. ์ํฌ๋ฆฟ ๊ฐ์ ๊ฐ๋ ค์ง๋๋ค(๋ฌธ์๋น '+kb(dd.perCap)+' ยท ์ ์ฒด '+kb(dd.totalCap)+' ์ํ).</div>'
|
|
356
|
+
+'<div class="dwrap"><div class="dnav">'
|
|
357
|
+
+fl.map(function(f,i){return '<div data-i="'+i+'"'+(i===0?' class="on"':'')+'>'+esc(f.title)+(f.missing?' <span style="color:var(--mut)">(์์)</span>':(f.guarded?' <span style="color:var(--mut)">๐</span>':(f.truncated?' <span style="color:var(--mut)">โ</span>':'')))+'</div>';}).join('')
|
|
358
|
+
+'</div><div class="dbody md" id="dbody"></div></div>';
|
|
359
|
+
var body=document.getElementById('dbody');
|
|
360
|
+
function show(i){
|
|
361
|
+
var f=fl[i]||{},h='<div class="sec" style="margin-top:0">'+esc(f.title||'')+' <span style="color:var(--mut);font-weight:400;font-size:11px">'+esc(f.rel||'')+'</span></div>';
|
|
362
|
+
if(f.missing){h+='<div class="note">์์ง ์๋ ํ์ผ์
๋๋ค โ <b>leerness handoff .</b> ์คํ ์ ์์ฑ๋ฉ๋๋ค.</div>';}
|
|
363
|
+
// ์๊ฒฉ์ฆ๋ช
ํ์ง๊ฐ ์๋ ๋ฌธ์๋ **๋ณธ๋ฌธ์ ์ฃ์ง ์๋๋ค** โ ๋ถ๋ถ ๋ง์คํน์ ๋นํ์ผ๋ก ์๋ ๊ฒ์ ๊ตฌ์กฐ์ ์ผ๋ก ๋ง๋๋ค.
|
|
364
|
+
else if(f.guarded){h+='<div class="note">๐ ์ด ๋ฌธ์์๋ <b>์๊ฒฉ์ฆ๋ช
์ผ๋ก ๋ณด์ด๋ ๋ด์ฉ</b>์ด ์์ด ๋ณธ๋ฌธ์ ์ฃ์ง ์์์ต๋๋ค('+(f.charsTotal||0)+'์). ํ์ผ์ ์ง์ ์ฌ์ธ์: '+esc(f.rel||'')+'<br>์ด ํ์ผ์ ๊ณต์ ๋ ์ ์์ผ๋ฏ๋ก, ๋ถ๋ถ์ ์ผ๋ก ๊ฐ๋ฆฌ๋ ๋์ ํต์งธ๋ก ์ ์ธํฉ๋๋ค.</div>';}
|
|
365
|
+
else if(f.unreadable){h+='<div class="note">์ฝ์ง ๋ชปํ์ต๋๋ค(๊ถํ/์ธ์ฝ๋ฉ). ์๋ณธ ํ์ผ์ ๊ทธ๋๋ก์
๋๋ค โ ์ง์ ์ฌ์ธ์.</div>';}
|
|
366
|
+
else if(f.skipped){h+='<div class="note">โ ์ ์ฒด ์ํ('+kb(dd.totalCap)+')์ ๋๋ฌํด <b>๋ด๊ธฐ์ง ์์์ต๋๋ค</b> โ ์๋ณธ '+(f.charsTotal||0)+'์. '+esc(f.rel||'')+' ๋ฅผ ์ง์ ์ฌ์ธ์.</div>';}
|
|
367
|
+
else{
|
|
368
|
+
// "์" ๋ ์ฝ๋ํฌ์ธํธ๋ค โ String.length ๋ฅผ ์ฐ๋ฉด ์ด๋ชจ์ง ๋ฌธ์์์ ๋ ๋ฐฐ๋ก ํ์๋๋ค(๊ฒ์ ์ค์ธก).
|
|
369
|
+
if(f.truncated)h+='<div class="note">โ ์ํ์ผ๋ก ์๋ ธ์ต๋๋ค โ '+(f.chars||0)+'/'+(f.charsTotal||0)+'์('+(f.tail?'๋ท๋ถ๋ถ':'์๋ถ๋ถ')+'๋ง). ์ ์ฒด๋ '+esc(f.rel||'')+' ๋ฅผ ์ฌ์ธ์.</div>';
|
|
370
|
+
h+=(f.lang==='json')?('<pre><code>'+mdEsc(f.text||'')+'</code></pre>'):mdRender(f.text||'');}
|
|
371
|
+
body.innerHTML=h;}
|
|
372
|
+
el.querySelectorAll('.dnav div').forEach(function(n){n.onclick=function(){
|
|
373
|
+
el.querySelectorAll('.dnav div').forEach(function(x){x.classList.toggle('on',x===n);});
|
|
374
|
+
show(parseInt(n.getAttribute('data-i'),10));};});
|
|
375
|
+
show(0);
|
|
376
|
+
})();
|
|
237
377
|
</script></body></html>`;
|
|
238
378
|
|
|
239
379
|
const _txt = v => (v == null ? '' : String(v));
|
|
240
|
-
|
|
380
|
+
// 1.36.96 (๊ฒ์ P1): ๋ฌธ์ ํญ๋ง ๊ฐ๋ํ๋๋ฐ **๊ฐ์ ๋ด์ฉ์ด nodesยทroadmap ์ผ๋ก๋ ์๋ฒ ๋**๋๋ค โ
|
|
381
|
+
// `decision add "Authorization: Bearer <ํ ํฐ>"` ์ด DATA.nodes[].label / detail ๋ก ์๋ฌธ ๊ทธ๋๋ก ์ค๋ ธ๋ค(์ค์ธก).
|
|
382
|
+
// ๊ทธ๋ํ ์ชฝ์๋ ๋ง์คํน์กฐ์ฐจ ์์๋ค. ์๋ฒ ๋๋๋ **๋ชจ๋ ์ฌ์ฉ์ ํ
์คํธ**๋ฅผ ๊ฐ์ ์ ์ด๋ก ํต๊ณผ์ํจ๋ค.
|
|
383
|
+
// ์๊ฒฉ์ฆ๋ช
ํ์ง๊ฐ ์์ผ๋ฉด ๊ทธ ํญ๋ชฉ ํ
์คํธ๋ฅผ ํต์งธ๋ก ๋์ฒดํ๊ณ , ์๋๋ฉด 2์ฐจ ๋ง์คํน๋ง ์ ์ฉํ๋ค.
|
|
384
|
+
const _GUARD_TXT = '๐ ์๊ฒฉ์ฆ๋ช
ํ์ง โ ์๋ต๋จ';
|
|
385
|
+
const _safe = (v) => { const t = _txt(v); return t && _hasCred(t) ? _GUARD_TXT : _redact(t); };
|
|
386
|
+
function _trunc(s, n) { s = _safe(s); return s.length > n ? s.slice(0, n - 1) + 'โฆ' : s; }
|
|
387
|
+
|
|
388
|
+
// โโ ๐ ๋ฌธ์ ํญ ๋ฐ์ดํฐ (1.36.96, P-0010) โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
|
|
389
|
+
// ์ฌ์ฉ์ ์์ฒญ์ "exe ์คํ๊ธฐ๋ก .harness ๋งํฌ๋ค์ด์ ๋์ฐ๊ธฐ"์๋ค. ์คํ๊ธฐ๋ ๋ฐํ์ ์์กด์ฑ 0 ยท install script 0
|
|
390
|
+
// ๊ฒฝ๊ณ๋ฅผ ๊นจ๋ฏ๋ก ๋ง๋ค์ง ์๋๋ค(1.36.90 ์์ ๊ฐ์ ๊ฒฝ๊ณ๋ฅผ ํ
์คํธ๋ก ๋ชป๋ฐ์๋ค). ๊ฐ์ ๋ชฉ์ ์ ์ ์ ๋จ์ผ ํ์ผ๋ก ์ด๋ฃฌ๋ค.
|
|
391
|
+
// `tail: true` ๋ **๋์ ๋ก๊ทธ**๋ค โ ์์ ๋จ๊ธฐ๋ฉด ๊ฐ์ฅ ์ค๋๋ ๊ฒ๋ง ๋ณด์ธ๋ค(1.36.95 handoff ์์ ๊ฒช์ ๊ทธ ๋ฐฉํฅ ์ค๋ฅ).
|
|
392
|
+
const DOC_FILES = [
|
|
393
|
+
{ key: 'plan', title: 'ํ๋ ยท ๋ก๋๋งต', rel: '.harness/plan.md' },
|
|
394
|
+
{ key: 'skills', title: '์คํฌ', rel: '.harness/skill-index.md' },
|
|
395
|
+
{ key: 'tech', title: '๊ธฐ์ ํ๋กํ', rel: '.harness/tech-profile.json', lang: 'json' },
|
|
396
|
+
{ key: 'handoff', title: '์ธ์
ํธ๋์คํ', rel: '.harness/session-handoff.md' },
|
|
397
|
+
{ key: 'state', title: 'ํ์ฌ ์ํ', rel: '.harness/current-state.md' },
|
|
398
|
+
{ key: 'progress', title: '์งํ ์ถ์ ', rel: '.harness/progress-tracker.md', tail: true },
|
|
399
|
+
{ key: 'decisions', title: '๊ฒฐ์ ๊ธฐ๋ก', rel: '.harness/decisions.md', tail: true },
|
|
400
|
+
];
|
|
401
|
+
const DOC_PER_CAP = 64 * 1024;
|
|
402
|
+
const DOC_TOTAL_CAP = 512 * 1024;
|
|
403
|
+
// โ ์ค๋์ ๋ชฉ๋ก(7์ข
ร 64KB = 448KB)์ผ๋ก๋ ์ ์ฒด ์ํ 512KB ์ **๋๋ฌํ ์ ์๋ค** โ ๋ชฉ๋ก์ด 8์ข
์ด์์ผ๋ก
|
|
404
|
+
// ๋ ๋๋ฅผ ์ํ backstop ์ด๋ค. ๊ทธ๋์ caps ๋ฅผ ์ฃผ์
๊ฐ๋ฅํ๊ฒ ๋๋ค: ๋๋ฌ ๋ถ๊ฐ๋ฅํ ๋ถ๊ธฐ๋ "์๋ค"๊ณ ๋ง ์ ์ผ๋ฉด
|
|
405
|
+
// ๊ณตํํ ๊ฐ๋๊ฐ ๋๋ค(๊ทธ ํจ์ ์ ์ด ์ ์ฅ์์์ ๋ฐ๋ณตํด์ ๋ฐ์๋ค). ํ
์คํธ๊ฐ ์์ ์ํ์ผ๋ก ์ค์ ๋ก ๋ฐํ์ํจ๋ค.
|
|
406
|
+
|
|
407
|
+
// ์ค ๊ฒฝ๊ณ์์ ์๋ฅด๊ณ , ํ ์ค์ด ์ํ๋ณด๋ค ๊ธธ๋ฉด **์ฝ๋ํฌ์ธํธ** ๊ฒฝ๊ณ์์ ์๋ฅธ๋ค(์๋ก๊ฒ์ดํธ ์ ๋ถํ ๊ธ์ง).
|
|
408
|
+
// 1.36.96 (๊ฒ์ P2): ์ํ ๋จ์๋ฅผ **UTF-8 ๋ฐ์ดํธ**๋ก ๋ฐ๊ฟจ๋ค. ์ข
์ ์ UTF-16 ์ฝ๋ ๋จ์๋ฅผ ์ธ๋ฉด์ "64KB"๋ผ๊ณ
|
|
409
|
+
// ์ ์๊ณ , ํ๊ธ ๋ฌธ์์์๋ ๋ฌธ์๋น ์ค์ 192KB ยท ํฉ๊ณ 1.38MB ๊น์ง ์ค๋ ค ์ฃผ์ฅ์ด ์ฌ์ค๊ณผ ๋ฌ๋๋ค(์ค์ธก: 1,152KB).
|
|
410
|
+
const _blen = (x) => Buffer.byteLength(x, 'utf8');
|
|
411
|
+
function _capDoc(s, cap, tail) {
|
|
412
|
+
s = _txt(s);
|
|
413
|
+
if (_blen(s) <= cap) return { text: s, truncated: false };
|
|
414
|
+
const ls = s.split('\n');
|
|
415
|
+
let acc = 0, keep = 0;
|
|
416
|
+
if (tail) {
|
|
417
|
+
for (let i = ls.length - 1; i >= 0; i--) { const add = (keep ? 1 : 0) + _blen(ls[i]); if (acc + add > cap) break; acc += add; keep++; }
|
|
418
|
+
} else {
|
|
419
|
+
for (let i = 0; i < ls.length; i++) { const add = (keep ? 1 : 0) + _blen(ls[i]); if (acc + add > cap) break; acc += add; keep++; }
|
|
420
|
+
}
|
|
421
|
+
// **"๋ฌด์์ ๋ด์ฉ์ผ๋ก ์
์ง"๋ฅผ ํ์ ํ์ง ์๋๋ค.** ์ด ์๋ฆฌ์์ ๋ฐ์ดํฐ ์์ค์ด ์ธ ๋ฒ ์ฌ๋ฐํ๋ค:
|
|
422
|
+
// โ `keep > 0` โ ๊ฒฝ๊ณ์ ๋น ์ค ํ๋๋ฉด 70,000์๊ฐ 0์ โก `acc > 0` โ ๋น ์ค ๋ ๊ฐ๋ฉด 1์
|
|
423
|
+
// โข ๋ด์ฉ ๋ฐ์ดํธ(content) โ CRLF ์ `\r` ๊ณผ ๊ณต๋ฐฑ/ํญ์ด ๋ด์ฉ์ผ๋ก ์ธ์ด์ ธ ๋ค์ 1~3์
|
|
424
|
+
// ๋งค๋ฒ ์
์ ์กฐ๊ธ์ฉ ํ๋ ธ์ผ๋ฏ๋ก ์
์ ์์ค๋ค. ์จ์ ํ ์ค๋ก ์ฑ์ด ๋ค, **๋จ์ ์์ฐ๋งํผ ๊ฒฝ๊ณ ์ค์ ์ฝ๋ํฌ์ธํธ๋ก
|
|
425
|
+
// ์๋ผ ์ด์ด ๋ถ์ธ๋ค**. ์ด๋ค ๊ณต๋ฐฑ ์กฐํฉ์๋ ์์ฐ์ด ์ฑ์์ง๊ณ , ์์๊ฐ ์ ์ง๋๋ฏ๋ก "์๋ถ๋ถ/๋ท๋ถ๋ถ" ๊ณ ์ง๊ฐ ์ฐธ์ด ๋๋ค.
|
|
426
|
+
// (ํ๋ ๋ ์ค ๊ธด ์ชฝ๋ง ๊ณจ๋๋๋ฐ, ๊ฒฝ๊ณ ์ค์ด ๊ธธ๋ฉด **๋ฌธ์์ ์ ๋ชฉยทํธํฐ๊ฐ ํต์งธ๋ก ์ฌ๋ผ์ก๋ค** โ ๊ฒ์ ์ค์ธก.)
|
|
427
|
+
let packed = tail ? ls.slice(ls.length - keep).join('\n') : ls.slice(0, keep).join('\n');
|
|
428
|
+
// `\n` ์ผ๋ก๋ง ๋๋๋ฏ๋ก CRLF ๋ฌธ์์์๋ ๊ฐ ์ค ๋์ `\r` ์ด ๋จ๋๋ค. head ๋ฐฉํฅ์์ ๋ค์ ์ค์ด ์ ๋ค์ด๊ฐ๋ฉด
|
|
429
|
+
// ์ฌ์กฐ๋ฆฝ ๋ ๊ฐํ์ด ๋ถ์ง ์์ **๊ณ ๋ฆฝ๋ CR** ์ด ๊ผฌ๋ฆฌ์ ๋จ๋๋ค(๊ฒ์ ์ค์ธก: "A\r"). ํ์ ๋ฐ์ดํฐ์ ์ ์ด๋ฌธ์๋ฅผ
|
|
430
|
+
// ๋จ๊ธฐ์ง ์๋๋ก ์๋ผ๋ธ๋ค โ tail ๋ฐฉํฅ์ ์์ ๊ฐํ์ด ๋ถ์ผ๋ฏ๋ก ํด๋น ์์.
|
|
431
|
+
if (!tail) packed = packed.replace(/\r$/, '');
|
|
432
|
+
const line = (tail ? ls[ls.length - 1 - keep] : ls[keep]) || '';
|
|
433
|
+
// ๊ฒฝ๊ณ ์ค์ **ํญ์** ์๋ผ ๋ถ์ด๋ฉด ํ๋ฒํ ๋ฌธ์๊น์ง ์ค ์ค๊ฐ์์ ์๋ฆฐ๋ค("์ค ๊ฒฝ๊ณ ์ ๋จ" ์์ฑ์ด ๊นจ์ง๋ค).
|
|
434
|
+
// ํผ์์๋ ์ํ์ ๋๋ ์ค, ์ฆ **์ด๋ค ์์ฐ์ผ๋ก๋ ํต์งธ๋ก๋ ๋ด๊ธธ ์ ์๋ ์ค**์ผ ๋๋ง ์๋ผ ๋ถ์ธ๋ค.
|
|
435
|
+
const mustCut = _blen(line) > cap;
|
|
436
|
+
const room = mustCut ? cap - acc - (keep && line ? 1 : 0) : 0; // ์ด์ด ๋ถ์ผ ๊ฐํ ๋ชซ๊น์ง ๋บ๋ค
|
|
437
|
+
const cps = Array.from(line);
|
|
438
|
+
let n = 0, len = 0;
|
|
439
|
+
if (room > 0) {
|
|
440
|
+
if (tail) { for (let i = cps.length - 1; i >= 0 && len + _blen(cps[i]) <= room; i--) { len += _blen(cps[i]); n++; } }
|
|
441
|
+
else { for (let i = 0; i < cps.length && len + _blen(cps[i]) <= room; i++) { len += _blen(cps[i]); n++; } }
|
|
442
|
+
}
|
|
443
|
+
const part = n ? (tail ? cps.slice(cps.length - n).join('') : cps.slice(0, n).join('')) : '';
|
|
444
|
+
const text = !part ? packed : (!keep ? part : (tail ? part + '\n' + packed : packed + '\n' + part));
|
|
445
|
+
return { text, truncated: true };
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
function buildDocsData(root, nowIso, caps) {
|
|
449
|
+
const perCap = (caps && caps.perCap) || DOC_PER_CAP;
|
|
450
|
+
const totalCap = (caps && caps.totalCap) || DOC_TOTAL_CAP;
|
|
451
|
+
const minSlice = Math.max(256, Math.min(2048, Math.floor(totalCap / 8)));
|
|
452
|
+
const files = [];
|
|
453
|
+
let spent = 0;
|
|
454
|
+
for (const d of DOC_FILES) {
|
|
455
|
+
const base = { key: d.key, title: d.title, rel: d.rel, lang: d.lang || 'md', tail: !!d.tail };
|
|
456
|
+
const p = path.join(root, d.rel);
|
|
457
|
+
if (!exists(p)) { files.push(Object.assign({}, base, { missing: true, text: '', totalChars: 0, truncated: false })); continue; }
|
|
458
|
+
let raw;
|
|
459
|
+
try { raw = read(p); } catch { files.push(Object.assign({}, base, { unreadable: true, text: '', totalChars: 0, truncated: false })); continue; }
|
|
460
|
+
// **์๊ฒฉ์ฆ๋ช
ํ์ง๊ฐ ์์ผ๋ฉด ๋ณธ๋ฌธ์ ์ฃ์ง ์๋๋ค.** ๊ฐ ๋จ์ ๋ง์คํน์ ๋ค์ฏ ๋ผ์ด๋ ๋์ ๊ณ์ ์์ด์
|
|
461
|
+
// ์์ ์ ์ ์ ์์ ๋บ๋ค(๋ง์คํน์ ์๋์์ ๋ ๋ฒ์งธ ๋ฐฉ์ด์ธต์ผ๋ก๋ง ๋จ๋๋ค). ์ค์ธก ๋น์ฉ 0.6%.
|
|
462
|
+
if (_hasCred(raw)) {
|
|
463
|
+
files.push(Object.assign({}, base, {
|
|
464
|
+
guarded: true, text: '', truncated: false,
|
|
465
|
+
totalChars: raw.length, charsTotal: Array.from(raw).length, totalBytes: _blen(raw), bytes: 0, chars: 0,
|
|
466
|
+
}));
|
|
467
|
+
continue;
|
|
468
|
+
}
|
|
469
|
+
const red = _redact(raw); // dashboard ์ ๊ฐ์ ์ ์ด(๋ ๋ฒ์งธ ๋ฐฉ์ด์ธต)
|
|
470
|
+
const remain = totalCap - spent;
|
|
471
|
+
// ์์ฌ ์์ฐ์ด ์๋ฏธ ์๋ ํฌ๊ธฐ๋ฉด **์กฐ๊ฐ์ ์ฃ์ง ์๊ณ ๊ฑด๋๋ด๋ค**. ์ข
์ ์ remain<=0 ์ผ ๋๋ง ๊ฑด๋๋ฐ์ด
|
|
472
|
+
// 159์์ง๋ฆฌ ์ธ๋ชจ์๋ ์กฐ๊ฐ์ด "์๋ฆผ"์ผ๋ก ํ์๋๋ค(์ธก์ ์ผ๋ก ํ์ธ). ์กฐ๊ฐ๋ณด๋ค "์ ๋ด์๋ค"๊ฐ ์ ํํ๋ค.
|
|
473
|
+
if (remain < minSlice) { files.push(Object.assign({}, base, { skipped: true, text: '', totalChars: red.length, totalBytes: _blen(red), bytes: 0, truncated: true, chars: 0, charsTotal: Array.from(red).length })); continue; }
|
|
474
|
+
const c = _capDoc(red, Math.min(perCap, remain), !!d.tail);
|
|
475
|
+
spent += _blen(c.text); // ์์ฐ๋ ๋ฐ์ดํธ๋ก ์ผ๋ค(์ํ๊ณผ ๊ฐ์ ๋จ์)
|
|
476
|
+
// ํ๋ฉด ๊ณ ์ง์ "์" ๋ **์ฝ๋ํฌ์ธํธ**์ฌ์ผ ํ๋ค. String.length(UTF-16 ์ฝ๋ ๋จ์)๋ฅผ ์ฐ๋ฉด ์ด๋ชจ์ง ๋ฌธ์์์
|
|
477
|
+
// 32,767/60,001์ ๋ก ๋์ค์ง๋ง ์ค์ ๋ก๋ 16,384/30,001์๋ค(๊ฒ์ ์ค์ธก). ์ธ์ด์ ํจ๊ป ์ฃ๋๋ค.
|
|
478
|
+
files.push(Object.assign({}, base, {
|
|
479
|
+
text: c.text, totalChars: red.length, totalBytes: _blen(red), bytes: _blen(c.text), truncated: c.truncated,
|
|
480
|
+
chars: Array.from(c.text).length, charsTotal: Array.from(red).length,
|
|
481
|
+
}));
|
|
482
|
+
}
|
|
483
|
+
return { at: nowIso, perCap, totalCap, spent, files };
|
|
484
|
+
}
|
|
241
485
|
|
|
242
486
|
// ํ๋ค์ค ํ๋ฉด โ {project, version, counts, nodes, edges}. deps ๋ก in-process ๋ก๋ ์ฃผ์
(์
ธ๋ง X).
|
|
243
487
|
function buildGraphData(root, deps = {}) {
|
|
@@ -315,7 +559,45 @@ function buildGraphData(root, deps = {}) {
|
|
|
315
559
|
// 1.36.53 (UR-0062): ๊ธฐ์ ํ๋กํ ์๋ฒ ๋ โ ๐ ๊ธฐ์ ํญ ๋ฐ์ดํฐ
|
|
316
560
|
const tech = (typeof deps._loadTechProfile === 'function' ? (deps._loadTechProfile(root) || null) : null) || { current: { languages: [], services: [] }, history: [] };
|
|
317
561
|
const toggleRegistry = deps._toggleRegistry || {};
|
|
318
|
-
|
|
562
|
+
// ํ๋๋ง๋ค ์์ผ๋ก ๊ฐ์ธ๋ฉด ๋ฐ๋์ ๋น ๋จ๋ฆฐ๋ค(๋ฌธ์ ํญ๋ง ๊ฐ๋ํ๋ค๊ฐ nodesยทroadmap ์ผ๋ก ์๋ค).
|
|
563
|
+
// **์๋ฒ ๋ ์ง์ ํ ๊ณณ**์์ ๋ชจ๋ ๋ฌธ์์ด์ ํต๊ณผ์ํจ๋ค โ ์ง๊ธ ์๋ ํ๋ฉด๋, ๋์ค์ ์ถ๊ฐ๋ ํ๋ฉด๋ ํจ๊ป ๋ฎ์ธ๋ค.
|
|
564
|
+
// idยทtype ๊ฐ์ ์์ฒด ์์ฑ ๊ฐ์ ํ์ง์ ๊ฑธ๋ฆฌ์ง ์์ผ๋ฏ๋ก ๋ฌดํดํ๋ค.
|
|
565
|
+
// **๊น์ด ์ ํ์ ๋๋ฉด ๊ทธ ๋๋จธ๊ฐ ํต์งธ๋ก ์ฐํํ๋ค.** ์ํ์ ๋ง์ผ๋ ค 12๋จ๊ณ ์ํ์ ๋๋๋, 12๋จ๊ณ๋ณด๋ค ๊น์
|
|
566
|
+
// ๊ฐ์ฒด๋ ๊ทธ๋๋ก ๋ฐํ๋ผ ๊ทธ ์๋ ๋ฌธ์์ด์ ์ ๊ทํ๊ฐ ์์ ๊ฑธ๋ฆฌ์ง ์์๋ค(๊ฒ์ ์ค์ธก: tech-profile.json ์
|
|
567
|
+
// ์์ JSON ์ด๋ผ ์ค CLI ๋ก ๋๋ฌ ๊ฐ๋ฅ). ์ํ ๋์ **๋ฐฉ๋ฌธ ์งํฉ**์ผ๋ก ์ํ๋ง ๋๋๋ค โ ๊น์ด๋ ์ ํํ์ง ์๋๋ค.
|
|
568
|
+
// ๋ฐฉ๋ฌธ ์งํฉ์ **์ฌ๊ท ์คํ์ฒ๋ผ** ์จ์ผ ํ๋ค. ์ ์ญ ์งํฉ์ผ๋ก ๋๋ฉด ๊ฐ์ ๊ฐ์ฒด๋ฅผ ๋ ํ๋๊ฐ ๊ณต์ ํ ๋
|
|
569
|
+
// ๋ ๋ฒ์งธ๊ฐ ์ํ์ด ์๋๋ฐ๋ ์๋ ค ๋๊ฐ๋ค(๊ฒ์ ์ค์ธก: `{first:X, second:X}` ์ second ๊ฐ null ์ด ๋๋ค).
|
|
570
|
+
// ๋ค์ด๊ฐ ๋ ๋ฃ๊ณ **๋์ฌ ๋ ๋บ๋ค** โ ์ง์ง ์ํ(์กฐ์์ ์์ ์ด ์๋ ๊ฒฝ์ฐ)๋ง ๋๊ธด๋ค.
|
|
571
|
+
// ์ฌ๊ท ๊น์ด๋ ์ ํํ์ง ์๋, ์คํ์ด ํฐ์ง๋ฉด ๊ทธ ๊ฐ์ง๋ง ํ์ง ๋ฌธ์์ด๋ก ๋์ฒดํ๋ค(์์ฑ ์์ฒด๊ฐ ์คํจํ๋ฉด ์ ๋๋ค).
|
|
572
|
+
// ๊น์ด ์ํ ์์ฒด๊ฐ ๋ฌธ์ ๊ฐ ์๋๋ผ **์ํ์ ๋๊ฒผ์ ๋ ์๋ณธ์ ๊ทธ๋๋ก ํต๊ณผ์ํจ ๊ฒ**์ด ๋ฌธ์ ์๋ค(๊ทธ๊ฒ ์ฐํ์๋ค).
|
|
573
|
+
// ์ํ์ ๋์ผ๋ฉด **์๋ฆฌํ์์ ๋ฌธ์์ด๋ก ๋์ฒด**ํ๋ค โ ์๋ฌด๊ฒ๋ ์์ง ์๊ณ , ๋ค์ด์ JSON.stringify ๋ ์์ ํ๋ค
|
|
574
|
+
// (์ง๋ ฌํ ์์ฒด๊ฐ ์ฝ 4์ฒ ๋จ๊ณ์์ ์คํ์ ํฐ๋จ๋ฆฐ๋ค โ 24KB ์ง๋ฆฌ ์ ํจ JSON ํ๋๋ก ์์ฑ์ด ์คํจํ๋ค).
|
|
575
|
+
const MAXD = 200; // ์ ์ ๋ฐ์ดํฐ๋ ์ด ๊ทผ์ฒ์๋ ์ค์ง ์๋๋ค
|
|
576
|
+
const _deepSafe = (v, path, depth) => {
|
|
577
|
+
if (typeof v === 'string') return _safe(v);
|
|
578
|
+
if (!v || typeof v !== 'object') return v;
|
|
579
|
+
const dep = depth || 0;
|
|
580
|
+
if (dep > MAXD) return _GUARD_TXT; // fail-safe: ์๋ณธ์ด ์๋๋ผ ํ์ ๋ฌธ์์ด๋ก ๋์ฒด
|
|
581
|
+
const p = path || new Set();
|
|
582
|
+
if (p.has(v)) return null; // ์กฐ์์ ์์ ์ด ์๋ค = ์ํ โ ์๋ผ๋ธ๋ค
|
|
583
|
+
p.add(v);
|
|
584
|
+
try {
|
|
585
|
+
if (Array.isArray(v)) return v.map(x => _deepSafe(x, p, dep + 1));
|
|
586
|
+
const o = {};
|
|
587
|
+
for (const k of Object.keys(v)) o[k] = _deepSafe(v[k], p, dep + 1);
|
|
588
|
+
return o;
|
|
589
|
+
} finally {
|
|
590
|
+
p.delete(v); // ํ์ ๋
ธ๋๊ฐ ๊ณต์ ์ฐธ์กฐ๋ฅผ ๋ค์ ์ธ ์ ์๊ฒ ๋๋๋ฆฐ๋ค
|
|
591
|
+
}
|
|
592
|
+
};
|
|
593
|
+
// 1.36.96 (P-0010): ๐ ๋ฌธ์ ํญ โ .harness ํต์ฌ ๋ฌธ์ 7์ข
์ค๋
์ท(๋ง์คํน + ์ํ + ์๋ฆผ ๊ณ ์ง).
|
|
594
|
+
const docs = buildDocsData(root, deps.nowIso || new Date().toISOString());
|
|
595
|
+
// `docs` ๋ buildDocsData ์์ **์ด๋ฏธ ๊ฐ์ ์ ์ด๋ฅผ ํต๊ณผํ๊ณ ํ๊ณ(spent/bytes)๋ ๊ฑฐ๊ธฐ์ ํ์ **๋๋ค.
|
|
596
|
+
// ์ฌ๊ธฐ์ ๋ค์ ๋ณํํ๋ฉด ํ
์คํธ๊ฐ ๋ฏธ์ธํ๊ฒ ๋ฐ๋์ด "๋ณด๊ณ ํ spent = ์ค์ ์๋ฒ ๋ ๋ฐ์ดํธ" ๋ถ๋ณ์์ด ๊นจ์ง๋ค
|
|
597
|
+
// (๊ฒ์ ์ค์ธก: 1๋ฐ์ดํธ ์ฐจ์ด). ๋ ๋ฒ ์ฒ๋ฆฌํ์ง ์๋๋ค.
|
|
598
|
+
const safe = _deepSafe({ project: rd.project || path.basename(root), version: rd.version || '', root, counts, nodes, edges, roadmap, toggles, toggleRegistry, tech });
|
|
599
|
+
safe.docs = docs;
|
|
600
|
+
return safe;
|
|
319
601
|
}
|
|
320
602
|
|
|
321
603
|
// `leerness graph --html [path] [--out file] [--json]` ํธ๋ค๋ฌ.
|
|
@@ -338,4 +620,4 @@ function graphHtmlCmd(root, deps = {}, outFile) {
|
|
|
338
620
|
return summary;
|
|
339
621
|
}
|
|
340
622
|
|
|
341
|
-
module.exports = { graphHtmlCmd, buildGraphData };
|
|
623
|
+
module.exports = { graphHtmlCmd, buildGraphData, buildDocsData, _capDoc, DOC_FILES, DOC_PER_CAP, DOC_TOTAL_CAP };
|
package/lib/pure-utils.js
CHANGED
|
@@ -24,11 +24,121 @@ const _SECRET_ASSIGN = /\b([A-Za-z0-9_]*(?:TOKEN|KEY|SECRET|PASSWORD|PASSWD|PWD|
|
|
|
24
24
|
// (ํค๋ ๋ฐ์ ๋งจ `Bearer <๊ฐ>` ์ ์๋ SHAPE ๊ท์น์ด ํํ๋ก ์ก๋๋ค โ ์ฐ๋ฌธ ํผ์ ์ํ์ ๊ฐ์ํ์ง ์๋๋ค.)
|
|
25
25
|
const _SECRET_AUTH_HEADER = /\b((?:proxy-)?authorization)([ \t]*[:=][ \t]*)(?:(Bearer|Basic|Token|ApiKey|Digest)([ \t]+))?([A-Za-z0-9._~+/-]+=*)/gi;
|
|
26
26
|
const _SECRET_SHAPE = /\b(sk-[A-Za-z0-9_-]{8,}|ghp_[A-Za-z0-9]{16,}|gho_[A-Za-z0-9]{16,}|ghs_[A-Za-z0-9]{16,}|github_pat_[A-Za-z0-9_]{20,}|xox[baprs]-[A-Za-z0-9-]{8,}|AKIA[0-9A-Z]{12,}|ASIA[0-9A-Z]{12,}|AIza[A-Za-z0-9_-]{20,}|eyJ[A-Za-z0-9_-]{10,}\.[A-Za-z0-9_-]{10,}\.[A-Za-z0-9_-]{5,})/g;
|
|
27
|
+
// 1.36.96 (๊ฒ์ P1): ๋ง์คํน์ด **์ค์บ๋์ ๋ค๋ฅธ(๋ ์ฝํ) ๋ชฉ๋ก**์ ์ฐ๊ณ ์์๋ค. ์ค์ธก์ผ๋ก 6์ข
์ด ๊ทธ๋๋ก ์์ด
|
|
28
|
+
// ํ๋ฉด์ ์ค๋ ธ๋ค โ DB ์ ์๋ฌธ์์ด ๋น๋ฐ๋ฒํธ ยท GitLab PAT ยท npm ํ ํฐ ยท Stripe live ํค ยท SendGrid ยท ๊ฐ์ธํค ๋ธ๋ก.
|
|
29
|
+
// ์ ๋ถ `SECRET_PATTERNS`(catalogs.js)์ **์ด๋ฏธ ์๋** ํจํด์ด๋ค. ํ์ชฝ๋ง ๊ฐํ๋ ์ ํ์ ์ธ ํ๋ฉด ๋ถ์ผ์น๋ผ
|
|
30
|
+
// ๊ฐ์ ๋ชฉ๋ก์ ๊ณต์ ํ๋ค. placeholder/entropy ๊ฐ๋๋ ์ค์บ๋์ ๋์ผํ๊ฒ ์ ์ฉํด ์คํ์ ๋๋ฆฌ์ง ์๋๋ค.
|
|
31
|
+
// (catalogs.js ๋ require ๊ฐ ์์ด ์ํ์ด ์๊ธฐ์ง ์๋๋ค. ๊ทธ๋๋ ์ง์ฐ ๋ก๋ + ์คํจ ์ ๊ธฐ์กด ๊ท์น๋ง ์ฌ์ฉ.)
|
|
32
|
+
// ๊ฐ์ธํค๋ **๋ธ๋ก ์ ์ฒด**๋ฅผ ์ง์ด๋ค. ์ค์บ๋๋ BEGIN ์ค๋ง ํ์งํ๋ฉด ์ถฉ๋ถํ์ง๋ง(์๋ค/์๋ค), ํ๋ฉด์ ์ฃ๋
|
|
33
|
+
// ํ
์คํธ๋ ๋ณธ๋ฌธ(base64)์ด ๋จ์ผ๋ฉด ํค๊ฐ ๊ทธ๋๋ก ๋
ธ์ถ๋๋ค โ ์ค์ธก์์ BEGIN ์ค๋ง *** ๊ฐ ๋๊ณ ๋ณธ๋ฌธ์ ๋จ์๋ค.
|
|
34
|
+
// `[\s\S]*?` ๋ **BEGIN ๊ณผ ๋ฌด๊ดํ END ์ฌ์ด์ ์ฐ๋ฌธ๊น์ง** ์ผํจ๋ค โ ์ข
๋ฃ๋์ง ์์ ํค ํ๋๊ฐ ๋ฌธ์ ๋ค์ชฝ์
|
|
35
|
+
// END ์ค๊ณผ ์ง์ง์ด์ ธ ๊ทธ ์ฌ์ด ์ ๋ถ๊ฐ ์ฌ๋ผ์ง ์ ์๋ค(๋ณ์ด ์คํ ์ค ๋ฐ๊ฒฌ). ์ฌ์ด์๋ PEM ํค๋ยทbase64ยท๋น ์ค๋ง ํ์ฉํ๋ค.
|
|
36
|
+
// **๋ฌธํฑ๊ณผ ๋ฌธ์ ์กฐ์ฑ์ผ๋ก๋ ํค ๋ณธ๋ฌธ๊ณผ ์ฐ๋ฌธ์ ๊ฐ๋ฅผ ์ ์๋ค.** ๋ค ๋ฒ ์๋ํ๊ณ ๋งค๋ฒ ํ์ชฝ์ด ๊นจ์ก๋ค:
|
|
37
|
+
// 16์ โ ์ธ์ฉ ๋ฌธ์์ ์๋ณ์ ์ผํด ยท 40์ โ ์งง๊ฒ ๊ฐ๊ธด ํค ๋์ถ ยท
|
|
38
|
+
// "์ซ์/๊ธฐํธ ํฌํจ" โ ์๋ฌธ์๋ง์ธ ์ค์ ํค ์ค ๋์ถ(๊ฒ์๊ฐ ์ง์ง RSA ํค๋ก 51์ค ๋์ถ์ ์ฌํ) ยท
|
|
39
|
+
// ๊ทธ ์ญ โ `PolicyVersion2026Final` ๊ฐ์ ์ ์ ์๋ณ์ ์ผํด.
|
|
40
|
+
// ๊ทธ๋์ ๊ฐ์ด ์๋๋ผ **๋ฌธ๋งฅ๊ณผ ์คํจ ๋ฐฉํฅ**์ผ๋ก ์ ํ๋ค. BEGIN ๋ง์ปค ๋ค์ **๊ณต๋ฐฑ ์๋ ํ ์ค**์ ํค ์ฌ๋ฃ๋ก ๋ณธ๋ค.
|
|
41
|
+
// ์ฐ๋ฌธ์ ๊ฑฐ์ ํญ์ ๊ณต๋ฐฑ์ ํฌํจํ๋ฏ๋ก ๋ฌธ๋จ์ ์ด์๋จ๊ณ , ์ด๋ค ์กฐ์ฑ์ ํค ๋ณธ๋ฌธ๋ ์์ง ์๋๋ค.
|
|
42
|
+
// ๋๊ฐ: BEGIN ์ ์ธ์ฉํ ๋ฌธ์์์ **๋ฐ๋ก ๋ค์ ๋จ์ผ ํ ํฐ ํ ์ค**์ด ๊ฐ๋ ค์ง๋ค. ์๋ณธ ํ์ผ์ ๊ทธ๋๋ก์ด๊ณ
|
|
43
|
+
// ์ด๊ฑด ํ์์ฉ ์ค๋
์ท์ด๋ฏ๋ก, ๋์ถ๋ณด๋ค ์ด ์ชฝ์ด ๋ซ๋ค โ ํ์์ฉ ๋ง์คํน์ ์์ ํ ์ชฝ์ผ๋ก ์คํจํด์ผ ํ๋ค.
|
|
44
|
+
// PGP ๋ธ๋ก์ `=CRC` ์ค๋ ์ด ๊ท์น์ ์์ฐํ ํฌํจ๋๋ค.
|
|
45
|
+
const _PEM_HDR = '(?:Proc-Type|DEK-Info|Comment|Subject|Originator|Version|MessageID|Charset|X-[A-Za-z0-9-]+):[^\\r\\n]*';
|
|
46
|
+
// ์ค **๋๊น์ง** ๊ณต๋ฐฑ์ด ์์ด์ผ ํ๋ค โ ์ต์ปค๊ฐ ์์ผ๋ฉด ์ฐ๋ฌธ ์ค์ ์ฒซ ๋ฑ๋ง๋ง ๋จน๊ณ ๋๋จธ์ง๋ฅผ ๋จ๊ธด๋ค(์ค์ธก).
|
|
47
|
+
const _PEM_BODY = '(?!-----)\\S+(?=[ \\t]*(?:\\r?\\n|$))';
|
|
48
|
+
// 1.36.96: **๊ฐ ๋จ์ ๋ง์คํน์ด ์๋ฒฝํด์ผ ํ๋ ๊ตฌ์กฐ๋ฅผ ๋ฒ๋ฆฐ๋ค.**
|
|
49
|
+
// ๋ฌธ์ ๋ทฐ์ด์์ ๋ค์ฏ ๋ผ์ด๋ ๋์ ๋์ถ ๊ฒฝ๋ก๊ฐ ๊ณ์ ๋์๋ค โ ์ธ์ฉ๋ฌธ(`> `)์ผ๋ก ๊ฐ์ผ PEM, base64 ์ `/`ยท`+`,
|
|
50
|
+
// ์๋ฌธ์ `bearer`, placeholder ๋ชจ์ ํ ํฐ, ์ค ์ ์ ๋์ดโฆ ๊ฐ์ ํํ๋ก ๊ฐ๋ฅด๋ ค๋ ์๋๋ง๋ค ๋ฐ๋ก๊ฐ ์์๋ค.
|
|
51
|
+
// ๊ทธ๋์ **์๊ฒฉ์ฆ๋ช
ํ์ง๊ฐ ํ๋๋ผ๋ ์์ผ๋ฉด ๊ทธ ๋ฌธ์์ ๋ณธ๋ฌธ์ ์์ ์ฃ์ง ์๋๋ค.** ๋ง์คํน์ ๋ฐฉ์ด์ ๋ ๋ฒ์งธ ์ธต์ผ๋ก๋ง ๋จ๊ณ ,
|
|
52
|
+
// "์๋ฒฝํ ๋ง์คํน"์ด ์์ ์ ์ ์ ์์ ๋น ์ง๋ค.
|
|
53
|
+
// ๋น์ฉ ์ค์ธก(์ค์ ๋ฌธ์ 156๊ฐ): ํ์ง๊ฐ ๊ฑธ๋ฆฐ ํ์ผ **1๊ฐ(0.6%)** โ ์ฌ์ค์ ๊ณต์ง๋ค.
|
|
54
|
+
// ํ์ง๋ **๊ฐ์ด ์๋๋ผ ํ์**์ผ๋ก๋ง ์ ์ํ๋ค(์ค ์ ์ ๋์ดยท๋์๋ฌธ์ยท๋ณธ๋ฌธ ์กฐ์ฑ์ ์์กดํ์ง ์๋๋ค).
|
|
55
|
+
// ๊ฒ์๊ฐ ํ์ง๋ฅผ ๋น ์ ธ๋๊ฐ๋ ๋ค ํํ๋ฅผ ์คํ์ผ๋ก ๋ณด์๋ค โ RFC6750 ์ ์งง์(19์) Bearer, ์ธ์
์ฟ ํค,
|
|
56
|
+
// compact JWE(5๋ถ์ ์ด๋ผ `eyJโฆeyJ` ํํ๊ฐ ์๋๋ค), ๋งํฌ๋ค์ด ๊ฐ์กฐ๋ก ๊ฐ์ผ `` `Bearer` `` .
|
|
57
|
+
// ๋ํ๊ธฐ ์ ์ ๋น์ฉ์ ์๋ค: ์ค์ ๋ฌธ์ 156๊ฐ์์ **์ถ๊ฐ๋ก ๊ฑธ๋ฆฌ๋ ํ์ผ 0๊ฐ**. ๊ทธ๋์ ์
๋ค ๋ํ๋ค.
|
|
58
|
+
const _CRED_MARKERS = [
|
|
59
|
+
/-----BEGIN (?:[A-Z0-9]+ )*PRIVATE KEY(?: BLOCK)?-----/,
|
|
60
|
+
// JWT(3๋ถ์ )์ JWE(5๋ถ์ )๋ฅผ ํจ๊ป โ ๋ ๋ฒ์งธ ๋ถ์ ์ด ๋น์ด ์์ ์ ์๋ค(dir ์๊ณ ๋ฆฌ์ฆ)
|
|
61
|
+
/\beyJ[A-Za-z0-9_-]{10,}\.[A-Za-z0-9_-]*\.[A-Za-z0-9_-]{2,}/,
|
|
62
|
+
// ์คํด๊ณผ ๊ฐ ์ฌ์ด์ ๋งํฌ๋ค์ด ๊ฐ์กฐ(`**` ยท `` ` ``)๊ฐ ๋ ์ ์๋ค. RFC6750 ํ ํฐ์ ์งง์ ์ ์์ด 16์๋ก ์ก๋๋ค.
|
|
63
|
+
/\bbearer\b[^A-Za-z0-9\r\n]{0,4}[A-Za-z0-9_\-.=+/~]{16,}/i,
|
|
64
|
+
/\b(?:proxy-)?authorization[ \t]*[:=]/i,
|
|
65
|
+
/\b(?:set-)?cookie[ \t]*[:=]/i,
|
|
66
|
+
/\b(?:gh[pousr]_|github_pat_|sk-|sk_live_|rk_live_|xox[baprs]-|xapp-|AKIA|ASIA|AIza|ya29\.|glpat-|npm_|SG\.)/,
|
|
67
|
+
/\b(?:postgres|postgresql|mysql|mongodb(?:\+srv)?|redis|amqp):\/\/[^:\s/@]+:[^@\s/]+@/i,
|
|
68
|
+
];
|
|
69
|
+
function hasCredentialMarker(s) {
|
|
70
|
+
const t = String(s == null ? '' : s);
|
|
71
|
+
return _CRED_MARKERS.some(re => re.test(t));
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
// ์นดํ๋ก๊ทธ์ Bearer ๋ฌธ์๊ตฐ์ `[A-Za-z0-9_\-.=]` ๋ผ base64 ์ `/` `+` ์์ ๋๊ธด๋ค โ ์ ์กฐ๊ฐ์ด 20์ ๋ฏธ๋ง์ด๋ฉด
|
|
75
|
+
// `Bearer <์คํ ํฐ>` ์ด ํต์งธ๋ก ๋จ๋๋ค(์ค์ธก: ์ 8์ ๋ค `/` ์ธ 40์ ํ ํฐ์ด ์ ํ ๊ฐ๋ ค์ง์ง ์์๋ค).
|
|
76
|
+
// `Authorization:` ํค๋ ํํ๋ _SECRET_AUTH_HEADER ๊ฐ ์ก์ง๋ง ๋งจ `Bearer โฆ` ๋ ์ด ๊ท์น์ด ํ์ํ๋ค.
|
|
77
|
+
// ์ค์บ๋ ์ชฝ ๋ฌธ์๊ตฐ๋ ๊ฐ์ ๊ตฌ๋ฉ์ด ์๋ค(T-0085 ๋ก ๋จ๊ฒผ๋ค) โ ์ฌ๊ธฐ์๋ ํ์ ๋์ถ๋ถํฐ ๋ง๋๋ค.
|
|
78
|
+
const _SECRET_BEARER = /\bBearer\s+[A-Za-z0-9_\-.=+/]{20,}/g;
|
|
79
|
+
const _SECRET_PEM = new RegExp('-----BEGIN (?:[A-Z0-9]+ )*PRIVATE KEY(?: BLOCK)?-----(?:[ \\t]*\\r?\\n[ \\t]*(?:' + _PEM_HDR + '|' + _PEM_BODY + ')?)*[ \\t]*\\r?\\n[ \\t]*-----END (?:[A-Z0-9]+ )*PRIVATE KEY(?: BLOCK)?-----', 'g');
|
|
80
|
+
// END ์ค์ด ์์ผ๋ฉด ์ ๊ท์น์ด ๋งค์น๋์ง ์์ BEGIN ์ค๋ง ์ง์์ง๊ณ **๋ณธ๋ฌธ base64 ๊ฐ ๊ทธ๋๋ก ๋จ์๋ค**(๊ฒ์ ์ค์ธก).
|
|
81
|
+
// ๋ถ์ฌ๋ฃ๋ค ์๋ฆฐ ํค๊ฐ ํํ๋ฏ๋ก, BEGIN ๋ค์ ์ด์ด์ง๋ base64/ํค๋ ์ค๊น์ง ํจ๊ป ์ง์ด๋ค.
|
|
82
|
+
// โ ์ํธํ ํค๋ `Proc-Type:`/`DEK-Info:` ํค๋ ๋ค **๋น ์ค**์ด ์ค๊ณ ๋ณธ๋ฌธ์ด ์์ํ๋ค โ ๋น ์ค์์ ๋ฉ์ถ๋ฉด ๋ณธ๋ฌธ์ด ์๋ค.
|
|
83
|
+
// โก ๋ฐ๋๋ก ์๋ฌด `Name: value` ์ค์ด๋ ๋จน์ผ๋ฉด BEGIN ์ ์ธ์ฉํ ์ ์ฑ
๋ฌธ์์ ์ฐ๋ฌธ์ ์ผํจ๋ค(๋ ๋ค ๊ฒ์ ์ค์ธก).
|
|
84
|
+
// ๊ทธ๋์ ํค๋๋ **PEM ํ์ค ์ด๋ฆ๋ง** ํ์ฉํ๊ณ , ๋ณธ๋ฌธ base64 ์ค์ด **์ต์ ํ๋** ์์ ๋๋ง ํ์ฅํ๋ค.
|
|
85
|
+
const _SECRET_PEM_OPEN = new RegExp('-----BEGIN (?:[A-Z0-9]+ )*PRIVATE KEY(?: BLOCK)?-----(?:[ \\t]*\\r?\\n[ \\t]*' + _PEM_HDR + ')*(?:[ \\t]*\\r?\\n[ \\t]*)*(?:[ \\t]*\\r?\\n[ \\t]*(?:' + _PEM_BODY + '))+[ \\t]*\\r?\\n?', 'g');
|
|
86
|
+
|
|
87
|
+
// **ํ์ง์ฉ ๋ฌธ๋งฅ ํด๋ฆฌ์คํฑ์ ๊ฐ๋ฆผ์ ๊ทธ๋๋ก ์ฐ๋ฉด ์ ๋๋ค.** ํ์ง์ ์คํ์ ๊ฒฝ๊ณ ํ ์ค์ด์ง๋ง, ๊ฐ๋ฆผ์ ์คํ์
|
|
88
|
+
// ์ฌ์ฉ์๊ฐ ๋ณด๋ ๋ฌธ์๋ฅผ ์กฐ์ฉํ ํ๊ดดํ๋ค(๋์๋ณด๋๋ ์ด ํจ์๋ฅผ ์ด๋ค). ๊ฒ์ ์ค์ธก์ผ๋ก ํ์ธํ ๋ ๊ฐ์ง:
|
|
89
|
+
// 'AWS secret commit <40์ ์ปค๋ฐํด์> was reverted' โ ๋ฌธ์ฅ ์ ์ฒด๊ฐ *** ๋ก ์ฌ๋ผ์ก๋ค.
|
|
90
|
+
// 'Use Bearer authenticationMiddleware for API requests.' โ 'Use *** for API requests.'
|
|
91
|
+
// ์ํธ๋กํผ ๊ฒ์ดํธ(_looksSecretLike)๋ก๋ ๊ฐ๋ฆฌ์ง ์์๋ค โ ์ง์ง AWS ํค๊น์ง placeholder ๋ก ํ์ ๋๋ค(์ค์ธก).
|
|
92
|
+
// ๊ทธ๋์ ๋ฌธ๋งฅ ํจํด์ ๊ฐ๋ฆผ์์ ์ ์ธํ๊ณ , Bearer ๋ ๊ฐ์ ์ซ์๊ฐ ์์ ๋๋ง ๊ฐ๋ฆฐ๋ค.
|
|
93
|
+
// ๋จ๋ ๊ตฌ๋ฉ: `Authorization:` ์์ด ์ ํ **์๋ฌธ์๋ง์ผ๋ก ๋** Bearer ํ ํฐ. ํค๋ ํํ๋ _SECRET_AUTH_HEADER ๊ฐ,
|
|
94
|
+
// ์ค์ ํ ํฐ ํ์(JWTยทghp_ยทAKIAยทsk- ๋ฑ)์ ํํ ํจํด์ด ์ก๋๋ค.
|
|
95
|
+
// ์ดํ์ AWS ๋ฌธ๋งฅ ํจํด์ ํต์งธ๋ก ์ ์ธํ๋๋ฐ, ๊ทธ๋ฌ๋ฉด `aws secret access key <40์>` ์ฒ๋ผ **๊ตฌ๋ถ์ ์๋ ์ค๊ฐ์ด
|
|
96
|
+
// ์๋ค**(๊ฒ์ ์ค์ธก). ๋ฌธ์ฅ์ ์ผํค์ง ์์ผ๋ฉด์ ๊ฐ๋ง ์ง์ฐ๋๋ก, ์ด ํจํด์ **๊ผฌ๋ฆฌ ์๊ฒฉ์ฆ๋ช
๋ง** ์นํํ๋ค.
|
|
97
|
+
// commit ํด์๊ฐ ๊ฐ์ ํํ๋ผ ๊ฐ๋ ค์ง๋ ๊ฒ์ ๊ฐ์ํ๋ค โ ๋ฌธ์ฅ ๊ตฌ์กฐ๋ ๋จ์ผ๋ฏ๋ก ํ๊ดด๊ฐ ์๋๋ค.
|
|
98
|
+
const _REDACT_SKIP = new Set();
|
|
99
|
+
const _REDACT_TAIL = {
|
|
100
|
+
'AWS Secret Access Key (context)': /(["']?)([A-Za-z0-9/+]{40})(["']?)$/,
|
|
101
|
+
};
|
|
102
|
+
// Bearer ๊ฐ๋ ๊ฐ์ ๊ฒฐ๋ก ์ด๋ค. ๊ธธ์ด ๋ฌธํฑ(32์)์ 20~31์ ์คํ ํฐ์ ๋์ณค๊ณ , ๋ชจ์ ํ๋ณ(camelCase ์์ธ)์
|
|
103
|
+
// `Bearer abcdefghijklmnopqrst` ยท `Bearer CorrectHorseBatteryStaple` ๊ฐ์ **์ ํจํ ๋ถํฌ๋ช
ํ ํฐ์ ์ฐ๋ฌธ์ผ๋ก
|
|
104
|
+
// ํ์ ํด ๋
ธ์ถ**ํ๋ค(๊ฒ์ ์ค์ธก). ๋ถํฌ๋ช
ํ ํฐ์ด ์๋ฌธ์๋ ๋ฑ๋ง๊ผด์ด ์๋๋ผ๋ ๋ณด์ฅ์ด ์๋ค โ ์์ธ๋ฅผ ์์ค๋ค.
|
|
105
|
+
// ๋๊ฐ: `Use Bearer authenticationMiddleware for API requests.` ๊ฐ์ ๋ฌธ์ฅ์ด `Use *** for โฆ` ๊ฐ ๋๋ค.
|
|
106
|
+
// ์นดํ๋ก๊ทธ๊ฐ ์ด๋ฏธ 20์ ์ด์๋ง ํ๋ณด๋ก ์ก์ผ๋ฏ๋ก `Bearer ์ธ์ฆ` ๊ฐ์ ์งง์ ํํ์ ์ํฅ์ด ์๋ค.
|
|
107
|
+
const _REDACT_GUARD = {};
|
|
108
|
+
let _SECRET_CATALOG = null;
|
|
109
|
+
function _secretCatalog() {
|
|
110
|
+
if (_SECRET_CATALOG) return _SECRET_CATALOG;
|
|
111
|
+
try { _SECRET_CATALOG = require('./catalogs').SECRET_PATTERNS || []; } catch { _SECRET_CATALOG = []; }
|
|
112
|
+
return _SECRET_CATALOG;
|
|
113
|
+
}
|
|
27
114
|
function redactSecrets(s, max) {
|
|
28
115
|
let out = String(s == null ? '' : s)
|
|
29
116
|
.replace(_SECRET_AUTH_HEADER, (m, key, sep, scheme, gap) => `${key}${sep}${scheme ? scheme + (gap || ' ') : ''}***`)
|
|
30
117
|
.replace(_SECRET_ASSIGN, (m, k) => `${k}=***`)
|
|
31
|
-
.replace(_SECRET_SHAPE, '***')
|
|
118
|
+
.replace(_SECRET_SHAPE, '***')
|
|
119
|
+
.replace(_SECRET_PEM, '***')
|
|
120
|
+
.replace(_SECRET_PEM_OPEN, '***\n')
|
|
121
|
+
.replace(_SECRET_BEARER, '***');
|
|
122
|
+
for (const p of _secretCatalog()) {
|
|
123
|
+
const { re, valueGroup, requireSecretLike } = p;
|
|
124
|
+
if (!re || _REDACT_SKIP.has(p.name)) continue;
|
|
125
|
+
const guard = _REDACT_GUARD[p.name];
|
|
126
|
+
try {
|
|
127
|
+
out = out.replace(re, (...args) => {
|
|
128
|
+
const m0 = args[0];
|
|
129
|
+
const val = (valueGroup != null) ? args[valueGroup] : m0;
|
|
130
|
+
if (!val) return m0;
|
|
131
|
+
if (guard && !guard(m0)) return m0; // ๊ฐ๋ฆผ ์ ์ฉ ์ถ๊ฐ ๊ฐ๋
|
|
132
|
+
const tailRe = _REDACT_TAIL[p.name]; // ๊ผฌ๋ฆฌ ๊ฐ๋ง ์ง์ฐ๋ ํจํด
|
|
133
|
+
if (tailRe) { const t = m0.match(tailRe); return t ? m0.slice(0, m0.length - t[0].length) + t[1] + '***' + t[3] : m0; }
|
|
134
|
+
if (_isPlaceholderSecret(val)) return m0; // .env.example ์ ๋๋ฏธ๊ฐ
|
|
135
|
+
if (valueGroup != null && requireSecretLike && !_looksSecretLike(val)) return m0;
|
|
136
|
+
if (valueGroup == null) return '***';
|
|
137
|
+
const i = m0.indexOf(val); // ๊ฐ๋ง ์ง์ฐ๊ณ ๋งฅ๋ฝ์ ๋จ๊ธด๋ค
|
|
138
|
+
return i < 0 ? '***' : m0.slice(0, i) + '***' + m0.slice(i + val.length);
|
|
139
|
+
});
|
|
140
|
+
} catch { /* ํ ํจํด์ด ์คํจํด๋ ๋๋จธ์ง ๋ง์คํน์ ๊ณ์ํ๋ค */ }
|
|
141
|
+
}
|
|
32
142
|
if (max && out.length > max) out = out.slice(0, max) + 'โฆ';
|
|
33
143
|
return out;
|
|
34
144
|
}
|
|
@@ -1321,7 +1431,7 @@ function _replaceMdSection(content, heading, newBodyLines, opts = {}) {
|
|
|
1321
1431
|
module.exports = { _decisionBlocksWithOffset, _blocksWithOffset, _lineOfOffset,
|
|
1322
1432
|
_parseImplExports, _briefUnfilled, _planGoalUnfilled, _mdSectionBody, _draftAnchors, _replaceMdSection,
|
|
1323
1433
|
_matchTool, _parsePackageJsonDeps, _parseRequirementsTxt, _buildGlossary, _renderGlossaryMd, GLOSSARY_START, GLOSSARY_END,
|
|
1324
|
-
_isSecretKey, redactSecrets, compareVer, parseHarnessVersion,
|
|
1434
|
+
_isSecretKey, redactSecrets, hasCredentialMarker, compareVer, parseHarnessVersion,
|
|
1325
1435
|
_isPlaceholderSecret, _looksSecretLike,
|
|
1326
1436
|
_mergeLines, _mergeEnvLines, _mergeReadmeSection, _managedMerge, _parseSkillsValue,
|
|
1327
1437
|
_parseArchiveBlocks, _parseSkillCatalog, _renderTeamsMd, _composeTeamPlan, _teamHandoffReminders, _cadenceAssessment, _teamDeployGate, _renderWorkspaceReferenceGuide, _memorySurface, _renderPulseLine,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "leerness",
|
|
3
|
-
"version": "1.36.
|
|
3
|
+
"version": "1.36.97",
|
|
4
4
|
"description": "The AI-coding operations layer that makes \"done\" require evidence โ persistent memory, evidence-gated completion checks, and clean handoffs for any AI agent (Claude Code, Codex, Cursor). State lives as plain files in your repo. CLI + MCP, 0 runtime dependencies.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"leerness",
|