@etiquekit/etq 1.0.14 → 1.0.16

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 +50 -39
  5. package/README.md +56 -56
  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 +7 -8
  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 +1154 -0
  23. package/package.json +11 -10
  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 -4690
  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 -842
  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 -15
  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,371 +0,0 @@
1
- /**
2
- * SQLite row mapping for the supervision hot store.
3
- *
4
- * Holds every `INSERT` / `UPDATE` / `SELECT` helper plus the row interfaces
5
- * and the `row → domain object` mappers. No I/O beyond the single `db.run` /
6
- * `db.get` / `db.all` calls. Transaction scoping is the caller's concern
7
- * (see `sqlite-impl.ts :: withSupervisionTransaction`).
8
- */
9
- import type {
10
- ActionClass,
11
- AllowedCommandId,
12
- ProjectionPolicy,
13
- SessionStatus,
14
- SupervisionCommand,
15
- SupervisionCommandRecord,
16
- SupervisionDeps,
17
- SupervisionEvent,
18
- SupervisionSession,
19
- SupervisionTurn,
20
- TurnResult,
21
- } from '../../../protocol/src/index';
22
- import { SupervisionRuntimeError } from './errors';
23
-
24
- // ---------------------------------------------------------------------------
25
- // INSERT helpers
26
- // ---------------------------------------------------------------------------
27
-
28
- export function insertSessionRow(
29
- db: ReturnType<SupervisionDeps['openSqlite']>,
30
- s: SupervisionSession,
31
- ): void {
32
- db.run(
33
- `INSERT INTO sessions (
34
- session_id, campaign_root, topic, objective, status,
35
- lead_seat, responder_seat, escalation_owner,
36
- time_cap_minutes, turn_cap,
37
- current_turn_id, next_owner_hint, approved_next_turn_json, last_blocker_json,
38
- source_refs_json, created_at, updated_at
39
- ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
40
- [
41
- s.sessionId, s.campaignRoot, s.topic, s.objective, s.status,
42
- s.leadSeat, s.responderSeat, s.escalationOwner,
43
- s.timeCapMinutes, s.turnCap,
44
- s.currentTurnId, s.nextOwnerHint, s.approvedNextTurnJson, s.lastBlockerJson,
45
- JSON.stringify(s.sourceRefs), s.createdAt, s.updatedAt,
46
- ],
47
- );
48
- }
49
-
50
- export function insertTurnRow(
51
- db: ReturnType<SupervisionDeps['openSqlite']>,
52
- t: SupervisionTurn,
53
- ): void {
54
- db.run(
55
- `INSERT INTO turns (
56
- turn_id, session_id, sequence_no, status, owner_seat,
57
- allowed_action_class, max_duration_minutes, allowed_commands_json,
58
- repo_roots_json, owned_paths_json, forbidden_paths_json, verify_commands_json,
59
- requires_human_approval, projection_policy,
60
- started_at, ended_at, result, summary, evidence_refs_json
61
- ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
62
- [
63
- t.turnId, t.sessionId, t.sequenceNo, t.status, t.ownerSeat,
64
- t.allowedActionClass, t.maxDurationMinutes, JSON.stringify(t.allowedCommands),
65
- JSON.stringify(t.repoRoots), JSON.stringify(t.ownedPaths),
66
- JSON.stringify(t.forbiddenPaths), JSON.stringify(t.verifyCommands),
67
- t.requiresHumanApproval ? 1 : 0, t.projectionPolicy,
68
- t.startedAt, t.endedAt, t.result, t.summary, JSON.stringify(t.evidenceRefs),
69
- ],
70
- );
71
- }
72
-
73
- export function insertCommandRow(
74
- db: ReturnType<SupervisionDeps['openSqlite']>,
75
- c: SupervisionCommandRecord,
76
- ): void {
77
- db.run(
78
- `INSERT INTO commands (
79
- command_id, session_id, turn_id, issued_by, command, payload_json,
80
- status, issued_at, applied_at, rejection_reason
81
- ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
82
- [
83
- c.commandId, c.sessionId, c.turnId, c.issuedBy, c.command, c.payloadJson,
84
- c.status, c.issuedAt, c.appliedAt, c.rejectionReason,
85
- ],
86
- );
87
- }
88
-
89
- export function insertEventRow(
90
- db: ReturnType<SupervisionDeps['openSqlite']>,
91
- event: SupervisionEvent,
92
- ): void {
93
- db.run(
94
- `INSERT INTO events (
95
- event_id, session_id, turn_id, command_id, event_type,
96
- actor, audience, at, payload_json
97
- ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`,
98
- [
99
- event.eventId, event.sessionId, event.turnId, event.commandId, event.eventType,
100
- event.actor, event.audience, event.at, JSON.stringify(event.payload ?? null),
101
- ],
102
- );
103
- }
104
-
105
- // ---------------------------------------------------------------------------
106
- // UPDATE helpers
107
- // ---------------------------------------------------------------------------
108
-
109
- export function updateSessionStatus(
110
- db: ReturnType<SupervisionDeps['openSqlite']>,
111
- sessionId: string,
112
- status: SessionStatus,
113
- at: string,
114
- ): void {
115
- db.run('UPDATE sessions SET status = ?, updated_at = ? WHERE session_id = ?', [status, at, sessionId]);
116
- }
117
-
118
- export function updateSessionNextOwner(
119
- db: ReturnType<SupervisionDeps['openSqlite']>,
120
- sessionId: string,
121
- nextOwner: string | null,
122
- at: string,
123
- ): void {
124
- db.run('UPDATE sessions SET next_owner_hint = ?, updated_at = ? WHERE session_id = ?', [
125
- nextOwner, at, sessionId,
126
- ]);
127
- }
128
-
129
- export function updateSessionApproval(
130
- db: ReturnType<SupervisionDeps['openSqlite']>,
131
- sessionId: string,
132
- approvalJson: string | null,
133
- at: string,
134
- ): void {
135
- db.run('UPDATE sessions SET approved_next_turn_json = ?, updated_at = ? WHERE session_id = ?', [
136
- approvalJson, at, sessionId,
137
- ]);
138
- }
139
-
140
- export function updateSessionBlocker(
141
- db: ReturnType<SupervisionDeps['openSqlite']>,
142
- sessionId: string,
143
- blockerJson: string | null,
144
- at: string,
145
- ): void {
146
- db.run('UPDATE sessions SET last_blocker_json = ?, updated_at = ? WHERE session_id = ?', [
147
- blockerJson, at, sessionId,
148
- ]);
149
- }
150
-
151
- export function updateSessionCurrentTurn(
152
- db: ReturnType<SupervisionDeps['openSqlite']>,
153
- sessionId: string,
154
- turnId: string,
155
- at: string,
156
- ): void {
157
- db.run('UPDATE sessions SET current_turn_id = ?, updated_at = ? WHERE session_id = ?', [
158
- turnId, at, sessionId,
159
- ]);
160
- }
161
-
162
- export function clearSessionCurrentTurn(
163
- db: ReturnType<SupervisionDeps['openSqlite']>,
164
- sessionId: string,
165
- at: string,
166
- ): void {
167
- db.run('UPDATE sessions SET current_turn_id = NULL, updated_at = ? WHERE session_id = ?', [at, sessionId]);
168
- }
169
-
170
- export function clearSessionApproval(
171
- db: ReturnType<SupervisionDeps['openSqlite']>,
172
- sessionId: string,
173
- at: string,
174
- ): void {
175
- db.run('UPDATE sessions SET approved_next_turn_json = NULL, updated_at = ? WHERE session_id = ?', [at, sessionId]);
176
- }
177
-
178
- export function updateTurnOnClose(
179
- db: ReturnType<SupervisionDeps['openSqlite']>,
180
- t: SupervisionTurn,
181
- ): void {
182
- db.run(
183
- `UPDATE turns SET status = ?, ended_at = ?, result = ?, summary = ?, evidence_refs_json = ? WHERE turn_id = ?`,
184
- [t.status, t.endedAt, t.result, t.summary, JSON.stringify(t.evidenceRefs), t.turnId],
185
- );
186
- }
187
-
188
- export function updateCommandApplied(
189
- db: ReturnType<SupervisionDeps['openSqlite']>,
190
- commandId: string,
191
- at: string,
192
- ): void {
193
- db.run(
194
- `UPDATE commands SET status = 'applied', applied_at = ? WHERE command_id = ?`,
195
- [at, commandId],
196
- );
197
- }
198
-
199
- export function updateCommandRejected(
200
- db: ReturnType<SupervisionDeps['openSqlite']>,
201
- commandId: string,
202
- at: string,
203
- reason: string,
204
- ): void {
205
- db.run(
206
- `UPDATE commands SET status = 'rejected', applied_at = ?, rejection_reason = ? WHERE command_id = ?`,
207
- [at, reason, commandId],
208
- );
209
- }
210
-
211
- // ---------------------------------------------------------------------------
212
- // SELECT / row → domain mappers
213
- // ---------------------------------------------------------------------------
214
-
215
- interface SessionRow {
216
- session_id: string;
217
- campaign_root: string;
218
- topic: string;
219
- objective: string;
220
- status: SessionStatus;
221
- lead_seat: string;
222
- responder_seat: string;
223
- escalation_owner: string;
224
- time_cap_minutes: number;
225
- turn_cap: number;
226
- current_turn_id: string | null;
227
- next_owner_hint: string | null;
228
- approved_next_turn_json: string | null;
229
- last_blocker_json: string | null;
230
- source_refs_json: string;
231
- created_at: string;
232
- updated_at: string;
233
- }
234
-
235
- export function loadSession(
236
- db: ReturnType<SupervisionDeps['openSqlite']>,
237
- sessionId: string,
238
- ): SupervisionSession {
239
- const row = db.get<SessionRow>('SELECT * FROM sessions WHERE session_id = ?', [sessionId]);
240
- if (!row) {
241
- throw new SupervisionRuntimeError(`session ${sessionId} not found`, 'SESSION_NOT_FOUND');
242
- }
243
- return rowToSession(row);
244
- }
245
-
246
- function rowToSession(row: SessionRow): SupervisionSession {
247
- return {
248
- sessionId: row.session_id,
249
- campaignRoot: row.campaign_root,
250
- topic: row.topic,
251
- objective: row.objective,
252
- status: row.status,
253
- leadSeat: row.lead_seat,
254
- responderSeat: row.responder_seat,
255
- escalationOwner: row.escalation_owner,
256
- timeCapMinutes: row.time_cap_minutes,
257
- turnCap: row.turn_cap,
258
- currentTurnId: row.current_turn_id,
259
- nextOwnerHint: row.next_owner_hint,
260
- approvedNextTurnJson: row.approved_next_turn_json,
261
- lastBlockerJson: row.last_blocker_json,
262
- sourceRefs: JSON.parse(row.source_refs_json) as string[],
263
- createdAt: row.created_at,
264
- updatedAt: row.updated_at,
265
- };
266
- }
267
-
268
- interface TurnRow {
269
- turn_id: string;
270
- session_id: string;
271
- sequence_no: number;
272
- status: 'open' | 'closed';
273
- owner_seat: string;
274
- allowed_action_class: ActionClass;
275
- max_duration_minutes: number;
276
- allowed_commands_json: string;
277
- repo_roots_json: string;
278
- owned_paths_json: string;
279
- forbidden_paths_json: string;
280
- verify_commands_json: string;
281
- requires_human_approval: number;
282
- projection_policy: ProjectionPolicy;
283
- started_at: string;
284
- ended_at: string | null;
285
- result: TurnResult | null;
286
- summary: string | null;
287
- evidence_refs_json: string;
288
- }
289
-
290
- export function loadTurn(
291
- db: ReturnType<SupervisionDeps['openSqlite']>,
292
- turnId: string,
293
- ): SupervisionTurn {
294
- const row = db.get<TurnRow>('SELECT * FROM turns WHERE turn_id = ?', [turnId]);
295
- if (!row) {
296
- throw new SupervisionRuntimeError(`turn ${turnId} not found`, 'TURN_NOT_FOUND');
297
- }
298
- return rowToTurn(row);
299
- }
300
-
301
- export function loadCurrentTurn(
302
- db: ReturnType<SupervisionDeps['openSqlite']>,
303
- session: SupervisionSession,
304
- ): SupervisionTurn | null {
305
- if (!session.currentTurnId) return null;
306
- const row = db.get<TurnRow>('SELECT * FROM turns WHERE turn_id = ?', [session.currentTurnId]);
307
- return row ? rowToTurn(row) : null;
308
- }
309
-
310
- function rowToTurn(row: TurnRow): SupervisionTurn {
311
- return {
312
- turnId: row.turn_id,
313
- sessionId: row.session_id,
314
- sequenceNo: row.sequence_no,
315
- status: row.status,
316
- ownerSeat: row.owner_seat,
317
- allowedActionClass: row.allowed_action_class,
318
- maxDurationMinutes: row.max_duration_minutes,
319
- allowedCommands: JSON.parse(row.allowed_commands_json) as AllowedCommandId[],
320
- repoRoots: JSON.parse(row.repo_roots_json) as string[],
321
- ownedPaths: JSON.parse(row.owned_paths_json) as string[],
322
- forbiddenPaths: JSON.parse(row.forbidden_paths_json) as string[],
323
- verifyCommands: JSON.parse(row.verify_commands_json) as string[],
324
- requiresHumanApproval: row.requires_human_approval === 1,
325
- projectionPolicy: row.projection_policy,
326
- startedAt: row.started_at,
327
- endedAt: row.ended_at,
328
- result: row.result,
329
- summary: row.summary,
330
- evidenceRefs: JSON.parse(row.evidence_refs_json) as string[],
331
- };
332
- }
333
-
334
- interface CommandRow {
335
- command_id: string;
336
- session_id: string;
337
- turn_id: string | null;
338
- issued_by: string;
339
- command: SupervisionCommand;
340
- payload_json: string;
341
- status: SupervisionCommandRecord['status'];
342
- issued_at: string;
343
- applied_at: string | null;
344
- rejection_reason: string | null;
345
- }
346
-
347
- export function loadPendingCommands(
348
- db: ReturnType<SupervisionDeps['openSqlite']>,
349
- sessionId: string,
350
- ): SupervisionCommandRecord[] {
351
- const rows = db.all<CommandRow>(
352
- 'SELECT * FROM commands WHERE session_id = ? AND status = ? ORDER BY issued_at ASC',
353
- [sessionId, 'queued'],
354
- );
355
- return rows.map(rowToCommand);
356
- }
357
-
358
- function rowToCommand(row: CommandRow): SupervisionCommandRecord {
359
- return {
360
- commandId: row.command_id,
361
- sessionId: row.session_id,
362
- turnId: row.turn_id,
363
- issuedBy: row.issued_by,
364
- command: row.command,
365
- payloadJson: row.payload_json,
366
- status: row.status,
367
- issuedAt: row.issued_at,
368
- appliedAt: row.applied_at,
369
- rejectionReason: row.rejection_reason,
370
- };
371
- }
@@ -1,154 +0,0 @@
1
- import type {
2
- SessionStatus,
3
- SupervisionDeps,
4
- SupervisionSession,
5
- SupervisionTurn,
6
- TurnResult,
7
- } from '../../../protocol/src/index';
8
- import { SupervisionRuntimeError } from './errors';
9
- import { appendSupervisionEvent, buildEvent } from './events';
10
- import { supervisionRuntimePaths } from './paths';
11
- import { renderProjection, writeLatestState } from './projection';
12
- import { applySupervisionSchema } from './sqlite';
13
- import { withSupervisionTransaction } from './sqlite-impl';
14
- import {
15
- clearSessionApproval,
16
- clearSessionCurrentTurn,
17
- insertEventRow,
18
- loadPendingCommands,
19
- loadSession,
20
- loadTurn,
21
- updateSessionStatus,
22
- updateTurnOnClose,
23
- } from './store-rows';
24
-
25
- export interface TurnCloseArgs {
26
- sessionId: string;
27
- campaignRoot: string;
28
- turnId: string;
29
- result: TurnResult;
30
- summary: string;
31
- evidenceRefs: string[];
32
- }
33
-
34
- /**
35
- * Close an open turn with the given result. Derives the next session status
36
- * from the result per PHASE1.md § Turn semantics:
37
- * - done / handed_off → running
38
- * - blocked → blocked
39
- * - stopped / timed_out → awaiting_human (also clears any stored approval)
40
- *
41
- * Canonical ordering: events.jsonl first (turn.closed + optional
42
- * session.status_changed), then one SQLite txn, then artifacts.
43
- */
44
- export async function closeSupervisionTurn(
45
- args: TurnCloseArgs,
46
- deps: SupervisionDeps,
47
- ): Promise<SupervisionTurn> {
48
- const paths = supervisionRuntimePaths(args.campaignRoot);
49
- const db = deps.openSqlite(paths.sqlitePath);
50
- try {
51
- applySupervisionSchema(db);
52
- const session = loadSession(db, args.sessionId);
53
- const turn = loadTurn(db, args.turnId);
54
- if (turn.sessionId !== args.sessionId) {
55
- throw new SupervisionRuntimeError(
56
- `turn ${args.turnId} does not belong to session ${args.sessionId}`,
57
- 'TURN_SESSION_MISMATCH',
58
- );
59
- }
60
- if (turn.status !== 'open') {
61
- throw new SupervisionRuntimeError(
62
- `turn ${args.turnId} is not open (status=${turn.status})`,
63
- 'TURN_NOT_OPEN',
64
- );
65
- }
66
-
67
- const now = deps.now().toISOString();
68
- const updatedTurn: SupervisionTurn = {
69
- ...turn,
70
- status: 'closed',
71
- endedAt: now,
72
- result: args.result,
73
- summary: args.summary,
74
- evidenceRefs: [...args.evidenceRefs],
75
- };
76
-
77
- // Derive next session status from result.
78
- const nextStatus: SessionStatus =
79
- args.result === 'done' || args.result === 'handed_off'
80
- ? 'running'
81
- : args.result === 'blocked'
82
- ? 'blocked'
83
- : 'awaiting_human';
84
- const statusChanged = nextStatus !== session.status;
85
- const clearApproval = nextStatus === 'awaiting_human' && !!session.approvedNextTurnJson;
86
-
87
- const turnEvent = buildEvent(deps, {
88
- eventType: 'turn.closed',
89
- sessionId: args.sessionId,
90
- turnId: turn.turnId,
91
- commandId: null,
92
- actor: turn.ownerSeat,
93
- audience: 'all',
94
- at: now,
95
- payload: {
96
- endedAt: now,
97
- result: args.result,
98
- summary: args.summary,
99
- evidenceRefs: [...args.evidenceRefs],
100
- },
101
- });
102
- const statusEvent = statusChanged
103
- ? buildEvent(deps, {
104
- eventType: 'session.status_changed',
105
- sessionId: session.sessionId,
106
- turnId: null,
107
- commandId: null,
108
- actor: 'system',
109
- audience: 'all',
110
- at: now,
111
- payload: { from: session.status, to: nextStatus, reason: `turn_closed:${args.result}` },
112
- })
113
- : null;
114
-
115
- // Events first (canonical), then SQLite mirror in a single transaction.
116
- await appendSupervisionEvent(paths.eventsPath, turnEvent);
117
- if (statusEvent) {
118
- await appendSupervisionEvent(paths.eventsPath, statusEvent);
119
- }
120
-
121
- withSupervisionTransaction(db, () => {
122
- updateTurnOnClose(db, updatedTurn);
123
- clearSessionCurrentTurn(db, session.sessionId, now);
124
- insertEventRow(db, turnEvent);
125
- if (statusEvent) {
126
- updateSessionStatus(db, session.sessionId, nextStatus, now);
127
- insertEventRow(db, statusEvent);
128
- }
129
- if (clearApproval) {
130
- clearSessionApproval(db, session.sessionId, now);
131
- }
132
- });
133
-
134
- const sessionForOutputs: SupervisionSession = {
135
- ...session,
136
- currentTurnId: null,
137
- status: nextStatus,
138
- approvedNextTurnJson: clearApproval ? null : session.approvedNextTurnJson,
139
- updatedAt: now,
140
- };
141
-
142
- await writeLatestState(paths.latestStatePath, sessionForOutputs, null);
143
- await renderProjection(
144
- deps,
145
- paths,
146
- sessionForOutputs,
147
- null,
148
- loadPendingCommands(db, session.sessionId),
149
- );
150
- return updatedTurn;
151
- } finally {
152
- db.close();
153
- }
154
- }