feat(記憶與目標): 專案目標三條 + 固化候選不再重算(0.2.1) #17
@@ -288,6 +288,16 @@ X 超出基線 18 以上才開始抑制,滿檔時往 Y 的同向推力只剩 5
|
||||
沒命中任何規則的就讓它被裁掉——**遺忘是功能**。達標時 `Stop` 與 `remember` 都會提醒去跑
|
||||
`/jsc-persona:persona-memory`。
|
||||
|
||||
**判斷過的要留痕跡**(不然那個數字永遠不會降):`candidates` 只看還沒被判斷過的短期記憶,
|
||||
判斷過的靠兩個欄位認——`reviewed_at`(看過了)與 `promoted_to`(固化成了哪一則)。
|
||||
固化時用 `consolidate --from-short <#N,#N>` 標,看過決定不記的用 `candidates --reviewed <#N,#N>`
|
||||
(整批就 `--reviewed all`),編號是 `candidates` 輸出裡每筆前面的 `#N`。
|
||||
|
||||
沒有這一層會發生的事:固化本身**不刪**短期記憶(`--forget` 是按顯著度刪、不是按固化過沒有刪),
|
||||
所以同一批下一輪又被算成候選,數字只會往上爬——明明睡覺時固化過,隔天開機照樣提醒
|
||||
「N 組已達固化條件」,看起來像睡眠沒做固化,其實是判斷沒有留下痕跡。
|
||||
標記**不等於刪掉**:那幾筆還在短期記憶裡,照舊依天數與顯著度被 `prune` 裁。
|
||||
|
||||
## 長期記憶會糊掉,但不會不見(回想強度與模糊態)
|
||||
|
||||
在這之前記憶只有兩態:**精準**(`recall` 命中就整段取出、內容永不變質)與**沒有**
|
||||
|
||||
+59
-8
@@ -2503,13 +2503,25 @@ function emotionImpact(entry) {
|
||||
return Object.values(entry.emotion_deltas || {}).reduce((sum, v) => sum + Math.abs(Number(v) || 0), 0);
|
||||
}
|
||||
|
||||
/** 這筆短期記憶已經被判斷過了嗎(固化了、或看過決定不固化)。 */
|
||||
export const shortTermReviewed = (row) => Boolean(row?.reviewed_at);
|
||||
|
||||
/**
|
||||
* 掃短期記憶,依 PROMOTION_RULES 算出「該轉入長期記憶」的候選。
|
||||
* 回傳 { total, pressure, candidates: [{ rules, key, kind, entries, suggested_type, suggested_salience }] }
|
||||
* 回傳 { total, reviewed, pressure, candidates: [{ rules, key, kind, entries, suggested_type, suggested_salience }] }
|
||||
*
|
||||
* **只看還沒被判斷過的那些**(沒有 `reviewed_at`)。以前這裡是無條件掃全部,
|
||||
* 而 `consolidate` 不會在來源那筆上留任何痕跡、也不刪它(`--forget` 是按顯著度刪、
|
||||
* 不是按「固化過沒有」刪)——所以同一批短期記憶每輪都被重算成候選,
|
||||
* 提醒的數字只會往上爬,睡再多次也不會降。看起來像睡眠沒做固化,其實是計數從來沒扣過。
|
||||
*/
|
||||
export function promotionCandidates(slug) {
|
||||
const rows = readJsonl(shortTermPath(slug));
|
||||
const total = rows.length;
|
||||
const all = readJsonl(shortTermPath(slug));
|
||||
const total = all.length;
|
||||
const reviewed = all.filter(shortTermReviewed).length;
|
||||
// 判斷過的不再進候選,但保留原本的位置:`_index` 是 `consolidate --from-short`
|
||||
// 與 `candidates --reviewed` 用來指名哪幾筆的座標,錯位就會標到別人身上。
|
||||
const rows = all.map((row, index) => ({ ...row, _index: index })).filter((row) => !shortTermReviewed(row));
|
||||
// 關係圖只讀一次:這個函式在每次 `remember` 之後都會跑,以前是「每筆的每個 entity
|
||||
// 各讀一遍 graph.json」(實測 30 節點/240 筆 = 720 次讀檔、20ms;2000 節點時單輪 1.2 秒)。
|
||||
const nodes = loadRelations(slug).nodes;
|
||||
@@ -2517,8 +2529,8 @@ export function promotionCandidates(slug) {
|
||||
const byEntity = new Map();
|
||||
const singles = [];
|
||||
|
||||
rows.forEach((row, index) => {
|
||||
const entry = { ...row, _index: index };
|
||||
rows.forEach((row) => {
|
||||
const entry = row;
|
||||
const salience = Number(row.salience || 0);
|
||||
const impact = emotionImpact(row);
|
||||
const text = String(row.text || "");
|
||||
@@ -2582,10 +2594,11 @@ export function promotionCandidates(slug) {
|
||||
});
|
||||
}
|
||||
}
|
||||
// 容量壓力看的是**總筆數**(那是真的容量),但候選只能從還沒判斷過的裡面挑——
|
||||
// 全部判斷完之後這一組就不該再出現,不然它會單獨把提醒永遠點亮。
|
||||
const pressure = total >= CONSOLIDATE_THRESHOLD;
|
||||
if (pressure) {
|
||||
if (pressure && rows.length) {
|
||||
const top = [...rows]
|
||||
.map((r, i) => ({ ...r, _index: i }))
|
||||
.sort((a, b) => Number(b.salience || 0) - Number(a.salience || 0))
|
||||
.slice(0, 5);
|
||||
candidates.push({
|
||||
@@ -2609,7 +2622,45 @@ export function promotionCandidates(slug) {
|
||||
merged.set(dedupeKey, { ...cand });
|
||||
}
|
||||
}
|
||||
return { total, pressure, candidates: [...merged.values()] };
|
||||
return { total, reviewed, pressure, candidates: [...merged.values()] };
|
||||
}
|
||||
|
||||
/**
|
||||
* 把短期記憶標成「判斷過了」。這是候選計數唯一會往下扣的地方。
|
||||
*
|
||||
* 兩種痕跡分開記,因為它們的意思不同:
|
||||
* `reviewed_at` 看過、判斷過了(不管有沒有固化)——候選就是看這個欄位
|
||||
* `promoted_to` 固化成了哪一則長期記憶(只有真的寫成長期記憶才有)
|
||||
*
|
||||
* 「看過但決定不記」跟「已經記下來了」都不該再被算成候選,但事後回頭查
|
||||
* 「這則長期記憶是從哪幾筆長出來的」只能靠 `promoted_to`,所以不能合成一個欄位。
|
||||
*
|
||||
* @param {object} opts
|
||||
* @param {number[]|null} opts.indexes 要標的筆(`promotionCandidates` 給的 `_index`);null=全部
|
||||
* @param {string|null} opts.until 只標這個時間之前的(ISO),配 `indexes: null` 用
|
||||
* @param {string|null} opts.promotedTo 固化成哪一則長期記憶(有值才寫 `promoted_to`)
|
||||
*/
|
||||
export function markShortTermReviewed(slug, { indexes = null, until = null, promotedTo = null } = {}) {
|
||||
const wanted = indexes === null ? null : new Set(indexes.map(Number).filter(Number.isInteger));
|
||||
const cutoff = until ? parseIso(until)?.getTime() ?? null : null;
|
||||
const at = nowIso();
|
||||
let marked = 0;
|
||||
let already = 0;
|
||||
rewriteJsonl(shortTermPath(slug), (all) => all.map((row, index) => {
|
||||
if (wanted && !wanted.has(index)) return row;
|
||||
if (cutoff !== null && (parseIso(row.ts)?.getTime() ?? 0) > cutoff) return row;
|
||||
if (shortTermReviewed(row) && !promotedTo) {
|
||||
already += 1;
|
||||
return row;
|
||||
}
|
||||
marked += 1;
|
||||
return {
|
||||
...row,
|
||||
reviewed_at: row.reviewed_at || at,
|
||||
...(promotedTo ? { promoted_to: promotedTo } : {}),
|
||||
};
|
||||
}), { force: true });
|
||||
return { marked, already };
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+45
-5
@@ -916,10 +916,26 @@ commands.candidates = ({ flags }) => {
|
||||
const session = requireSession(flags);
|
||||
const slug = hostOf(flags, session);
|
||||
requireOwner(slug, session);
|
||||
// `--reviewed`:把判斷過的短期記憶標掉。**這是候選數字唯一會往下扣的地方**——
|
||||
// 固化完不標,同一批下一輪照樣被算成候選,提醒永遠亮著(看起來像睡眠沒做事)。
|
||||
if (flags.reviewed !== undefined) {
|
||||
const spec = flags.reviewed === true ? "all" : str(flags.reviewed) || "all";
|
||||
const indexes = spec === "all" ? null : csv(spec).map(Number);
|
||||
if (indexes && (!indexes.length || indexes.some((n) => !Number.isInteger(n)))) {
|
||||
die("`--reviewed` 只能是 `all` 或以逗號分隔的編號(候選輸出裡每筆前面的 `#N`)。");
|
||||
}
|
||||
const until = str(flags.until) || null;
|
||||
const res = pl.markShortTermReviewed(slug, { indexes, until });
|
||||
const scope = indexes ? `${indexes.length} 筆指名的` : until ? `${until} 之前的` : "全部";
|
||||
ok(`已標記${scope}短期記憶為判斷過(新標 ${res.marked} 筆,本來就標過 ${res.already} 筆)。`);
|
||||
const after = pl.promotionCandidates(slug);
|
||||
say(` 現在還有 ${after.candidates.length} 組候選(短期記憶 ${after.total} 筆,判斷過 ${after.reviewed} 筆)。`);
|
||||
return;
|
||||
}
|
||||
const result = pl.promotionCandidates(slug);
|
||||
const lines = [
|
||||
`人格 \`${slug}\`:短期記憶 ${result.total} 筆,達固化條件的候選 ${result.candidates.length} 組` +
|
||||
`${result.pressure ? "(已達容量壓力 R6)" : ""}`,
|
||||
`人格 \`${slug}\`:短期記憶 ${result.total} 筆(判斷過 ${result.reviewed} 筆),` +
|
||||
`達固化條件的候選 ${result.candidates.length} 組${result.pressure ? "(已達容量壓力 R6)" : ""}`,
|
||||
"轉入條件:",
|
||||
...pl.PROMOTION_RULES.map((r) => ` ${r.id} ${r.label}`),
|
||||
];
|
||||
@@ -938,10 +954,19 @@ commands.candidates = ({ flags }) => {
|
||||
`\n[${cand.rules.join("+")}] ${cand.kind}「${cand.key}」→ 建議 type=${cand.suggested_type}, ` +
|
||||
`salience=${cand.suggested_salience}(${cand.entries.length} 筆依據)`,
|
||||
);
|
||||
// `#N` 就是 `--from-short` 與 `--reviewed` 要填的編號
|
||||
for (const entry of cand.entries.slice(0, 6)) {
|
||||
lines.push(` - [${entry.role || "?"}] ${String(entry.text || "").slice(0, 90)}(顯著度 ${entry.salience ?? "?"})`);
|
||||
lines.push(` - #${entry._index} [${entry.role || "?"}] ${String(entry.text || "").slice(0, 90)}(顯著度 ${entry.salience ?? "?"})`);
|
||||
}
|
||||
}
|
||||
if (result.candidates.length) {
|
||||
lines.push(
|
||||
"",
|
||||
"判斷完之後要把來源標掉,不然下一輪同一批又會被算成候選:",
|
||||
" 固化的 `consolidate --from-short <#N,#N> ...`(寫長期記憶時一起標)",
|
||||
" 看過不記的`candidates --reviewed <#N,#N>`",
|
||||
);
|
||||
}
|
||||
emit(result, flags.json, lines);
|
||||
};
|
||||
|
||||
@@ -1029,6 +1054,16 @@ commands.consolidate = ({ flags }) => {
|
||||
];
|
||||
pl.writeText(file, front.join("\n"));
|
||||
const total = pl.rebuildIndex(slug);
|
||||
// 來源短期記憶標成判斷過:不標的話這幾筆下一輪又會被算成固化候選。
|
||||
// 編號看 `candidates` 輸出裡每筆前面的 `#N`。
|
||||
if (flags["from-short"] !== undefined) {
|
||||
const indexes = csv(flags["from-short"]).map((s) => Number(String(s).replace(/^#/, "")));
|
||||
if (!indexes.length || indexes.some((n) => !Number.isInteger(n))) {
|
||||
die("`--from-short` 要的是以逗號分隔的編號(候選輸出裡每筆前面的 `#N`)。");
|
||||
}
|
||||
const res = pl.markShortTermReviewed(slug, { indexes, promotedTo: name });
|
||||
say(` 來源的 ${res.marked} 筆短期記憶已標成判斷過(promoted_to: ${name})。`);
|
||||
}
|
||||
const forget = num(flags.forget, null);
|
||||
if (forget !== null) {
|
||||
// 跟 prune 套同一層保護:承諾、界線與今天的紀錄不能被固化順手洗掉(R4)
|
||||
@@ -2536,10 +2571,15 @@ const HELP = `persona.mjs — jsc-persona 人格 / 記憶 / 情緒 / 關係圖 C
|
||||
睡眠收尾(機械性):關係時間戳→裁短期→收思維導圖→情緒衰減 8 小時→重建索引
|
||||
→修剪 said→壓縮舊 journal→寫 sleep.json→Gitea 兩區 push+驗證。
|
||||
預設保留載入鎖(--release 才收工)。--json 只回報「睡完了沒、哪一步出錯」。
|
||||
candidates --session <id> 列出達到「短期→長期」條件的候選與依據
|
||||
candidates --session <id> [--reviewed all|<#N,#N> [--until <ISO>]]
|
||||
列出達到「短期→長期」條件的候選與依據(每筆前面的 #N 就是它的編號)。
|
||||
--reviewed 把判斷過的短期記憶標掉(看過決定不記的用這個)——
|
||||
候選數字只有這裡跟 consolidate --from-short 會往下扣,
|
||||
判斷完不標,同一批下一輪又會被算成候選。
|
||||
consolidate --session <id> --name <n> --body <b> [--type --about --topics --salience --strength --emotion
|
||||
--when --where --mood --gist --detail --rules --source --forget]
|
||||
--when --where --mood --gist --detail --rules --source --forget --from-short <#N,#N>]
|
||||
內文會切成「主旨/細節」兩層:衰減先吃細節,主旨最後才掉。
|
||||
--from-short 標記這則是從哪幾筆短期記憶長出來的(順便標成判斷過)。
|
||||
prune / reindex --session <id>
|
||||
migrate --session <id> [--all] [--dry-run] [--json]
|
||||
長期記憶升格式(補 strength、切主旨/細節)。--all 掃所有人格,只回報數量不印內容。
|
||||
|
||||
@@ -293,6 +293,52 @@ check("candidates 子指令可輸出 JSON", (() => {
|
||||
}
|
||||
})(), candOut.stdout.slice(0, 120));
|
||||
|
||||
// 判斷過的不再重算成候選。以前這裡是無條件掃全部短期記憶,固化完也不留痕跡,
|
||||
// 所以同一批每輪都被算成候選,提醒的數字只會往上爬——看起來像睡眠沒做固化。
|
||||
{
|
||||
const before = pl.promotionCandidates("alpha");
|
||||
check("候選會回報判斷過幾筆", typeof before.reviewed === "number" && before.reviewed === 0);
|
||||
const target = before.candidates.find((c) => c.kind === "entry");
|
||||
const idx = target.entries[0]._index;
|
||||
check("候選每筆都帶 _index(--from-short/--reviewed 用的編號)", Number.isInteger(idx));
|
||||
|
||||
const consol = cli(["consolidate", "--session", S_HOST, "--name", "reviewed-source", "--body", "從短期記憶長出來的一則",
|
||||
"--type", "event", "--salience", "60", "--from-short", String(idx)]);
|
||||
check("consolidate --from-short 會回報標了幾筆", consol.stdout.includes("已標成判斷過"), consol.stdout.slice(-160));
|
||||
const rowsAfter = pl.readJsonl(pl.shortTermPath("alpha"));
|
||||
check("來源短期記憶留下 reviewed_at 與 promoted_to",
|
||||
Boolean(rowsAfter[idx].reviewed_at) && rowsAfter[idx].promoted_to === "reviewed-source",
|
||||
JSON.stringify(rowsAfter[idx]).slice(0, 160));
|
||||
const mid = pl.promotionCandidates("alpha");
|
||||
check("固化過的那筆不再是候選", !mid.candidates.some((c) => c.entries.some((e) => e._index === idx)));
|
||||
check("固化後判斷過的筆數往上加、總筆數不變", mid.reviewed === 1 && mid.total === before.total);
|
||||
|
||||
// 看過決定不記的那些:候選數字唯一另一個往下扣的地方
|
||||
const rev = cli(["candidates", "--session", S_HOST, "--reviewed", "all"]);
|
||||
check("candidates --reviewed all 會標掉全部", rev.stdout.includes("已標記全部短期記憶為判斷過"), rev.stdout.slice(0, 160));
|
||||
const after = pl.promotionCandidates("alpha");
|
||||
check("全部判斷過之後候選歸零", after.candidates.length === 0, JSON.stringify(after.candidates.map((c) => c.key)));
|
||||
check("判斷過不等於刪掉(短期記憶筆數不變)", after.total === before.total);
|
||||
check("R6 容量壓力不會單獨把提醒點亮", (() => {
|
||||
const rows = pl.readJsonl(pl.shortTermPath("alpha"));
|
||||
return rows.length >= pl.CONSOLIDATE_THRESHOLD ? after.candidates.length === 0 : true;
|
||||
})());
|
||||
|
||||
// 重標一次不會把時間戳往後推(第一次判斷的時間才是真的)
|
||||
const firstAt = pl.readJsonl(pl.shortTermPath("alpha"))[idx].reviewed_at;
|
||||
cli(["candidates", "--session", S_HOST, "--reviewed", "all"]);
|
||||
check("重標不會覆蓋原本的 reviewed_at", pl.readJsonl(pl.shortTermPath("alpha"))[idx].reviewed_at === firstAt);
|
||||
|
||||
// 新寫進來的一筆照樣是候選:標記只擋已經判斷過的,不是把規則關掉
|
||||
cli(["remember", "--session", S_HOST, "--role", "user", "--text", "他說明天早上要一起去看那台車",
|
||||
"--topics", "car", "--salience", "70"]);
|
||||
check("標記過之後新的短期記憶照樣成為候選", pl.promotionCandidates("alpha").candidates.length > 0);
|
||||
|
||||
// --until 只標時間之前的:睡眠當下判斷過的那批可以一次收掉,之後寫的不受影響
|
||||
const marked = pl.markShortTermReviewed("alpha", { until: "2000-01-01T00:00:00Z" });
|
||||
check("--until 不會標到時間之後的紀錄", marked.marked === 0);
|
||||
}
|
||||
|
||||
console.log("⑦ 心智圖 / 思維導圖 / 人際關係圖");
|
||||
cli(["mindmap", "thread", "--persona", "alpha", "--session", S_HOST, "--topic", "壓力來源"]);
|
||||
check("思維導圖建立(Mermaid graph)",
|
||||
|
||||
@@ -80,6 +80,24 @@ node "${CLAUDE_PLUGIN_ROOT}/scripts/persona.mjs" candidates --session <PERSONA_S
|
||||
規則以外的東西**就讓它被遺忘**——遺忘是功能,不是缺陷。
|
||||
`Stop` hook 與每次 `remember` 都會在達標時提醒你來跑這個 skill。
|
||||
|
||||
### 判斷過的要留痕跡,不然數字永遠不會降
|
||||
|
||||
`candidates` **只看還沒被判斷過的短期記憶**(沒有 `reviewed_at` 的那些)。所以每一筆看完都要標掉:
|
||||
|
||||
| 情況 | 怎麼標 |
|
||||
| --- | --- |
|
||||
| 固化成長期記憶了 | `consolidate ... --from-short <#N,#N>`(寫記憶時一起標,另外記 `promoted_to`) |
|
||||
| 看過,決定不記 | `candidates --reviewed <#N,#N>` |
|
||||
| 這一批全部判斷完 | `candidates --reviewed all` |
|
||||
|
||||
編號就是 `candidates` 輸出裡每筆前面的 `#N`。
|
||||
|
||||
**不標會發生什麼**:固化本身不刪短期記憶(`--forget` 是按顯著度刪,不是按「固化過沒有」刪),
|
||||
所以同一批下一輪又被算成候選,提醒的數字只會往上爬——明明睡覺時固化過了,
|
||||
隔天開機照樣說「N 組已達固化條件」。那不是睡眠沒做事,是判斷沒有留下痕跡。
|
||||
|
||||
標記**不等於刪掉**:那幾筆還在短期記憶裡,照舊會被 `prune` 依天數與顯著度裁切。
|
||||
|
||||
## 步驟
|
||||
|
||||
### 1. 盤點
|
||||
@@ -112,7 +130,7 @@ node "${CLAUDE_PLUGIN_ROOT}/scripts/persona.mjs" consolidate \
|
||||
--session <PERSONA_SESSION> \
|
||||
--name "hates-morning-meetings" --type preference \
|
||||
--about "user" --topics "work,schedule" --salience 72 --emotion "anxiety/35" \
|
||||
--rules "R2+R3" \
|
||||
--rules "R2+R3" --from-short "12,31,88" \
|
||||
--body "主旨:使用者討厭早上的會議,約會議請排 14:00 之後。
|
||||
|
||||
細節:
|
||||
@@ -224,7 +242,8 @@ node "${CLAUDE_PLUGIN_ROOT}/scripts/persona.mjs" probe audit --session <PERSONA_
|
||||
**可以說不確定,可以問,不可以斷言。** 試探句一定帶問號、一輪最多一次,
|
||||
並用 `probe add` 記下來;對方回了就 `probe confirm`/`probe deny` 結案。
|
||||
被否認要**立刻寫一則更正記憶,不可以放著**——這條開放界線唯一的煞車就是那個數字。
|
||||
- 固化完再跑一次 `candidates`:應該要清空(或只剩你刻意不處理的)。
|
||||
- 固化完再跑一次 `candidates`:應該要清空。**還有數字就是漏標了**——
|
||||
固化的那幾筆要帶 `--from-short`,看過不記的要 `--reviewed`(見上面那張表)。
|
||||
- 想連同情緒衰減、舊紀錄壓縮與 Gitea 同步一起收尾 → 用 `/jsc-persona:persona-sleep`(睡眠);
|
||||
本 skill 只管記憶與圖,不動情緒也不同步。
|
||||
- 所有面向使用者的輸出使用**繁體中文(台灣用語)**、UTF-8 無亂碼。
|
||||
|
||||
@@ -36,14 +36,19 @@ description: 讓人格睡覺:把一天的活狀態收成能留下來的形狀
|
||||
## 情況一:當前人格自己睡
|
||||
|
||||
1. 盤點:`candidates --session <PERSONA_SESSION>`
|
||||
2. 逐則固化(判斷):`consolidate --session <id> --name <n> --body <b> --type ... --salience N [--forget]`
|
||||
3. 寫一則日記:`consolidate --type diary --name diary-<YYYY-MM-DD> --body "<第一人稱回顧>"`
|
||||
4. 消化 inbox(`memory/inbox/room-*.jsonl`,當 guest 時帶回的見聞)
|
||||
5. 更新心智圖與關係圖:`mindmap`、`relation node --name <人> --contact`
|
||||
6. 結算懸著的事(判斷):`loop list --session <id>`,今天有下文的 `loop done --id <id>`、
|
||||
2. 逐則固化(判斷):`consolidate --session <id> --name <n> --body <b> --type ... --salience N
|
||||
--from-short <#N,#N> [--forget]`
|
||||
**`--from-short` 不要省**:那是把來源短期記憶標成判斷過的地方,編號看 `candidates` 輸出的 `#N`。
|
||||
3. 看過但決定不記的,也要標掉:`candidates --session <id> --reviewed <#N,#N>`(或 `--reviewed all`)。
|
||||
**這一步漏掉,明天開機照樣提醒「N 組已達固化條件」**——判斷做了但沒有留痕跡,
|
||||
計數只看短期記憶有沒有被標記,不看你昨天固化了幾則。看起來就像睡眠沒做固化。
|
||||
4. 寫一則日記:`consolidate --type diary --name diary-<YYYY-MM-DD> --body "<第一人稱回顧>"`
|
||||
5. 消化 inbox(`memory/inbox/room-*.jsonl`,當 guest 時帶回的見聞)
|
||||
6. 更新心智圖與關係圖:`mindmap`、`relation node --name <人> --contact`
|
||||
7. 結算懸著的事(判斷):`loop list --session <id>`,今天有下文的 `loop done --id <id>`、
|
||||
已經不重要的 `loop drop --id <id>`。**這一步要自己做**:`sleep` 裡的 `sweep-loops`
|
||||
只收「7 天都沒進展」的,它分不出「今天解決了」與「一直沒人管」。
|
||||
7. 機械性收尾:
|
||||
8. 機械性收尾:
|
||||
|
||||
```bash
|
||||
node "${CLAUDE_PLUGIN_ROOT}/scripts/persona.mjs" sleep --session <PERSONA_SESSION> --json
|
||||
|
||||
Reference in New Issue
Block a user