@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.
- package/AGENTS.md +26 -19
- package/LICENSE +3 -2
- package/NOTICE +4 -6
- package/QuickStart.md +50 -39
- package/README.md +56 -56
- package/bin/etiquette +5 -1
- package/bin/etiquette-core +5 -1
- package/docs/ARCHITECTURE.md +17 -20
- package/docs/CONCEPTS.md +5 -5
- package/docs/CORE_PROFILE.md +15 -7
- package/docs/LANE_PROVISIONING.md +2 -7
- package/docs/README.md +14 -13
- package/docs/RELEASE_SURFACE_AUDIT.md +7 -8
- package/docs/SEAT_DISCIPLINE.md +91 -55
- package/docs/SEAT_PROVISIONING.md +19 -16
- package/docs/TEAM_HANDOFF.md +21 -21
- package/docs/WORKTREE_QOL.md +0 -7
- package/docs/contracts/ledger-entry/README.md +11 -11
- package/docs/contracts/ledger-entry/ledger-entry.v0.2.md +2 -2
- package/docs/contracts/ledger-entry/ledger-entry.v0.md +8 -8
- package/lib/etiquette-core.js +313 -0
- package/lib/etiquette.js +1154 -0
- package/package.json +11 -10
- package/templates/etiquette-vanilla-v0/README.md +3 -2
- package/templates/etiquette-vanilla-v0/source/control-seat/README.md +6 -0
- package/templates/etiquette-vanilla-v0/source/control-seat/bin/access-assurance-check +55 -0
- package/templates/etiquette-vanilla-v0/source/control-seat/bin/seat-doctor +5 -0
- package/templates/etiquette-vanilla-v0/source/control-seat/docs/work/access/ACCESS-ASSURANCE.md +39 -0
- package/templates/etiquette-vanilla-v0/source/control-seat/docs/work/access/workspace-secure-profile.v0.json +53 -0
- package/templates/etiquette-vanilla-v0/validate-vanilla.sh +5 -0
- package/templates/hosted-receiver/README.md +41 -0
- package/templates/hosted-receiver/w1-github-webhook-receiver.mjs +129 -0
- package/templates/seat-packs-v0/README.md +2 -3
- package/templates/seat-packs-v0/source/claude-code-seat/README.md +3 -3
- package/templates/seat-packs-v0/source/codex-seat/README.md +3 -3
- package/templates/seat-packs-v0/source/gemini-seat/README.md +3 -3
- package/templates/seat-packs-v0/source/ollama-seat/README.md +3 -3
- package/templates/seat-packs-v0/source/openrouter-seat/README.md +3 -3
- package/docs/CONCEPT_STATUS.md +0 -66
- package/packages/control/src/authority/lease.ts +0 -261
- package/packages/control/src/authority/node-delegation.ts +0 -257
- package/packages/control/src/authority/rig-conductor.ts +0 -632
- package/packages/control/src/cli/argv.ts +0 -155
- package/packages/control/src/cli/commands/console.ts +0 -200
- package/packages/control/src/cli/commands/dispatch-core.ts +0 -89
- package/packages/control/src/cli/commands/dispatch.ts +0 -279
- package/packages/control/src/cli/commands/harness.ts +0 -89
- package/packages/control/src/cli/commands/hook.ts +0 -50
- package/packages/control/src/cli/commands/ledger.ts +0 -91
- package/packages/control/src/cli/commands/local-workflow.ts +0 -4690
- package/packages/control/src/cli/commands/memory.ts +0 -445
- package/packages/control/src/cli/commands/release.ts +0 -108
- package/packages/control/src/cli/commands/rubric.ts +0 -103
- package/packages/control/src/cli/commands/seat.ts +0 -179
- package/packages/control/src/cli/commands/session.ts +0 -127
- package/packages/control/src/cli/commands/supervision.ts +0 -246
- package/packages/control/src/cli/commands/sync.ts +0 -119
- package/packages/control/src/cli/commands/workflow.ts +0 -86
- package/packages/control/src/cli/commands/workspace.ts +0 -50
- package/packages/control/src/cli/core-usage.ts +0 -34
- package/packages/control/src/cli/prompt.ts +0 -67
- package/packages/control/src/cli/supervision-deps.ts +0 -44
- package/packages/control/src/cli/usage.ts +0 -241
- package/packages/control/src/cli.ts +0 -207
- package/packages/control/src/core-cli.ts +0 -50
- package/packages/control/src/dispatch/decision.ts +0 -202
- package/packages/control/src/dispatch/projection.ts +0 -293
- package/packages/control/src/dispatch/record.ts +0 -153
- package/packages/control/src/engagement/project.ts +0 -170
- package/packages/control/src/fs.ts +0 -19
- package/packages/control/src/harness/pruning.ts +0 -406
- package/packages/control/src/hooks/dispatcher.ts +0 -117
- package/packages/control/src/hooks/outbox.ts +0 -86
- package/packages/control/src/hooks/sanitize.ts +0 -6
- package/packages/control/src/hooks/types.ts +0 -34
- package/packages/control/src/index.ts +0 -384
- package/packages/control/src/ledger/entry.ts +0 -303
- package/packages/control/src/ledger/indexer.ts +0 -542
- package/packages/control/src/memory/context.ts +0 -149
- package/packages/control/src/memory/drain-import.ts +0 -207
- package/packages/control/src/memory/indexer.ts +0 -284
- package/packages/control/src/memory/query.ts +0 -75
- package/packages/control/src/memory/sanitize.ts +0 -50
- package/packages/control/src/memory/sharded-drain-import.ts +0 -212
- package/packages/control/src/memory/status.ts +0 -211
- package/packages/control/src/memory/store-lifecycle.ts +0 -509
- package/packages/control/src/memory/store.ts +0 -284
- package/packages/control/src/memory/types.ts +0 -146
- package/packages/control/src/parity/surfaces.ts +0 -748
- package/packages/control/src/project.ts +0 -141
- package/packages/control/src/projection/local-ledger-view.ts +0 -373
- package/packages/control/src/projection/return-enforcement.ts +0 -48
- package/packages/control/src/projection/timeline-preview.ts +0 -539
- package/packages/control/src/projection/timeline.ts +0 -708
- package/packages/control/src/release/readiness.ts +0 -842
- package/packages/control/src/rubric/loader.ts +0 -326
- package/packages/control/src/rubric/promotion.ts +0 -54
- package/packages/control/src/rubric/runner.ts +0 -159
- package/packages/control/src/rubric/types.ts +0 -158
- package/packages/control/src/seat/owner-card.ts +0 -388
- package/packages/control/src/seat/readiness.ts +0 -834
- package/packages/control/src/session/runbook.ts +0 -431
- package/packages/control/src/shared/sanitize.ts +0 -49
- package/packages/control/src/supervision/action-classes.ts +0 -192
- package/packages/control/src/supervision/command-apply.ts +0 -378
- package/packages/control/src/supervision/errors.ts +0 -14
- package/packages/control/src/supervision/event-replay.ts +0 -155
- package/packages/control/src/supervision/events.ts +0 -109
- package/packages/control/src/supervision/index.ts +0 -16
- package/packages/control/src/supervision/manifest.ts +0 -127
- package/packages/control/src/supervision/paths.ts +0 -49
- package/packages/control/src/supervision/projection-adapter.ts +0 -274
- package/packages/control/src/supervision/projection.ts +0 -75
- package/packages/control/src/supervision/rebuild.ts +0 -99
- package/packages/control/src/supervision/session-open.ts +0 -131
- package/packages/control/src/supervision/session-read.ts +0 -99
- package/packages/control/src/supervision/sqlite-impl.ts +0 -71
- package/packages/control/src/supervision/sqlite.ts +0 -121
- package/packages/control/src/supervision/store-rows.ts +0 -371
- package/packages/control/src/supervision/turn-close.ts +0 -154
- package/packages/control/src/supervision/turn-open.ts +0 -284
- package/packages/control/src/sync/event-log-merge-driver.ts +0 -263
- package/packages/control/src/sync/join-plan.ts +0 -375
- package/packages/control/src/sync/outbox.ts +0 -492
- package/packages/control/src/workflow/evaluator.ts +0 -140
- package/packages/control/src/workflow/loader.ts +0 -200
- package/packages/control/src/workflow/types.ts +0 -90
- package/packages/control/src/workspace/authority.ts +0 -499
- package/packages/protocol/src/guards.ts +0 -119
- package/packages/protocol/src/huddle-board.ts +0 -198
- package/packages/protocol/src/huddle.ts +0 -295
- package/packages/protocol/src/incident.ts +0 -251
- package/packages/protocol/src/index.ts +0 -8
- package/packages/protocol/src/interfaces.ts +0 -107
- package/packages/protocol/src/packet-profile.ts +0 -195
- package/packages/protocol/src/state.ts +0 -81
- package/packages/protocol/src/types.ts +0 -434
- package/release/lineage.v0.json +0 -15
- package/scripts/release-candidate-verify.sh +0 -175
- package/scripts/release-checksum.sh +0 -25
- package/scripts/release-pack-canary.sh +0 -97
- package/scripts/release-scan.sh +0 -249
- 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
|
-
}
|