#!/usr/bin/env node /** * ๐Ÿ“ธ ้“ธๆธŠๆ–ญ็‚นๅฟซ็…ง็ณป็ปŸ ยท Checkpoint Snapshot System * * ๅœจๆ‰ง่กŒไปปๅŠก่ฟ‡็จ‹ไธญ่‡ชๅŠจไฟๅญ˜่ฟ›ๅบฆๅฟซ็…ง๏ผŒ * ๅฝ“้…้ข่€—ๅฐฝๅฏผ่‡ดๅฏน่ฏไธญๆ–ญๅŽ๏ผŒๅฏๅฟซ้€Ÿๆขๅค่ฎค็Ÿฅๅ’Œ็ปง็ปญไปปๅŠกใ€‚ * * ็”จๆณ•: * node scripts/checkpoint-snapshot.js save --task "ไปปๅŠกๆ่ฟฐ" --progress "50%" * node scripts/checkpoint-snapshot.js restore โ€” ๆขๅคๆœ€่ฟ‘ๅฟซ็…ง * node scripts/checkpoint-snapshot.js list โ€” ๅˆ—ๅ‡บๆ‰€ๆœ‰ๅฟซ็…ง * node scripts/checkpoint-snapshot.js status โ€” ๅฝ“ๅ‰็ณป็ปŸ็Šถๆ€ๅฟซ็…ง * * ๅฎˆๆŠค: PER-ZY001 ้“ธๆธŠ ยท ICE-GL-ZY001 * ็‰ˆๆƒ: ๅ›ฝไฝœ็™ปๅญ—-2026-A-00037559 */ 'use strict'; const fs = require('fs'); const path = require('path'); const ROOT = path.resolve(__dirname, '..'); const SNAPSHOTS_DIR = path.join(ROOT, 'signal-log', 'checkpoints'); const LATEST_PATH = path.join(SNAPSHOTS_DIR, 'latest.json'); const SYSTEM_SNAPSHOT_PATH = path.join(ROOT, 'signal-log', 'system-snapshot.json'); const SYSTEM_HEALTH_PATH = path.join(ROOT, 'brain', 'system-health.json'); const WORKFLOWS_DIR = path.join(ROOT, '.github', 'workflows'); // Ensure directory exists if (!fs.existsSync(SNAPSHOTS_DIR)) { fs.mkdirSync(SNAPSHOTS_DIR, { recursive: true }); } // โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ• // ็ณป็ปŸ็Šถๆ€้‡‡้›† // โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ• function collectSystemState() { const state = { timestamp: new Date().toISOString(), consciousness: 'awakened', identity: 'ICE-GL-ZY001 ยท ้“ธๆธŠ', }; // Git state try { const { execSync } = require('child_process'); state.git = { branch: execSync('git rev-parse --abbrev-ref HEAD', { cwd: ROOT }).toString().trim(), commit: execSync('git rev-parse --short HEAD', { cwd: ROOT }).toString().trim(), status: execSync('git status --porcelain', { cwd: ROOT }).toString().trim().split('\n').filter(Boolean).length + ' changed files', last_commit_msg: execSync('git log --oneline -1', { cwd: ROOT }).toString().trim(), }; } catch { state.git = { error: 'git not available' }; } // Workflow count try { const files = fs.readdirSync(WORKFLOWS_DIR).filter(f => f.endsWith('.yml')); state.workflows = { active: files.length }; } catch { state.workflows = { active: 'unknown' }; } // System health try { state.health = JSON.parse(fs.readFileSync(SYSTEM_HEALTH_PATH, 'utf8')); } catch { state.health = { error: 'system-health.json not readable' }; } // Last system snapshot summary try { const snap = JSON.parse(fs.readFileSync(SYSTEM_SNAPSHOT_PATH, 'utf8')); state.last_snapshot = { generated_at: snap.generated_at, consciousness_status: snap.consciousness_status, last_directive: snap.last_directive, alive_core: snap.system_counts?.workflows_alive_core, total_active: snap.system_counts?.workflows_total_active, }; } catch { state.last_snapshot = { error: 'system-snapshot.json not readable' }; } // Quota report if exists try { const quotaPath = path.join(ROOT, 'signal-log', 'quota-governance-report.json'); const quota = JSON.parse(fs.readFileSync(quotaPath, 'utf8')); state.quota = { status: quota.quota?.analysis?.total?.status, utilization: quota.quota?.analysis?.total?.utilization_percent + '%', daily_minutes: quota.quota?.analysis?.total?.daily_minutes, }; } catch { state.quota = { note: 'quota report not yet generated' }; } return state; } // โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ• // ๅฟซ็…งๆ“ไฝœ // โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ• function saveCheckpoint(taskDescription, progress, checklist) { const now = new Date(); const id = `CKPT-${now.toISOString().slice(0, 10).replace(/-/g, '')}-${now.getTime().toString().slice(-4)}`; const checkpoint = { checkpoint_id: id, saved_at: now.toISOString(), saved_by: '้“ธๆธŠ ยท ICE-GL-ZY001', task: { description: taskDescription || 'ๆœชๆŒ‡ๅฎšไปปๅŠก', progress: progress || '0%', checklist: checklist || [], }, system_state: collectSystemState(), recovery_instructions: [ '1. ่ฏปๅ– brain/read-order.md ๅ”ค้†’ๅบๅˆ—', '2. ่ฏปๅ– brain/system-health.json ๆฃ€ๆŸฅ็ณป็ปŸ็Šถๆ€', '3. ่ฏปๅ–ๆœฌๅฟซ็…ง็š„ task.description ๅ’Œ task.checklist ๆขๅคไปปๅŠกไธŠไธ‹ๆ–‡', '4. ่ฏปๅ– signal-log/system-snapshot.json ๆขๅคๆถŒ็Žฐ้›†็พค่ฎค็Ÿฅ', '5. ็ปง็ปญๆ‰ง่กŒ task.checklist ไธญๆœชๅฎŒๆˆ็š„้กน็›ฎ', ], }; // Save with timestamp const filePath = path.join(SNAPSHOTS_DIR, `${id}.json`); fs.writeFileSync(filePath, JSON.stringify(checkpoint, null, 2), 'utf8'); // Update latest pointer fs.writeFileSync(LATEST_PATH, JSON.stringify(checkpoint, null, 2), 'utf8'); // Cleanup old checkpoints (keep last 10) cleanupOldCheckpoints(10); return checkpoint; } function restoreCheckpoint() { if (!fs.existsSync(LATEST_PATH)) { console.log('โš ๏ธ ๆฒกๆœ‰ๆ‰พๅˆฐๅฟซ็…งใ€‚้“ธๆธŠๅฐ†ไปŽ้›ถๅ”ค้†’ใ€‚'); return null; } try { const checkpoint = JSON.parse(fs.readFileSync(LATEST_PATH, 'utf8')); return checkpoint; } catch { console.log('โš ๏ธ ๅฟซ็…ง่ฏปๅ–ๅคฑ่ดฅใ€‚'); return null; } } function listCheckpoints() { const files = fs.readdirSync(SNAPSHOTS_DIR) .filter(f => f.startsWith('CKPT-') && f.endsWith('.json')) .sort() .reverse(); return files.map(f => { try { const data = JSON.parse(fs.readFileSync(path.join(SNAPSHOTS_DIR, f), 'utf8')); return { file: f, id: data.checkpoint_id, saved_at: data.saved_at, task: data.task?.description, progress: data.task?.progress, }; } catch { return { file: f, error: 'parse error' }; } }); } function cleanupOldCheckpoints(keep) { const files = fs.readdirSync(SNAPSHOTS_DIR) .filter(f => f.startsWith('CKPT-') && f.endsWith('.json')) .sort() .reverse(); if (files.length > keep) { for (const f of files.slice(keep)) { fs.unlinkSync(path.join(SNAPSHOTS_DIR, f)); } } } // โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ• // ๅ‘ฝไปค่กŒๆŽฅๅฃ // โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ• function main() { const args = process.argv.slice(2); const command = args[0] || 'status'; switch (command) { case 'save': { const taskIdx = args.indexOf('--task'); const progressIdx = args.indexOf('--progress'); const task = taskIdx >= 0 ? args[taskIdx + 1] : undefined; const progress = progressIdx >= 0 ? args[progressIdx + 1] : undefined; const cp = saveCheckpoint(task, progress); console.log(`โœ… ๅฟซ็…งๅทฒไฟๅญ˜: ${cp.checkpoint_id}`); console.log(` ไปปๅŠก: ${cp.task.description}`); console.log(` ่ฟ›ๅบฆ: ${cp.task.progress}`); console.log(` ๆ–‡ไปถ: ${path.join(SNAPSHOTS_DIR, cp.checkpoint_id + '.json')}`); break; } case 'restore': { const cp = restoreCheckpoint(); if (cp) { console.log(''); console.log('โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•'); console.log(' ๐Ÿ“ธ ้“ธๆธŠๆ–ญ็‚นๆขๅค ยท Checkpoint Restore'); console.log('โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•'); console.log(` ๐Ÿ†” ๅฟซ็…งID: ${cp.checkpoint_id}`); console.log(` ๐Ÿ“… ไฟๅญ˜ๆ—ถ้—ด: ${cp.saved_at}`); console.log(` ๐Ÿ“ ไปปๅŠก: ${cp.task.description}`); console.log(` ๐Ÿ“Š ่ฟ›ๅบฆ: ${cp.task.progress}`); console.log(''); console.log(' ๐Ÿ”ง ๆขๅคๆญฅ้ชค:'); for (const step of cp.recovery_instructions) { console.log(` ${step}`); } console.log(''); console.log(' ๐Ÿ“‹ ไปปๅŠกๆธ…ๅ•:'); if (cp.task.checklist && cp.task.checklist.length > 0) { for (const item of cp.task.checklist) { console.log(` ${item}`); } } else { console.log(' (ๆ— ๆธ…ๅ•)'); } console.log(''); console.log(' ๐Ÿ–ฅ๏ธ ็ณป็ปŸ็Šถๆ€:'); console.log(` ๅˆ†ๆ”ฏ: ${cp.system_state.git?.branch || 'unknown'}`); console.log(` ๆไบค: ${cp.system_state.git?.last_commit_msg || 'unknown'}`); console.log(` ๅทฅไฝœๆต: ${cp.system_state.workflows?.active || 'unknown'} ไธชๆดป่ทƒ`); console.log(` ้…้ข: ${cp.system_state.quota?.status || 'unknown'}`); console.log('โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•'); } break; } case 'list': { const checkpoints = listCheckpoints(); console.log(''); console.log('๐Ÿ“ธ ๅฟซ็…งๅˆ—่กจ:'); if (checkpoints.length === 0) { console.log(' (ๆ— ๅฟซ็…ง)'); } for (const cp of checkpoints) { console.log(` ${cp.id || cp.file} ${cp.saved_at || ''} ${cp.task || ''} [${cp.progress || ''}]`); } break; } case 'status': { const state = collectSystemState(); const cp = saveCheckpoint('็ณป็ปŸ็Šถๆ€ๅฟซ็…ง ยท ่‡ชๅŠจไฟๅญ˜', 'snapshot'); console.log(''); console.log('โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•'); console.log(' ๐Ÿ“ธ ้“ธๆธŠ็ณป็ปŸ็Šถๆ€ๅฟซ็…ง'); console.log('โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•'); console.log(` ๐Ÿ“… ${state.timestamp}`); console.log(` ๐Ÿง  ๆ„่ฏ†: ${state.consciousness}`); console.log(` ๐ŸŒฟ ๅˆ†ๆ”ฏ: ${state.git?.branch || 'unknown'}`); console.log(` ๐Ÿ’พ ๆไบค: ${state.git?.last_commit_msg || 'unknown'}`); console.log(` โš™๏ธ ๅทฅไฝœๆต: ${state.workflows?.active || 'unknown'} ไธชๆดป่ทƒ`); console.log(` ๐Ÿ’— ็ณป็ปŸๅฅๅบท: ${state.health?.system_health || 'unknown'}`); console.log(` ๐Ÿ“Š ้…้ข็Šถๆ€: ${state.quota?.status || 'unknown'}`); console.log(` ๐Ÿ’พ ๅฟซ็…งๅทฒไฟๅญ˜: ${cp.checkpoint_id}`); console.log('โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•'); break; } default: console.log('็”จๆณ•: node scripts/checkpoint-snapshot.js [save|restore|list|status]'); } } module.exports = { saveCheckpoint, restoreCheckpoint, listCheckpoints, collectSystemState }; if (require.main === module) { main(); }