chore(rebar): Pier_T_rebar 작업 폴더 초기 구성 및 외부 의존 파일 통합

- Code\rebar_pipeline, review_pipeline, pier-program을 정션에서 실제 폴더로 전환
- Code\rhino_mcp 및 CLAUDE_rhino배경.md 추가, .mcp.json은 PYTHONPATH로 새 위치 사용
- pier-program 내부 .git 제거(이력은 backup\pier-program_20261028.bundle에 보관)
- worktree 가이드 반영(CLAUDE.local.md, HANDOFF.md)
- D:\Rhino-MCP 경로 참조를 새 위치로 치환

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
ahnyongjooandClaude Sonnet 5.5 committed 2026-10-28 11:20:18 +09:00
commit 964a841de1
3978 files changed
+58013356

No files matched your search

File diff suppressed because it is too large. Load diff
+144
View File
@@ -0,0 +1,144 @@
// Minimal HWP5 text extractor: CFB (OLE2) reader + zlib + PARA_TEXT records. No external packages.
const fs = require('fs');
const zlib = require('zlib');
const [,, inFile, outFile] = process.argv;
const buf = fs.readFileSync(inFile);
const sig = buf.slice(0, 8).toString('hex');
if (sig !== 'd0cf11e0a1b11ae1') { console.error('not an OLE file', sig); process.exit(1); }
const secShift = buf.readUInt16LE(0x1e);
const secSize = 1 << secShift;
const miniShift = buf.readUInt16LE(0x20);
const miniSize = 1 << miniShift;
const nFat = buf.readUInt32LE(0x2c);
const dirStart = buf.readUInt32LE(0x30);
const miniCutoff = buf.readUInt32LE(0x38);
const miniFatStart = buf.readUInt32LE(0x3c);
let difatStart = buf.readUInt32LE(0x44);
const nDifat = buf.readUInt32LE(0x48);
const ENDOFCHAIN = 0xfffffffe;
const FREE = 0xffffffff;
function secOff(s) { return (s + 1) * secSize; }
function readSector(s) { return buf.slice(secOff(s), secOff(s) + secSize); }
// FAT sector list from header DIFAT + DIFAT chain
const fatSecs = [];
for (let i = 0; i < 109 && fatSecs.length < nFat; i++) {
const v = buf.readUInt32LE(0x4c + i * 4);
if (v === FREE || v === ENDOFCHAIN) break;
fatSecs.push(v);
}
let d = difatStart;
for (let i = 0; i < nDifat && d !== ENDOFCHAIN && d !== FREE; i++) {
const sec = readSector(d);
for (let j = 0; j < secSize / 4 - 1 && fatSecs.length < nFat; j++) {
const v = sec.readUInt32LE(j * 4);
if (v !== FREE && v !== ENDOFCHAIN) fatSecs.push(v);
}
d = sec.readUInt32LE(secSize - 4);
}
const fat = [];
for (const s of fatSecs) {
const sec = readSector(s);
for (let j = 0; j < secSize / 4; j++) fat.push(sec.readUInt32LE(j * 4));
}
function chain(start) {
const out = [];
let s = start;
let guard = 0;
while (s !== ENDOFCHAIN && s !== FREE && guard++ < 10000000) { out.push(s); s = fat[s]; }
return out;
}
function readStream(start, size) {
const parts = chain(start).map(readSector);
return Buffer.concat(parts).slice(0, size);
}
// directory
const dirBuf = readStream(dirStart, chain(dirStart).length * secSize);
const entries = [];
for (let i = 0; i < dirBuf.length / 128; i++) {
const e = dirBuf.slice(i * 128, i * 128 + 128);
const nl = e.readUInt16LE(0x40);
if (nl === 0) { entries.push(null); continue; }
const name = e.slice(0, nl - 2).toString('utf16le');
entries.push({
name, type: e.readUInt8(0x42), left: e.readUInt32LE(0x44), right: e.readUInt32LE(0x48), child: e.readUInt32LE(0x4c),
start: e.readUInt32LE(0x74), size: Number(e.readBigUInt64LE(0x78)), id: i,
});
}
const root = entries[0];
const miniStream = readStream(root.start, root.size);
const miniFat = [];
{
const mf = Buffer.concat(chain(miniFatStart).map(readSector));
for (let j = 0; j < mf.length / 4; j++) miniFat.push(mf.readUInt32LE(j * 4));
}
function readMini(start, size) {
const parts = [];
let s = start;
let guard = 0;
while (s !== ENDOFCHAIN && s !== FREE && guard++ < 10000000) {
parts.push(miniStream.slice(s * miniSize, s * miniSize + miniSize));
s = miniFat[s];
}
return Buffer.concat(parts).slice(0, size);
}
function streamOf(e) { return e.size < miniCutoff ? readMini(e.start, e.size) : readStream(e.start, e.size); }
// walk tree to build path -> entry
const paths = {};
function walk(id, prefix) {
if (id === 0xffffffff || id >= entries.length || !entries[id]) return;
const e = entries[id];
walk(e.left, prefix);
const p = prefix + '/' + e.name;
paths[p] = e;
if (e.type === 1) walk(e.child, p);
walk(e.right, prefix);
}
walk(entries[0].child, '');
const header = streamOf(paths['/FileHeader']);
const flags = header.readUInt32LE(36);
const compressed = (flags & 1) !== 0;
const encrypted = (flags & 2) !== 0;
if (encrypted) { console.error('encrypted document'); process.exit(2); }
console.error('HWP version', header.readUInt32LE(32).toString(16), 'compressed', compressed, 'sections', Object.keys(paths).filter(p => /BodyText\/Section\d+$/.test(p)).length);
const secNames = Object.keys(paths).filter(p => /^\/BodyText\/Section\d+$/.test(p)).sort((a, b) => parseInt(a.match(/\d+$/)[0]) - parseInt(b.match(/\d+$/)[0]));
const EXT = new Set([1, 2, 3, 11, 12, 14, 15, 16, 17, 18, 21, 22, 23]);
const INL = new Set([4, 5, 6, 7, 8, 9, 19, 20]);
let outTxt = [];
for (const sn of secNames) {
let data = streamOf(paths[sn]);
if (compressed) data = zlib.inflateRawSync(data);
let pos = 0;
while (pos + 4 <= data.length) {
const h = data.readUInt32LE(pos); pos += 4;
const tag = h & 0x3ff; let size = (h >>> 20) & 0xfff;
if (size === 0xfff) { size = data.readUInt32LE(pos); pos += 4; }
const rec = data.slice(pos, pos + size); pos += size;
if (tag === 0x43) { // PARA_TEXT
let s = '';
for (let i = 0; i + 1 < rec.length;) {
const ch = rec.readUInt16LE(i);
if (ch >= 32) { s += String.fromCharCode(ch); i += 2; }
else if (EXT.has(ch) || INL.has(ch)) { if (ch === 9) s += '\t'; i += 16; }
else if (ch === 10 || ch === 13) { s += '\n'; i += 2; }
else if (ch === 24 || ch === 25 || ch === 26 || ch === 27 || ch === 28 || ch === 29 || ch === 30 || ch === 31) { if (ch === 24) s += '-'; if (ch === 30 || ch === 31) s += ' '; i += 2; }
else { i += 2; }
}
outTxt.push(s.replace(/\n+$/, ''));
} else if (tag === 0x58) { // EQEDIT (equation script)
try {
const n = rec.readUInt16LE(4);
const script = rec.slice(6, 6 + n * 2).toString('utf16le').replace(/\s+/g, ' ').trim();
outTxt.push(' [수식: ' + script + ']');
} catch (e) { outTxt.push(' [수식 읽기 실패]'); }
}
}
}
fs.writeFileSync(outFile, outTxt.join('\n'), 'utf8');
console.error('paragraphs', outTxt.length, 'chars', outTxt.join('\n').length);