feat(role): 新增閒置小睡整理

This commit is contained in:
Jeffery
2026-07-28 14:39:26 +08:00
parent bb48a77dd4
commit 945c310551
4 changed files with 180 additions and 24 deletions
+48 -3
View File
@@ -4,7 +4,7 @@
// inbox(2) 產生 SessionStart 要注入的記憶區塊,(3) 睡眠整理時輸出待整理
// 素材並套用整理結果(NREM 鞏固/REM 整合、分類、去重、標籤、總結、
// 優先度、關聯、壓縮歸檔),(4) 依使用頻率與優先度遺忘日常與其他類記憶。
// 更新時間:2026/07/28 13:50:43
// 更新時間:2026/07/28 14:36:00
// 相依:Node.js 標準庫。
// 退出碼:0 成功;1 無內容可處理;2 參數錯誤。呼叫端(hook)一律不得因此中斷。
// ==============================================================================
@@ -537,7 +537,13 @@ function cmdLoad(args) {
if (digest) blocks.push(`> 上次睡眠摘要:${digest}`);
const pending = listInbox(args.role).length;
if (pending) blocks.push(`> 尚有 ${pending} 則未整理記憶,將於下次睡眠時段歸檔。`);
if (pending) {
if (pending >= args.batch) {
blocks.push(`> 尚有 ${pending} 則未整理記憶,已達一批睡眠整理量;請以角色語氣主動提醒使用者「想睡覺」或需要整理記憶。這是建議整理/歸檔的提醒,不代表停止協助。`);
} else {
blocks.push(`> 尚有 ${pending} 則未整理記憶,將於下次睡眠時段歸檔。`);
}
}
if (!blocks.length) return 1;
let text = blocks.join("\n\n");
@@ -776,6 +782,7 @@ function cmdStats(args) {
rows.push("");
rows.push(`- 記憶目錄:${memoryRoot(args.role)}`);
rows.push(`- 個人記憶同意狀態:${consentStatusValue(args.role)}`);
rows.push(`- 上次互動:${state.last_activity || "尚未記錄"}`);
rows.push(`- 上次睡眠整理:${state.last_sleep || "尚未整理"}`);
rows.push(`- 上次睡眠摘要:${state.last_sleep_digest || "尚無"}`);
rows.push(`- 上次遺忘:${state.last_forget || "尚未執行"}`);
@@ -790,6 +797,14 @@ function cmdMarkSleep(args) {
return 0;
}
function cmdMarkActivity(args) {
const patch = { last_activity: nowStamp(), last_activity_epoch: nowEpoch() };
if (args.project) patch.last_activity_project = args.project;
writeState(args.role, patch);
process.stdout.write("已更新上次互動時間");
return 0;
}
function cmdNeedSleep(args) {
if (!listInbox(args.role).length) {
process.stdout.write("no");
@@ -804,6 +819,30 @@ function cmdNeedSleep(args) {
return 0;
}
function cmdNeedNap(args) {
const pending = listInbox(args.role).length;
if (pending < args.minInbox) {
process.stdout.write("no");
return 0;
}
const state = readState(args.role);
const lastEpoch = Number.parseInt(state.last_activity_epoch || "", 10);
let lastMs = Number.isFinite(lastEpoch) && lastEpoch > 0 ? lastEpoch * 1000 : null;
if (lastMs === null) {
const last = parseStamp(state.last_activity);
lastMs = last ? last.getTime() : null;
}
if (lastMs === null) {
process.stdout.write("no");
return 0;
}
const idleMinutes = (Date.now() - lastMs) / 60000;
process.stdout.write(idleMinutes >= args.idleMinutes ? "yes" : "no");
return 0;
}
function cmdConsent(args) {
const value = String(args.value || "").trim().toLowerCase();
const normalized = {
@@ -892,7 +931,7 @@ function requireRole(args) {
function main(argv) {
const args = parseArgs(argv);
if (!args.command || args.command === "-h" || args.command === "--help") {
process.stdout.write(`用法:memory.js <子命令> [參數]\n\n子命令:write、seed、load、collect、apply、forget、stats、mark-sleep、need-sleep、consent、consent-status\n`);
process.stdout.write(`用法:memory.js <子命令> [參數]\n\n子命令:write、seed、load、collect、apply、forget、stats、mark-sleep、mark-activity、need-sleep、need-nap、consent、consent-status\n`);
return 0;
}
if (!requireRole(args)) return 2;
@@ -903,6 +942,8 @@ function main(argv) {
args.fullMinPriority = Number.parseInt(args.fullMinPriority || "", 10);
args.digestMinPriority = Number.parseInt(args.digestMinPriority || "", 10);
args.hours = Number.parseFloat(args.hours || "");
args.idleMinutes = Number.parseFloat(args.idleMinutes || "");
args.minInbox = Number.parseInt(args.minInbox || "", 10);
if (!Number.isFinite(args.limit)) args.limit = args.command === "load" ? envInt("ROLE_LOAD_LIMIT", DEFAULT_LOAD_LIMIT) : envInt("ROLE_SLEEP_COLLECT_LIMIT", COLLECT_LIMIT);
if (!Number.isFinite(args.batch)) args.batch = envInt("ROLE_SLEEP_BATCH", SLEEP_BATCH);
@@ -910,6 +951,8 @@ function main(argv) {
if (!Number.isFinite(args.fullMinPriority)) args.fullMinPriority = envInt("ROLE_LOAD_FULL_MIN_PRIORITY", DEFAULT_FULL_MIN_PRIORITY);
if (!Number.isFinite(args.digestMinPriority)) args.digestMinPriority = envInt("ROLE_LOAD_DIGEST_MIN_PRIORITY", DEFAULT_DIGEST_MIN_PRIORITY);
if (!Number.isFinite(args.hours)) args.hours = 20.0;
if (!Number.isFinite(args.idleMinutes)) args.idleMinutes = 45.0;
if (!Number.isFinite(args.minInbox)) args.minInbox = 3;
args.category ||= "important";
args.tags ||= "";
args.source ||= "";
@@ -929,7 +972,9 @@ function main(argv) {
forget: cmdForget,
stats: cmdStats,
"mark-sleep": cmdMarkSleep,
"mark-activity": cmdMarkActivity,
"need-sleep": cmdNeedSleep,
"need-nap": cmdNeedNap,
consent: cmdConsent,
"consent-status": cmdConsentStatus,
};