kongbrain 0.1.1 → 0.1.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/src/surreal.ts CHANGED
@@ -482,6 +482,30 @@ export class SurrealStore {
482
482
  }
483
483
  }
484
484
 
485
+ async markSessionActive(sessionId: string): Promise<void> {
486
+ assertRecordId(sessionId);
487
+ await this.queryExec(
488
+ `UPDATE ${sessionId} SET cleanup_completed = false, last_active = time::now()`,
489
+ );
490
+ }
491
+
492
+ async markSessionEnded(sessionId: string): Promise<void> {
493
+ assertRecordId(sessionId);
494
+ await this.queryExec(
495
+ `UPDATE ${sessionId} SET ended_at = time::now(), cleanup_completed = true`,
496
+ );
497
+ }
498
+
499
+ async getOrphanedSessions(limit = 3): Promise<{ id: string; started_at: string }[]> {
500
+ return this.queryFirst<{ id: string; started_at: string }>(
501
+ `SELECT id, started_at FROM session
502
+ WHERE cleanup_completed != true
503
+ AND started_at < time::now() - 2m
504
+ ORDER BY started_at DESC LIMIT $lim`,
505
+ { lim: limit },
506
+ );
507
+ }
508
+
485
509
  async linkSessionToTask(sessionId: string, taskId: string): Promise<void> {
486
510
  await this.queryExec(`RELATE ${sessionId}->session_task->${taskId}`);
487
511
  }
package/src/wakeup.ts CHANGED
@@ -13,6 +13,7 @@ import type { CompleteFn } from "./state.js";
13
13
  import type { SurrealStore } from "./surreal.js";
14
14
  import { hasSoul, getSoul, checkGraduation } from "./soul.js";
15
15
  import type { MaturityStage } from "./soul.js";
16
+ import { readAndDeleteHandoffFile } from "./handoff-file.js";
16
17
  import { swallow } from "./errors.js";
17
18
 
18
19
  // --- Types ---
@@ -63,6 +64,7 @@ export async function synthesizeWakeup(
63
64
  store: SurrealStore,
64
65
  complete: CompleteFn,
65
66
  currentSessionId?: string,
67
+ workspaceDir?: string,
66
68
  ): Promise<string | null> {
67
69
  if (!store.isAvailable()) return null;
68
70
 
@@ -75,7 +77,10 @@ export async function synthesizeWakeup(
75
77
  hasSoul(store),
76
78
  ]);
77
79
 
78
- if (!handoff && monologues.length === 0 && identityChunks.length === 0 && previousTurns.length === 0) return null;
80
+ // Check for sync handoff file (written on abrupt exit)
81
+ const handoffFile = workspaceDir ? readAndDeleteHandoffFile(workspaceDir) : null;
82
+
83
+ if (!handoff && !handoffFile && monologues.length === 0 && identityChunks.length === 0 && previousTurns.length === 0) return null;
79
84
 
80
85
  const sections: string[] = [];
81
86
 
@@ -98,6 +103,13 @@ export async function synthesizeWakeup(
98
103
  }
99
104
  annotation += ")";
100
105
  sections.push(`[LAST HANDOFF] ${annotation}\n${handoff.text}`);
106
+ } else if (handoffFile) {
107
+ // Fallback: sync handoff file from abrupt exit (no DB handoff note exists)
108
+ const lines: string[] = [];
109
+ lines.push(`Session ended abruptly (${handoffFile.userTurnCount} turns, ${handoffFile.unextractedTokens} unextracted tokens)`);
110
+ if (handoffFile.lastUserText) lines.push(`Last user message: ${handoffFile.lastUserText}`);
111
+ if (handoffFile.lastAssistantText) lines.push(`Last assistant message: ${handoffFile.lastAssistantText}`);
112
+ sections.push(`[LAST SESSION EXIT]\n${lines.join("\n")}`);
101
113
  }
102
114
 
103
115
  if (previousTurns.length > 0) {