Merge remote-tracking branch 'origin/master' into session-surface

Reconciles the session-surface work (surfaceOp/sourceEventSeqs provenance as
the sole derivation path) with master's worktree-subagent series (fork-seed
boundary + out-of-process subagent backends).

Semantic reconciliations beyond the textual auto-merge:
- SQLite SCHEMA_VERSION: both sides bumped 2->3. Merged to a single v3 carrying
  BOTH column families — master's seed_length on `sessions` and surface's
  source_event_seqs/surface_op on `events`. writeRow + both INSERT sites bind
  the full set; the schema doc lists all three added columns as the v2->v3 gap.
- agent-loop runStep request: master's `sessionId: session.id` and surface's
  per-append surfaceOp/sourceEventSeqs coexist (different regions).
- Fork seed + surface: a fork seeds the child from the parent's LIVE events,
  which now carry surfaceOp, so the child's surface rebuilds correctly. Verified
  end-to-end — the subagent-fork replay recalls the inherited "SAFFRON" codeword
  through the seeded prefix.
- Subagent snapshot fixtures (recorded pre-surface) re-enriched via KEYLESS
  deterministic replay: only surfaceOp/sourceEventSeqs added onto existing
  recorded lines (matched by seq), no recorded value changed. Not re-recorded
  against the live API.

Gates: typecheck, test (1112), test:snapshot (14), doc-sync, lint, build,
hygiene all green.
This commit is contained in:
Hypatia May
2026-06-24 10:48:01 +08:00
203 changed files with 8630 additions and 484 deletions

View File

@@ -5,17 +5,19 @@
"private": true,
"type": "module",
"main": "lib/index.js",
"types": "lib/index.d.ts",
"types": "lib/types/index.d.ts",
"exports": {
".": {
"types": "./lib/index.d.ts",
"types": "./lib/types/index.d.ts",
"default": "./lib/index.js"
},
"./src/*": "./src/*",
"./package.json": "./package.json"
},
"files": [
"lib",
"lib/index.js",
"lib/types/**/*.d.ts",
"lib/types/**/*.d.ts.map",
"src"
],
"license": "BSD-3-Clause",

View File

@@ -241,19 +241,21 @@ export class SessionPersistenceSqlite extends SessionPersistence implements Pers
*/
private writeRow(meta: SessionHeader): void {
this.db.prepare(`
INSERT INTO sessions (id, version, created_at, cwd, parent_session)
VALUES (?, ?, ?, ?, ?)
INSERT INTO sessions (id, version, created_at, cwd, parent_session, seed_length)
VALUES (?, ?, ?, ?, ?, ?)
ON CONFLICT(id) DO UPDATE SET
version = excluded.version,
created_at = excluded.created_at,
cwd = excluded.cwd,
parent_session = excluded.parent_session
parent_session = excluded.parent_session,
seed_length = excluded.seed_length
`).run(
meta.id,
meta.version,
meta.createdAt,
meta.cwd ?? null,
meta.parentSession ?? null,
meta.seedLength ?? null,
)
}
}

View File

@@ -30,6 +30,7 @@ export interface SessionRow {
created_at: number
cwd: string | null
parent_session: string | null
seed_length: number | null
}
/** An `events` table row: one `SessionEvent` mapped 1:1 (`data` is JSON text). */
@@ -55,8 +56,9 @@ export interface EventRow {
* current {@link SCHEMA_VERSION}; an existing database whose version is NOT the
* current one (written by a different, incompatible build — older or newer) is
* REJECTED rather than opened against a layout this build does not understand.
* There are no migrations: v1 had a different `sessions` layout and is not
* upgraded in place.
* There are no migrations: an earlier layout (v1's different `sessions` shape,
* v2 without the `seed_length`/`source_event_seqs`/`surface_op` columns) is not
* upgraded in place — it is rejected.
*/
export function openDatabase(path: string): DatabaseSync {
const db = new DatabaseSync(path)
@@ -80,7 +82,8 @@ export function openDatabase(path: string): DatabaseSync {
version INTEGER NOT NULL,
created_at INTEGER NOT NULL,
cwd TEXT,
parent_session TEXT
parent_session TEXT,
seed_length INTEGER
) STRICT
`)
db.exec(`
@@ -106,6 +109,7 @@ export function rowToMeta(row: SessionRow): SessionHeader {
createdAt: row.created_at,
...row.cwd !== null ? { cwd: row.cwd } : {},
...row.parent_session !== null ? { parentSession: row.parent_session as SessionId } : {},
...row.seed_length !== null ? { seedLength: row.seed_length } : {},
}
}

View File

@@ -2,7 +2,7 @@
"extends": "../../../tsconfig.base.json",
"compilerOptions": {
"rootDir": "src",
"outDir": "lib"
"outDir": "lib/types"
},
"include": [
"src"