@cliphijack/santaclaude 1.0.27 → 1.0.29
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/package.json +1 -1
- package/santaclaude.js +22 -2
package/package.json
CHANGED
package/santaclaude.js
CHANGED
|
@@ -264,6 +264,25 @@ const SHARE_PORT = 8799;
|
|
|
264
264
|
const SHARE_DIRS = [path.join(os.homedir(), '.santaclaude', 'outbox'), path.join(os.homedir(), '.santaclaude', 'share'), path.join(os.homedir(), 'Downloads')];
|
|
265
265
|
let _tnCache = null, _shareToken = null, _shareServer = null;
|
|
266
266
|
function notionSet() { try { return /^NOTION_TOKEN=.+/m.test(fs.readFileSync(path.join(os.homedir(), '.santaclaude', '.env'), 'utf8')); } catch (e) { return false; } } // ~/.santaclaude/.env 에 토큰 있나
|
|
267
|
+
// 🔮 노션 피드 — 부모페이지("클로드세션") 하위(세션 페이지·DB)를 읽어 웹에 보여줌. 커넥터(유저 PC)가 직접 호출 → 서버 무부담
|
|
268
|
+
let _njCache = null;
|
|
269
|
+
function refreshNotion() {
|
|
270
|
+
let env = ''; try { env = fs.readFileSync(path.join(os.homedir(), '.santaclaude', '.env'), 'utf8'); } catch (e) { _njCache = null; return; }
|
|
271
|
+
const tok = (env.match(/^NOTION_TOKEN=(.+)$/m) || [])[1];
|
|
272
|
+
const parent = (env.match(/^NOTION_PARENT_PAGE=(.+)$/m) || [])[1];
|
|
273
|
+
if (!tok) { _njCache = null; return; }
|
|
274
|
+
if (!parent) { _njCache = { noParent: true, items: [] }; return; }
|
|
275
|
+
fetch('https://api.notion.com/v1/blocks/' + parent.trim() + '/children?page_size=50', { headers: { Authorization: 'Bearer ' + tok.trim(), 'Notion-Version': '2022-06-28' } })
|
|
276
|
+
.then((r) => r.json()).then((j) => {
|
|
277
|
+
if (!j || j.object === 'error') { _njCache = { err: (j && j.message) || 'notion error', items: [] }; return; }
|
|
278
|
+
const items = [];
|
|
279
|
+
for (const b of (j.results || [])) {
|
|
280
|
+
if (b.type === 'child_page') items.push({ t: 'page', id: (b.id || '').replace(/-/g, ''), title: (b.child_page && b.child_page.title) || '(제목 없음)' });
|
|
281
|
+
else if (b.type === 'child_database') items.push({ t: 'db', id: (b.id || '').replace(/-/g, ''), title: (b.child_database && b.child_database.title) || '(DB)' });
|
|
282
|
+
}
|
|
283
|
+
_njCache = { items: items.slice(0, 30), parent: parent.trim().replace(/-/g, '') };
|
|
284
|
+
}).catch(() => { _njCache = null; });
|
|
285
|
+
}
|
|
267
286
|
function startShareServer(ip) { // 테일넷 IP에만 바인드 → 테일넷 피어만 접근. 경로 토큰 + basename으로 보호
|
|
268
287
|
if (_shareServer || !ip) return;
|
|
269
288
|
try { _shareToken = require('crypto').randomBytes(8).toString('hex'); } catch (e) { _shareToken = String(Date.now()); }
|
|
@@ -423,6 +442,7 @@ async function run(conf) {
|
|
|
423
442
|
try { execFileSync('tmux', ['set-option', '-g', 'history-limit', '50000'], { stdio: 'ignore' }); } catch (e) {} // 새로 띄우는 루돌프 pane은 스크롤백 5만줄(기존 pane은 유지)
|
|
424
443
|
setTimeout(() => { try { fs.writeFileSync(_GOOD, VER); } catch (e) {} }, 60000); // 60초+ 살면 이 버전을 안정버전으로 기록(롤백 기준)
|
|
425
444
|
refreshTn(); setInterval(refreshTn, 30000); // 📡 테일스케일·Taildrop 감지(30초)
|
|
445
|
+
refreshNotion(); setInterval(refreshNotion, 45000); // 🔮 노션 피드(45초)
|
|
426
446
|
setTimeout(checkUpdate, 90000); setInterval(checkUpdate, 3 * 3600 * 1000); // 자동 업데이트 체크: 시작 90초 후 + 3시간마다
|
|
427
447
|
console.log(`🛷 SantaClaude 커넥터 가동 v${VER} — pane=${pane} · ${every / 1000}s 폴링 · ${api}`);
|
|
428
448
|
if (paneExists(pane)) {
|
|
@@ -690,7 +710,7 @@ async function run(conf) {
|
|
|
690
710
|
console.log(`[발사] ${new Date().toISOString()} → ${tgt}: ${String(j.message).slice(0, 60)}`);
|
|
691
711
|
try { inject(tgt, '[SantaClaude] ' + j.message); } catch (e) { console.warn(` 주입 실패(${tgt}): ${e.message}`); }
|
|
692
712
|
}
|
|
693
|
-
function sendHb() { if (ws && ws.readyState === 1) { try { ws.send(JSON.stringify({ type: 'hb', pane, sessions: listWindows(session), token: LEAGUE_ON ? token : undefined, tok: LEAGUE_ON ? tok24h() : undefined, tn: _tnCache, notion: { set: notionSet() } })); } catch (e) {} } }
|
|
713
|
+
function sendHb() { if (ws && ws.readyState === 1) { try { ws.send(JSON.stringify({ type: 'hb', pane, sessions: listWindows(session), token: LEAGUE_ON ? token : undefined, tok: LEAGUE_ON ? tok24h() : undefined, tn: _tnCache, notion: { set: notionSet(), feed: _njCache } })); } catch (e) {} } }
|
|
694
714
|
// 화면 미러 — 변경됐을 때만 전송(claude 멈추면 0). 2.5초 체크라 응답 직후 빠르게 반영
|
|
695
715
|
let lastScr = '';
|
|
696
716
|
function sendScreen() { if (!ws || ws.readyState !== 1) return; let cur; try { cur = JSON.stringify(captureAll(session)); } catch (e) { return; } if (cur === lastScr) return; lastScr = cur; try { ws.send(JSON.stringify({ type: 'screen', screens: JSON.parse(cur) })); } catch (e) {} }
|
|
@@ -716,7 +736,7 @@ async function run(conf) {
|
|
|
716
736
|
// 폴링 폴백 (node<21 = WebSocket 미지원) — 워커가 DO 백엔드라 폴링이어도 KV write 0
|
|
717
737
|
async function pollTick() {
|
|
718
738
|
try {
|
|
719
|
-
post(api, '/api/heartbeat', { token, pane, sessions: listWindows(session), screens: captureAll(session), tok: LEAGUE_ON ? tok24h() : undefined, tn: _tnCache, notion: { set: notionSet() } }).catch(() => {});
|
|
739
|
+
post(api, '/api/heartbeat', { token, pane, sessions: listWindows(session), screens: captureAll(session), tok: LEAGUE_ON ? tok24h() : undefined, tn: _tnCache, notion: { set: notionSet(), feed: _njCache } }).catch(() => {});
|
|
720
740
|
post(api, '/api/control/claim', { token }).then((c) => { for (const cmd of (c && c.commands) || []) runControl(cmd); }).catch(() => {});
|
|
721
741
|
const d = await post(api, '/api/jobs/claim', { token });
|
|
722
742
|
for (const j of (d.jobs || [])) onJob(j);
|