@etiquekit/etq 1.0.13 → 1.0.15

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.
Files changed (143) hide show
  1. package/AGENTS.md +26 -19
  2. package/LICENSE +3 -2
  3. package/NOTICE +4 -6
  4. package/QuickStart.md +46 -35
  5. package/README.md +57 -55
  6. package/bin/etiquette +5 -1
  7. package/bin/etiquette-core +5 -1
  8. package/docs/ARCHITECTURE.md +17 -20
  9. package/docs/CONCEPTS.md +5 -5
  10. package/docs/CORE_PROFILE.md +15 -7
  11. package/docs/LANE_PROVISIONING.md +2 -7
  12. package/docs/README.md +14 -13
  13. package/docs/RELEASE_SURFACE_AUDIT.md +6 -7
  14. package/docs/SEAT_DISCIPLINE.md +91 -55
  15. package/docs/SEAT_PROVISIONING.md +19 -16
  16. package/docs/TEAM_HANDOFF.md +21 -21
  17. package/docs/WORKTREE_QOL.md +0 -7
  18. package/docs/contracts/ledger-entry/README.md +11 -11
  19. package/docs/contracts/ledger-entry/ledger-entry.v0.2.md +2 -2
  20. package/docs/contracts/ledger-entry/ledger-entry.v0.md +8 -8
  21. package/lib/etiquette-core.js +313 -0
  22. package/lib/etiquette.js +1151 -0
  23. package/package.json +13 -12
  24. package/templates/etiquette-vanilla-v0/README.md +3 -2
  25. package/templates/etiquette-vanilla-v0/source/control-seat/README.md +6 -0
  26. package/templates/etiquette-vanilla-v0/source/control-seat/bin/access-assurance-check +55 -0
  27. package/templates/etiquette-vanilla-v0/source/control-seat/bin/seat-doctor +5 -0
  28. package/templates/etiquette-vanilla-v0/source/control-seat/docs/work/access/ACCESS-ASSURANCE.md +39 -0
  29. package/templates/etiquette-vanilla-v0/source/control-seat/docs/work/access/workspace-secure-profile.v0.json +53 -0
  30. package/templates/etiquette-vanilla-v0/validate-vanilla.sh +5 -0
  31. package/templates/hosted-receiver/README.md +41 -0
  32. package/templates/hosted-receiver/w1-github-webhook-receiver.mjs +129 -0
  33. package/templates/seat-packs-v0/README.md +2 -3
  34. package/templates/seat-packs-v0/source/claude-code-seat/README.md +3 -3
  35. package/templates/seat-packs-v0/source/codex-seat/README.md +3 -3
  36. package/templates/seat-packs-v0/source/gemini-seat/README.md +3 -3
  37. package/templates/seat-packs-v0/source/ollama-seat/README.md +3 -3
  38. package/templates/seat-packs-v0/source/openrouter-seat/README.md +3 -3
  39. package/docs/CONCEPT_STATUS.md +0 -66
  40. package/packages/control/src/authority/lease.ts +0 -261
  41. package/packages/control/src/authority/node-delegation.ts +0 -257
  42. package/packages/control/src/authority/rig-conductor.ts +0 -632
  43. package/packages/control/src/cli/argv.ts +0 -155
  44. package/packages/control/src/cli/commands/console.ts +0 -200
  45. package/packages/control/src/cli/commands/dispatch-core.ts +0 -89
  46. package/packages/control/src/cli/commands/dispatch.ts +0 -279
  47. package/packages/control/src/cli/commands/harness.ts +0 -89
  48. package/packages/control/src/cli/commands/hook.ts +0 -50
  49. package/packages/control/src/cli/commands/ledger.ts +0 -91
  50. package/packages/control/src/cli/commands/local-workflow.ts +0 -4686
  51. package/packages/control/src/cli/commands/memory.ts +0 -445
  52. package/packages/control/src/cli/commands/release.ts +0 -108
  53. package/packages/control/src/cli/commands/rubric.ts +0 -103
  54. package/packages/control/src/cli/commands/seat.ts +0 -179
  55. package/packages/control/src/cli/commands/session.ts +0 -127
  56. package/packages/control/src/cli/commands/supervision.ts +0 -246
  57. package/packages/control/src/cli/commands/sync.ts +0 -119
  58. package/packages/control/src/cli/commands/workflow.ts +0 -86
  59. package/packages/control/src/cli/commands/workspace.ts +0 -50
  60. package/packages/control/src/cli/core-usage.ts +0 -34
  61. package/packages/control/src/cli/prompt.ts +0 -67
  62. package/packages/control/src/cli/supervision-deps.ts +0 -44
  63. package/packages/control/src/cli/usage.ts +0 -241
  64. package/packages/control/src/cli.ts +0 -207
  65. package/packages/control/src/core-cli.ts +0 -50
  66. package/packages/control/src/dispatch/decision.ts +0 -202
  67. package/packages/control/src/dispatch/projection.ts +0 -293
  68. package/packages/control/src/dispatch/record.ts +0 -153
  69. package/packages/control/src/engagement/project.ts +0 -170
  70. package/packages/control/src/fs.ts +0 -19
  71. package/packages/control/src/harness/pruning.ts +0 -406
  72. package/packages/control/src/hooks/dispatcher.ts +0 -117
  73. package/packages/control/src/hooks/outbox.ts +0 -86
  74. package/packages/control/src/hooks/sanitize.ts +0 -6
  75. package/packages/control/src/hooks/types.ts +0 -34
  76. package/packages/control/src/index.ts +0 -384
  77. package/packages/control/src/ledger/entry.ts +0 -303
  78. package/packages/control/src/ledger/indexer.ts +0 -542
  79. package/packages/control/src/memory/context.ts +0 -149
  80. package/packages/control/src/memory/drain-import.ts +0 -207
  81. package/packages/control/src/memory/indexer.ts +0 -284
  82. package/packages/control/src/memory/query.ts +0 -75
  83. package/packages/control/src/memory/sanitize.ts +0 -50
  84. package/packages/control/src/memory/sharded-drain-import.ts +0 -212
  85. package/packages/control/src/memory/status.ts +0 -211
  86. package/packages/control/src/memory/store-lifecycle.ts +0 -509
  87. package/packages/control/src/memory/store.ts +0 -284
  88. package/packages/control/src/memory/types.ts +0 -146
  89. package/packages/control/src/parity/surfaces.ts +0 -748
  90. package/packages/control/src/project.ts +0 -141
  91. package/packages/control/src/projection/local-ledger-view.ts +0 -373
  92. package/packages/control/src/projection/return-enforcement.ts +0 -48
  93. package/packages/control/src/projection/timeline-preview.ts +0 -539
  94. package/packages/control/src/projection/timeline.ts +0 -708
  95. package/packages/control/src/release/readiness.ts +0 -831
  96. package/packages/control/src/rubric/loader.ts +0 -326
  97. package/packages/control/src/rubric/promotion.ts +0 -54
  98. package/packages/control/src/rubric/runner.ts +0 -159
  99. package/packages/control/src/rubric/types.ts +0 -158
  100. package/packages/control/src/seat/owner-card.ts +0 -388
  101. package/packages/control/src/seat/readiness.ts +0 -834
  102. package/packages/control/src/session/runbook.ts +0 -431
  103. package/packages/control/src/shared/sanitize.ts +0 -49
  104. package/packages/control/src/supervision/action-classes.ts +0 -192
  105. package/packages/control/src/supervision/command-apply.ts +0 -378
  106. package/packages/control/src/supervision/errors.ts +0 -14
  107. package/packages/control/src/supervision/event-replay.ts +0 -155
  108. package/packages/control/src/supervision/events.ts +0 -109
  109. package/packages/control/src/supervision/index.ts +0 -16
  110. package/packages/control/src/supervision/manifest.ts +0 -127
  111. package/packages/control/src/supervision/paths.ts +0 -49
  112. package/packages/control/src/supervision/projection-adapter.ts +0 -274
  113. package/packages/control/src/supervision/projection.ts +0 -75
  114. package/packages/control/src/supervision/rebuild.ts +0 -99
  115. package/packages/control/src/supervision/session-open.ts +0 -131
  116. package/packages/control/src/supervision/session-read.ts +0 -99
  117. package/packages/control/src/supervision/sqlite-impl.ts +0 -71
  118. package/packages/control/src/supervision/sqlite.ts +0 -121
  119. package/packages/control/src/supervision/store-rows.ts +0 -371
  120. package/packages/control/src/supervision/turn-close.ts +0 -154
  121. package/packages/control/src/supervision/turn-open.ts +0 -284
  122. package/packages/control/src/sync/event-log-merge-driver.ts +0 -263
  123. package/packages/control/src/sync/join-plan.ts +0 -375
  124. package/packages/control/src/sync/outbox.ts +0 -492
  125. package/packages/control/src/workflow/evaluator.ts +0 -140
  126. package/packages/control/src/workflow/loader.ts +0 -200
  127. package/packages/control/src/workflow/types.ts +0 -90
  128. package/packages/control/src/workspace/authority.ts +0 -499
  129. package/packages/protocol/src/guards.ts +0 -119
  130. package/packages/protocol/src/huddle-board.ts +0 -198
  131. package/packages/protocol/src/huddle.ts +0 -295
  132. package/packages/protocol/src/incident.ts +0 -251
  133. package/packages/protocol/src/index.ts +0 -8
  134. package/packages/protocol/src/interfaces.ts +0 -107
  135. package/packages/protocol/src/packet-profile.ts +0 -195
  136. package/packages/protocol/src/state.ts +0 -81
  137. package/packages/protocol/src/types.ts +0 -434
  138. package/release/lineage.v0.json +0 -14
  139. package/scripts/release-candidate-verify.sh +0 -175
  140. package/scripts/release-checksum.sh +0 -25
  141. package/scripts/release-pack-canary.sh +0 -97
  142. package/scripts/release-scan.sh +0 -249
  143. package/scripts/release-sign.sh +0 -34
@@ -1,131 +0,0 @@
1
- import { existsSync } from 'node:fs';
2
- import { appendFile, readFile } from 'node:fs/promises';
3
- import { join } from 'node:path';
4
- import type {
5
- SupervisionDeps,
6
- SupervisionSession,
7
- } from '../../../protocol/src/index';
8
- import { SupervisionRuntimeError } from './errors';
9
- import { appendSupervisionEvent, buildEvent } from './events';
10
- import { loadSeatManifest } from './manifest';
11
- import { supervisionRuntimePaths } from './paths';
12
- import { renderProjection, writeLatestState } from './projection';
13
- import { applySupervisionSchema } from './sqlite';
14
- import { withSupervisionTransaction } from './sqlite-impl';
15
- import { insertEventRow, insertSessionRow } from './store-rows';
16
-
17
- export interface SessionOpenArgs {
18
- sessionId: string;
19
- campaignRoot: string;
20
- topic: string;
21
- objective: string;
22
- leadSeat: string;
23
- responderSeat: string;
24
- escalationOwner: string;
25
- timeCapMinutes: number;
26
- turnCap: number;
27
- sourceRefs: string[];
28
- seatManifestOverride?: string;
29
- }
30
-
31
- /**
32
- * Open a new supervision session.
33
- *
34
- * Per PHASE1.md canonical ordering: events.jsonl first (rebuild authority),
35
- * then SQLite mirror inside a single transaction, then artifacts
36
- * (latest-state.json + projection renders).
37
- */
38
- export async function openSupervisionSession(
39
- args: SessionOpenArgs,
40
- deps: SupervisionDeps,
41
- ): Promise<SupervisionSession> {
42
- // Validate seat manifest exists and is well-formed before any state lands.
43
- await loadSeatManifest(args.seatManifestOverride);
44
-
45
- const paths = supervisionRuntimePaths(args.campaignRoot);
46
- await deps.mkdirp(paths.runtimeDir);
47
- await maybeAddGitExclude(args.campaignRoot);
48
-
49
- const db = deps.openSqlite(paths.sqlitePath);
50
- try {
51
- applySupervisionSchema(db);
52
-
53
- const existing = db.get<{ session_id: string }>(
54
- 'SELECT session_id FROM sessions WHERE session_id = ?',
55
- [args.sessionId],
56
- );
57
- if (existing) {
58
- throw new SupervisionRuntimeError(
59
- `session ${args.sessionId} already exists in ${paths.sqlitePath}`,
60
- 'SESSION_EXISTS',
61
- );
62
- }
63
-
64
- const now = deps.now().toISOString();
65
- const session: SupervisionSession = {
66
- sessionId: args.sessionId,
67
- campaignRoot: paths.campaignRoot,
68
- topic: args.topic,
69
- objective: args.objective,
70
- status: 'running',
71
- leadSeat: args.leadSeat,
72
- responderSeat: args.responderSeat,
73
- escalationOwner: args.escalationOwner,
74
- timeCapMinutes: args.timeCapMinutes,
75
- turnCap: args.turnCap,
76
- currentTurnId: null,
77
- nextOwnerHint: null,
78
- approvedNextTurnJson: null,
79
- lastBlockerJson: null,
80
- sourceRefs: [...args.sourceRefs],
81
- createdAt: now,
82
- updatedAt: now,
83
- };
84
-
85
- // Canonical ordering: events.jsonl first (rebuild authority),
86
- // then SQLite mirror inside a single transaction, then artifacts.
87
- const event = buildEvent(deps, {
88
- eventType: 'session.opened',
89
- sessionId: session.sessionId,
90
- turnId: null,
91
- commandId: null,
92
- actor: args.leadSeat,
93
- audience: 'all',
94
- at: now,
95
- payload: session,
96
- });
97
- await appendSupervisionEvent(paths.eventsPath, event);
98
-
99
- withSupervisionTransaction(db, () => {
100
- insertSessionRow(db, session);
101
- insertEventRow(db, event);
102
- });
103
-
104
- await writeLatestState(paths.latestStatePath, session, null);
105
- await renderProjection(deps, paths, session, null, []);
106
-
107
- return session;
108
- } finally {
109
- db.close();
110
- }
111
- }
112
-
113
- /**
114
- * If the campaign root is a git worktree, add `.etiquette/runtime/`
115
- * to `.git/info/exclude` so the hot state never becomes an accidental
116
- * tracked change. Best-effort — unwritable excludes do not fail session-open.
117
- */
118
- async function maybeAddGitExclude(campaignRoot: string): Promise<void> {
119
- const excludePath = join(campaignRoot, '.git', 'info', 'exclude');
120
- if (!existsSync(excludePath)) return;
121
- try {
122
- const existing = await readFile(excludePath, 'utf-8');
123
- const line = '.etiquette/runtime/';
124
- if (!existing.split('\n').some((l) => l.trim() === line)) {
125
- const newline = existing.endsWith('\n') ? '' : '\n';
126
- await appendFile(excludePath, `${newline}${line}\n`);
127
- }
128
- } catch {
129
- // Best-effort; if .git/info/exclude is unwritable we do not fail session-open.
130
- }
131
- }
@@ -1,99 +0,0 @@
1
- import type {
2
- SupervisionDeps,
3
- SupervisionProjection,
4
- } from '../../../protocol/src/index';
5
- import { appendSupervisionEvent, buildEvent } from './events';
6
- import { supervisionRuntimePaths } from './paths';
7
- import { renderProjection } from './projection';
8
- import { applySupervisionSchema } from './sqlite';
9
- import { withSupervisionTransaction } from './sqlite-impl';
10
- import {
11
- insertEventRow,
12
- loadCurrentTurn,
13
- loadPendingCommands,
14
- loadSession,
15
- } from './store-rows';
16
-
17
- export interface SessionStatusArgs {
18
- sessionId: string;
19
- campaignRoot: string;
20
- }
21
-
22
- /**
23
- * Read the current session snapshot (pure read; no state change, no
24
- * projection render, no event emit). Used by `session-status` CLI and
25
- * conformance tests that need to observe state without triggering a
26
- * projection cycle.
27
- */
28
- export async function readSupervisionSession(
29
- args: SessionStatusArgs,
30
- deps: SupervisionDeps,
31
- ): Promise<SupervisionProjection> {
32
- const paths = supervisionRuntimePaths(args.campaignRoot);
33
- const db = deps.openSqlite(paths.sqlitePath);
34
- try {
35
- applySupervisionSchema(db);
36
- const session = loadSession(db, args.sessionId);
37
- const currentTurn = loadCurrentTurn(db, session);
38
- const pendingCommands = loadPendingCommands(db, args.sessionId);
39
- return {
40
- sessionId: session.sessionId,
41
- renderedAt: deps.now().toISOString(),
42
- sessionSnapshot: session,
43
- currentTurn,
44
- pendingCommands,
45
- };
46
- } finally {
47
- db.close();
48
- }
49
- }
50
-
51
- export interface SessionProjectArgs {
52
- sessionId: string;
53
- campaignRoot: string;
54
- }
55
-
56
- /**
57
- * Render the projection artifacts (STATUS_BOARD.md + seat channels +
58
- * latest-projection.json) from current SQLite state, and emit a
59
- * `projection.rendered` event so replay stays complete.
60
- *
61
- * Idempotent per PHASE1.md § Projection rules — rerunning does not duplicate
62
- * channel entries (meta-events like `projection.rendered` are filtered from
63
- * seat-channel output by the adapter).
64
- */
65
- export async function projectSupervisionSession(
66
- args: SessionProjectArgs,
67
- deps: SupervisionDeps,
68
- ): Promise<SupervisionProjection> {
69
- const paths = supervisionRuntimePaths(args.campaignRoot);
70
- const db = deps.openSqlite(paths.sqlitePath);
71
- try {
72
- applySupervisionSchema(db);
73
- const session = loadSession(db, args.sessionId);
74
- const currentTurn = loadCurrentTurn(db, session);
75
- const pendingCommands = loadPendingCommands(db, args.sessionId);
76
- const projection = await renderProjection(deps, paths, session, currentTurn, pendingCommands);
77
-
78
- // Emit projection.rendered event (after render so we know the render succeeded).
79
- const renderedAt = projection.renderedAt;
80
- const event = buildEvent(deps, {
81
- eventType: 'projection.rendered',
82
- sessionId: session.sessionId,
83
- turnId: session.currentTurnId,
84
- commandId: null,
85
- actor: 'system',
86
- audience: 'all',
87
- at: renderedAt,
88
- payload: { renderedAt },
89
- });
90
- await appendSupervisionEvent(paths.eventsPath, event);
91
- withSupervisionTransaction(db, () => {
92
- insertEventRow(db, event);
93
- });
94
-
95
- return projection;
96
- } finally {
97
- db.close();
98
- }
99
- }
@@ -1,71 +0,0 @@
1
- import { Database } from 'bun:sqlite';
2
- import type { SupervisionSqliteHandle } from '../../../protocol/src/index';
3
-
4
- /**
5
- * Wrap a synchronous SQLite mutation bundle in a `BEGIN IMMEDIATE` /
6
- * `COMMIT` transaction. On throw, issue `ROLLBACK` best-effort and rethrow.
7
- *
8
- * Per PHASE1.md and the Phase D addendum: session row + event row +
9
- * command row updates should commit atomically on the SQLite side for
10
- * each logical command operation. Events in `events.jsonl` remain the
11
- * canonical rebuild authority; SQLite is a derived mirror.
12
- *
13
- * Do NOT wrap PRAGMA statements or DDL inside this helper — apply the
14
- * schema before opening a transaction.
15
- */
16
- export function withSupervisionTransaction<T>(
17
- handle: SupervisionSqliteHandle,
18
- fn: () => T,
19
- ): T {
20
- handle.run('BEGIN IMMEDIATE');
21
- try {
22
- const result = fn();
23
- handle.run('COMMIT');
24
- return result;
25
- } catch (err) {
26
- try {
27
- handle.run('ROLLBACK');
28
- } catch {
29
- // Best-effort rollback; the real error is re-thrown below.
30
- }
31
- throw err;
32
- }
33
- }
34
-
35
- /**
36
- * Open (or create) a SQLite database at `path` and wrap it as a
37
- * SupervisionSqliteHandle. Multi-statement DDL (schema init) goes through
38
- * `.exec()`; single-statement parameterized queries go through prepared
39
- * statements via `.query()`.
40
- *
41
- * Usage in tests: pass ":memory:" for an in-process DB without filesystem.
42
- */
43
- export function openSupervisionSqlite(path: string): SupervisionSqliteHandle {
44
- const db = new Database(path);
45
- return {
46
- run(sql: string, params?: unknown[]): void {
47
- if (!params || params.length === 0) {
48
- db.exec(sql);
49
- return;
50
- }
51
- db.query(sql).run(...(params as never[]));
52
- },
53
- all<T = unknown>(sql: string, params?: unknown[]): T[] {
54
- const stmt = db.query(sql);
55
- if (!params || params.length === 0) {
56
- return stmt.all() as T[];
57
- }
58
- return stmt.all(...(params as never[])) as T[];
59
- },
60
- get<T = unknown>(sql: string, params?: unknown[]): T | undefined {
61
- const stmt = db.query(sql);
62
- const row = !params || params.length === 0
63
- ? stmt.get()
64
- : stmt.get(...(params as never[]));
65
- return (row as T | null) ?? undefined;
66
- },
67
- close(): void {
68
- db.close();
69
- },
70
- };
71
- }
@@ -1,121 +0,0 @@
1
- import type { SupervisionSqliteHandle } from '../../../protocol/src/index';
2
-
3
- /**
4
- * SQLite schema for Phase 1 supervision hot state. See
5
- * etiquette/internal/docs/supervision/PHASE1.md for column semantics.
6
- *
7
- * The schema is applied once on session-open. Re-applying is a no-op
8
- * (`CREATE TABLE IF NOT EXISTS`). WAL mode is enabled unconditionally.
9
- */
10
- export const SUPERVISION_SCHEMA_SQL = `
11
- PRAGMA journal_mode = WAL;
12
-
13
- CREATE TABLE IF NOT EXISTS sessions (
14
- session_id TEXT PRIMARY KEY,
15
- campaign_root TEXT NOT NULL,
16
- topic TEXT NOT NULL,
17
- objective TEXT NOT NULL,
18
- status TEXT NOT NULL CHECK (status IN ('running','paused','blocked','awaiting_human','closed')),
19
- lead_seat TEXT NOT NULL,
20
- responder_seat TEXT NOT NULL,
21
- escalation_owner TEXT NOT NULL,
22
- time_cap_minutes INTEGER NOT NULL,
23
- turn_cap INTEGER NOT NULL,
24
- current_turn_id TEXT,
25
- next_owner_hint TEXT,
26
- approved_next_turn_json TEXT,
27
- last_blocker_json TEXT,
28
- source_refs_json TEXT NOT NULL,
29
- created_at TEXT NOT NULL,
30
- updated_at TEXT NOT NULL
31
- );
32
-
33
- CREATE TABLE IF NOT EXISTS turns (
34
- turn_id TEXT PRIMARY KEY,
35
- session_id TEXT NOT NULL REFERENCES sessions(session_id),
36
- sequence_no INTEGER NOT NULL,
37
- status TEXT NOT NULL CHECK (status IN ('open','closed')),
38
- owner_seat TEXT NOT NULL,
39
- allowed_action_class TEXT NOT NULL CHECK (allowed_action_class IN (
40
- 'coordination_only','read_only_local','bounded_verification','bounded_product_mutation','human_only'
41
- )),
42
- max_duration_minutes INTEGER NOT NULL,
43
- allowed_commands_json TEXT NOT NULL,
44
- repo_roots_json TEXT NOT NULL,
45
- owned_paths_json TEXT NOT NULL,
46
- forbidden_paths_json TEXT NOT NULL,
47
- verify_commands_json TEXT NOT NULL,
48
- requires_human_approval INTEGER NOT NULL CHECK (requires_human_approval IN (0,1)),
49
- projection_policy TEXT NOT NULL CHECK (projection_policy IN ('on_state_change','on_command_only')),
50
- started_at TEXT NOT NULL,
51
- ended_at TEXT,
52
- result TEXT CHECK (result IS NULL OR result IN ('done','blocked','handed_off','stopped','timed_out')),
53
- summary TEXT,
54
- evidence_refs_json TEXT NOT NULL,
55
- UNIQUE (session_id, sequence_no)
56
- );
57
-
58
- CREATE TABLE IF NOT EXISTS commands (
59
- command_id TEXT PRIMARY KEY,
60
- session_id TEXT NOT NULL REFERENCES sessions(session_id),
61
- turn_id TEXT REFERENCES turns(turn_id),
62
- issued_by TEXT NOT NULL,
63
- command TEXT NOT NULL CHECK (command IN (
64
- 'status','pause','resume','stop','approve_next_turn','redirect_owner',
65
- 'request_summary','mark_blocked','escalate_to_human'
66
- )),
67
- payload_json TEXT NOT NULL,
68
- status TEXT NOT NULL CHECK (status IN ('queued','applied','rejected','expired')),
69
- issued_at TEXT NOT NULL,
70
- applied_at TEXT,
71
- rejection_reason TEXT
72
- );
73
-
74
- CREATE TABLE IF NOT EXISTS events (
75
- seq INTEGER PRIMARY KEY AUTOINCREMENT,
76
- event_id TEXT UNIQUE NOT NULL,
77
- session_id TEXT NOT NULL,
78
- turn_id TEXT,
79
- command_id TEXT,
80
- event_type TEXT NOT NULL CHECK (event_type IN (
81
- 'session.opened','session.status_changed','session.next_owner_changed',
82
- 'turn.opened','turn.closed',
83
- 'command.queued','command.applied','command.rejected',
84
- 'projection.rendered','rebuild.completed'
85
- )),
86
- actor TEXT NOT NULL,
87
- audience TEXT NOT NULL,
88
- at TEXT NOT NULL,
89
- payload_json TEXT NOT NULL
90
- );
91
-
92
- CREATE VIEW IF NOT EXISTS latest_session_state AS
93
- SELECT
94
- s.*,
95
- t.turn_id AS current_turn_id_verified,
96
- t.sequence_no AS current_turn_sequence_no,
97
- t.status AS current_turn_status,
98
- t.owner_seat AS current_turn_owner
99
- FROM sessions s
100
- LEFT JOIN turns t ON t.turn_id = s.current_turn_id;
101
-
102
- CREATE VIEW IF NOT EXISTS latest_turn_state AS
103
- SELECT * FROM turns
104
- WHERE status = 'open'
105
- ORDER BY started_at DESC;
106
-
107
- CREATE VIEW IF NOT EXISTS pending_commands AS
108
- SELECT * FROM commands
109
- WHERE status = 'queued'
110
- ORDER BY issued_at ASC;
111
- `;
112
-
113
- /**
114
- * Apply the schema to a SQLite handle. Idempotent; safe to call on every
115
- * session-open.
116
- */
117
- export function applySupervisionSchema(handle: SupervisionSqliteHandle): void {
118
- // SQLite CLI wrappers generally accept multi-statement SQL on run(); this
119
- // matches the shape used by bun:sqlite and better-sqlite3's .exec().
120
- handle.run(SUPERVISION_SCHEMA_SQL);
121
- }