#!/usr/bin/env node // SessionStart:清理死鎖、續租,並把 PERSONA_SESSION 與人格清單注入上下文。 // // session_id 只有 hook 拿得到,所以這裡把它注入上下文;後續 skill 呼叫 CLI 時 // 必須帶 `--session <這個值>`,guard hook 會驗證,程序無法冒用別人的身分。 // // 人格「由使用者呼叫才載入」:這裡只列出可用人格,不自動載入沒綁過的人格。 import { readEvent, respond } from "./_hook.mjs"; import * as pl from "../scripts/persona-lib.mjs"; const event = readEvent(); if (!event) process.exit(0); const sessionId = event.session_id || "unknown"; const source = event.source || "startup"; const cwd = event.cwd || null; pl.gcRuntime(); const data = pl.loadSession(sessionId); const host = data.host; const lines = [ "", `PERSONA_SESSION=${sessionId}`, `人格倉庫:${pl.personaHome()}`, "規則:", ` 1. 呼叫 persona.mjs 一律帶 \`--session ${sessionId}\`(值不符會被 hook 拒絕)。`, " 2. 人格**只有使用者叫你載入時才載入**(/jsc-persona:persona-chat ),不要自己挑一個人格附身。", " 3. 一個程序只能載入一個人格;要與別的人格對話請用 /jsc-persona:persona-invite。", " 4. 禁止直接讀寫非當前人格的目錄,hook 會擋下(跨人格資料隔離)。", ]; if (host && pl.personaExists(host)) { // resume / compact / clear:把鎖續租回來,並帶回人格狀態 try { pl.acquireLock(host, sessionId, { cwd }); lines.push(`已接續人格 \`${host}\`(session 恢復:${source})。`); lines.push(pl.turnContext(host, sessionId)); } catch (err) { lines.push(`⚠ 無法接續人格 \`${host}\`:${err.message}`); } } else { const personas = pl.listPersonas(); if (personas.length) { lines.push("尚未載入人格。可用人格(等使用者指定):"); for (const slug of personas) { const status = pl.lockStatus(slug); lines.push(` - ${status.locked ? "🔒" : status.stale ? "⚠" : "🔓"} \`${slug}\` ${pl.identityBrief(slug)}`); } lines.push("載入方式:/jsc-persona:persona-chat "); } else { lines.push("尚無任何人格。可用 /jsc-persona:persona-create 或 /jsc-persona:persona-anime(動漫作品+角色名)建立。"); } } lines.push(""); respond({ hookSpecificOutput: { hookEventName: "SessionStart", additionalContext: lines.join("\n"), }, suppressOutput: true, });