ai-psychosis/hooks/scripts/session-end.mjs
Kjell Tore Guttormsen aca38d6558 feat(ultraplan-local): v1.6.0 — /ultraresearch-local deep research command
Add /ultraresearch-local for structured research combining local codebase
analysis with external knowledge via parallel agent swarms. Produces research
briefs with triangulation, confidence ratings, and source quality assessment.

New command: /ultraresearch-local with modes --quick, --local, --external, --fg.
New agents: research-orchestrator (opus), docs-researcher, community-researcher,
security-researcher, contrarian-researcher, gemini-bridge (all sonnet).
New template: research-brief-template.md.

Integration: --research flag in /ultraplan-local accepts pre-built research
briefs (up to 3), enriches the interview and exploration phases. Planning
orchestrator cross-references brief findings during synthesis.

Design principle: Context Engineering — right information to right agent at
right time. Research briefs are structured artifacts in the pipeline:
ultraresearch → brief → ultraplan --research → plan → ultraexecute.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-08 08:58:35 +02:00

67 lines
1.6 KiB
JavaScript

// Interaction Awareness — SessionEnd hook (Layer 2, Node.js)
// Finalizes session record, computes duration, cleans up state.
import { existsSync } from 'fs';
import {
readStdin, initConfig, requireLayer, getSessionId,
nowEpoch, nowIso,
STATE_DIR, SESSIONS_LOG,
readState, sessionStateFile, appendJsonl, removeFile
} from './lib.mjs';
readStdin();
initConfig();
requireLayer(2);
const sid = getSessionId();
if (!sid) process.exit(0);
const nowTs = nowEpoch();
const nowIsoStr = nowIso();
const sf = sessionStateFile();
if (!existsSync(sf)) {
appendJsonl(SESSIONS_LOG, {
session_id: sid,
end: nowIsoStr,
note: 'no_state_file'
});
process.exit(0);
}
// Read final state
const state = readState();
const startEpoch = Number(state.start_epoch) || 0;
const toolCount = Number(state.tool_count) || 0;
const editCount = Number(state.edit_count) || 0;
const depFlags = Number(state.dep_flags) || 0;
const escFlags = Number(state.esc_flags) || 0;
const fatFlags = Number(state.fatigue_flags) || 0;
const valFlags = Number(state.val_flags) || 0;
const startIso = state.start_iso || '';
// Compute duration
let durationMin = 0;
if (startEpoch > 0) {
durationMin = Math.floor((nowTs - startEpoch) / 60);
}
// Append finalized session record
appendJsonl(SESSIONS_LOG, {
session_id: sid,
start: startIso,
end: nowIsoStr,
duration_min: durationMin,
tool_count: toolCount,
edit_count: editCount,
flags: {
dependency: depFlags,
escalation: escFlags,
fatigue: fatFlags,
validation: valFlags
}
});
// Clean up state file
removeFile(sf);
process.exit(0);