@jmoyers/harness 0.1.0
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/LICENSE +21 -0
- package/README.md +145 -0
- package/native/ptyd/Cargo.lock +16 -0
- package/native/ptyd/Cargo.toml +7 -0
- package/native/ptyd/src/main.rs +257 -0
- package/package.json +90 -0
- package/scripts/build-ptyd.sh +73 -0
- package/scripts/control-plane-daemon.ts +277 -0
- package/scripts/cursor-hook-relay.ts +82 -0
- package/scripts/harness-animate.ts +469 -0
- package/scripts/harness-bin.js +77 -0
- package/scripts/harness-core.ts +1 -0
- package/scripts/harness-inspector.ts +439 -0
- package/scripts/harness.ts +2493 -0
- package/src/adapters/agent-session-state.ts +390 -0
- package/src/cli/gateway-record.ts +173 -0
- package/src/codex/live-session.ts +872 -0
- package/src/config/config-core.ts +1359 -0
- package/src/config/secrets-core.ts +170 -0
- package/src/control-plane/agent-realtime-api.ts +2441 -0
- package/src/control-plane/codex-session-stream.ts +392 -0
- package/src/control-plane/codex-telemetry.ts +1325 -0
- package/src/control-plane/lifecycle-hooks.ts +706 -0
- package/src/control-plane/session-summary.ts +380 -0
- package/src/control-plane/status/agent-status-reducer.ts +21 -0
- package/src/control-plane/status/reducer-base.ts +170 -0
- package/src/control-plane/status/reducers/claude-status-reducer.ts +37 -0
- package/src/control-plane/status/reducers/codex-status-reducer.ts +48 -0
- package/src/control-plane/status/reducers/critique-status-reducer.ts +15 -0
- package/src/control-plane/status/reducers/cursor-status-reducer.ts +37 -0
- package/src/control-plane/status/reducers/terminal-status-reducer.ts +15 -0
- package/src/control-plane/status/session-status-engine.ts +76 -0
- package/src/control-plane/stream-client.ts +396 -0
- package/src/control-plane/stream-command-parser.ts +1673 -0
- package/src/control-plane/stream-protocol.ts +1808 -0
- package/src/control-plane/stream-server-background.ts +486 -0
- package/src/control-plane/stream-server-command.ts +2557 -0
- package/src/control-plane/stream-server-connection.ts +234 -0
- package/src/control-plane/stream-server-observed-filter.ts +112 -0
- package/src/control-plane/stream-server-session-runtime.ts +566 -0
- package/src/control-plane/stream-server-state-store.ts +15 -0
- package/src/control-plane/stream-server.ts +3192 -0
- package/src/cursor/managed-hooks.ts +282 -0
- package/src/domain/conversations.ts +414 -0
- package/src/domain/directories.ts +78 -0
- package/src/domain/repositories.ts +123 -0
- package/src/domain/tasks.ts +148 -0
- package/src/domain/workspace.ts +156 -0
- package/src/events/normalized-events.ts +124 -0
- package/src/mux/ansi-integrity.ts +103 -0
- package/src/mux/control-plane-op-queue.ts +212 -0
- package/src/mux/conversation-rail.ts +339 -0
- package/src/mux/double-click.ts +78 -0
- package/src/mux/dual-pane-core.ts +435 -0
- package/src/mux/harness-core-ui.ts +817 -0
- package/src/mux/input-shortcuts.ts +667 -0
- package/src/mux/live-mux/actions-conversation.ts +344 -0
- package/src/mux/live-mux/actions-repository.ts +246 -0
- package/src/mux/live-mux/actions-task.ts +115 -0
- package/src/mux/live-mux/args.ts +142 -0
- package/src/mux/live-mux/command-menu.ts +298 -0
- package/src/mux/live-mux/control-plane-records.ts +546 -0
- package/src/mux/live-mux/conversation-state.ts +188 -0
- package/src/mux/live-mux/directory-resolution.ts +34 -0
- package/src/mux/live-mux/event-mapping.ts +96 -0
- package/src/mux/live-mux/gateway-profiler.ts +152 -0
- package/src/mux/live-mux/gateway-render-trace.ts +177 -0
- package/src/mux/live-mux/gateway-status-timeline.ts +166 -0
- package/src/mux/live-mux/git-parsing.ts +131 -0
- package/src/mux/live-mux/git-snapshot.ts +263 -0
- package/src/mux/live-mux/git-state.ts +136 -0
- package/src/mux/live-mux/global-shortcut-handlers.ts +143 -0
- package/src/mux/live-mux/home-pane-actions.ts +58 -0
- package/src/mux/live-mux/home-pane-drop.ts +44 -0
- package/src/mux/live-mux/home-pane-entity-click.ts +96 -0
- package/src/mux/live-mux/home-pane-pointer.ts +96 -0
- package/src/mux/live-mux/input-forwarding.ts +112 -0
- package/src/mux/live-mux/layout.ts +30 -0
- package/src/mux/live-mux/left-nav-activation.ts +103 -0
- package/src/mux/live-mux/left-nav.ts +85 -0
- package/src/mux/live-mux/left-rail-actions.ts +118 -0
- package/src/mux/live-mux/left-rail-conversation-click.ts +82 -0
- package/src/mux/live-mux/left-rail-pointer.ts +74 -0
- package/src/mux/live-mux/modal-command-menu-handler.ts +101 -0
- package/src/mux/live-mux/modal-conversation-handlers.ts +217 -0
- package/src/mux/live-mux/modal-input-reducers.ts +94 -0
- package/src/mux/live-mux/modal-overlays.ts +287 -0
- package/src/mux/live-mux/modal-pointer.ts +70 -0
- package/src/mux/live-mux/modal-prompt-handlers.ts +187 -0
- package/src/mux/live-mux/modal-task-editor-handler.ts +156 -0
- package/src/mux/live-mux/observed-stream.ts +87 -0
- package/src/mux/live-mux/palette-parsing.ts +128 -0
- package/src/mux/live-mux/pointer-routing.ts +108 -0
- package/src/mux/live-mux/process-usage.ts +53 -0
- package/src/mux/live-mux/project-pane-pointer.ts +44 -0
- package/src/mux/live-mux/rail-layout.ts +244 -0
- package/src/mux/live-mux/render-trace-analysis.ts +213 -0
- package/src/mux/live-mux/render-trace-state.ts +84 -0
- package/src/mux/live-mux/repository-folding.ts +207 -0
- package/src/mux/live-mux/runtime-shutdown.ts +51 -0
- package/src/mux/live-mux/selection.ts +411 -0
- package/src/mux/live-mux/startup-utils.ts +187 -0
- package/src/mux/live-mux/status-timeline-state.ts +82 -0
- package/src/mux/live-mux/task-pane-shortcuts.ts +206 -0
- package/src/mux/live-mux/terminal-palette.ts +79 -0
- package/src/mux/new-thread-prompt.ts +165 -0
- package/src/mux/project-tree.ts +295 -0
- package/src/mux/render-frame.ts +113 -0
- package/src/mux/runtime-wiring.ts +185 -0
- package/src/mux/selector-index.ts +160 -0
- package/src/mux/startup-sequencer.ts +238 -0
- package/src/mux/task-composer.ts +289 -0
- package/src/mux/task-focused-pane.ts +417 -0
- package/src/mux/task-screen-keybindings.ts +539 -0
- package/src/mux/terminal-input-modes.ts +35 -0
- package/src/mux/workspace-path.ts +55 -0
- package/src/mux/workspace-rail-model.ts +701 -0
- package/src/mux/workspace-rail.ts +247 -0
- package/src/perf/perf-core.ts +307 -0
- package/src/pty/pty_host.ts +217 -0
- package/src/pty/session-broker.ts +158 -0
- package/src/recording/terminal-recording.ts +383 -0
- package/src/services/control-plane.ts +567 -0
- package/src/services/conversation-lifecycle.ts +176 -0
- package/src/services/conversation-startup-hydration.ts +47 -0
- package/src/services/directory-hydration.ts +49 -0
- package/src/services/event-persistence.ts +104 -0
- package/src/services/mux-ui-state-persistence.ts +82 -0
- package/src/services/output-load-sampler.ts +231 -0
- package/src/services/process-usage-refresh.ts +88 -0
- package/src/services/recording.ts +75 -0
- package/src/services/render-trace-recorder.ts +177 -0
- package/src/services/runtime-control-actions.ts +123 -0
- package/src/services/runtime-control-plane-ops.ts +131 -0
- package/src/services/runtime-conversation-actions.ts +113 -0
- package/src/services/runtime-conversation-activation.ts +78 -0
- package/src/services/runtime-conversation-starter.ts +171 -0
- package/src/services/runtime-conversation-title-edit.ts +149 -0
- package/src/services/runtime-directory-actions.ts +164 -0
- package/src/services/runtime-envelope-handler.ts +198 -0
- package/src/services/runtime-git-state.ts +92 -0
- package/src/services/runtime-input-pipeline.ts +50 -0
- package/src/services/runtime-input-router.ts +202 -0
- package/src/services/runtime-layout-resize.ts +236 -0
- package/src/services/runtime-left-rail-render.ts +159 -0
- package/src/services/runtime-main-pane-input.ts +230 -0
- package/src/services/runtime-modal-input.ts +119 -0
- package/src/services/runtime-navigation-input.ts +207 -0
- package/src/services/runtime-process-wiring.ts +68 -0
- package/src/services/runtime-rail-input.ts +287 -0
- package/src/services/runtime-render-flush.ts +146 -0
- package/src/services/runtime-render-lifecycle.ts +104 -0
- package/src/services/runtime-render-orchestrator.ts +108 -0
- package/src/services/runtime-render-pipeline.ts +167 -0
- package/src/services/runtime-render-state.ts +72 -0
- package/src/services/runtime-repository-actions.ts +197 -0
- package/src/services/runtime-right-pane-render.ts +132 -0
- package/src/services/runtime-shutdown.ts +79 -0
- package/src/services/runtime-stream-subscriptions.ts +56 -0
- package/src/services/runtime-task-composer-persistence.ts +139 -0
- package/src/services/runtime-task-editor-actions.ts +83 -0
- package/src/services/runtime-task-pane-actions.ts +198 -0
- package/src/services/runtime-task-pane-shortcuts.ts +189 -0
- package/src/services/runtime-task-pane.ts +62 -0
- package/src/services/runtime-workspace-actions.ts +153 -0
- package/src/services/runtime-workspace-observed-events.ts +190 -0
- package/src/services/session-projection-instrumentation.ts +190 -0
- package/src/services/startup-background-probe.ts +91 -0
- package/src/services/startup-background-resume.ts +65 -0
- package/src/services/startup-orchestrator.ts +166 -0
- package/src/services/startup-output-tracker.ts +54 -0
- package/src/services/startup-paint-tracker.ts +115 -0
- package/src/services/startup-persisted-conversation-queue.ts +45 -0
- package/src/services/startup-settled-gate.ts +67 -0
- package/src/services/startup-shutdown.ts +53 -0
- package/src/services/startup-span-tracker.ts +77 -0
- package/src/services/startup-state-hydration.ts +94 -0
- package/src/services/startup-visibility.ts +35 -0
- package/src/services/status-timeline-recorder.ts +144 -0
- package/src/services/task-pane-selection-actions.ts +153 -0
- package/src/services/task-planning-hydration.ts +58 -0
- package/src/services/task-planning-observed-events.ts +89 -0
- package/src/services/workspace-observed-events.ts +113 -0
- package/src/store/control-plane-store-normalize.ts +760 -0
- package/src/store/control-plane-store-types.ts +224 -0
- package/src/store/control-plane-store.ts +2951 -0
- package/src/store/event-store.ts +253 -0
- package/src/store/sqlite.ts +81 -0
- package/src/terminal/compat-matrix.ts +345 -0
- package/src/terminal/differential-checkpoints.ts +132 -0
- package/src/terminal/parity-suite.ts +441 -0
- package/src/terminal/snapshot-oracle.ts +1840 -0
- package/src/ui/conversation-input-forwarder.ts +114 -0
- package/src/ui/conversation-selection-input.ts +103 -0
- package/src/ui/debug-footer-notice.ts +39 -0
- package/src/ui/global-shortcut-input.ts +126 -0
- package/src/ui/input-preflight.ts +68 -0
- package/src/ui/input-token-router.ts +312 -0
- package/src/ui/input.ts +238 -0
- package/src/ui/kit.ts +509 -0
- package/src/ui/left-nav-input.ts +80 -0
- package/src/ui/left-rail-pointer-input.ts +148 -0
- package/src/ui/main-pane-pointer-input.ts +150 -0
- package/src/ui/modals/manager.ts +192 -0
- package/src/ui/mux-theme.ts +529 -0
- package/src/ui/panes/conversation.ts +19 -0
- package/src/ui/panes/home-gridfire.ts +302 -0
- package/src/ui/panes/home.ts +109 -0
- package/src/ui/panes/left-rail.ts +12 -0
- package/src/ui/panes/project.ts +44 -0
- package/src/ui/pointer-routing-input.ts +158 -0
- package/src/ui/repository-fold-input.ts +91 -0
- package/src/ui/screen.ts +210 -0
- package/src/ui/surface.ts +224 -0
|
@@ -0,0 +1,253 @@
|
|
|
1
|
+
import { DatabaseSync } from './sqlite.ts';
|
|
2
|
+
import { mkdirSync } from 'node:fs';
|
|
3
|
+
import { dirname } from 'node:path';
|
|
4
|
+
import type { NormalizedEventEnvelope } from '../events/normalized-events.ts';
|
|
5
|
+
|
|
6
|
+
interface EventRow {
|
|
7
|
+
rowId: number;
|
|
8
|
+
tenantId: string;
|
|
9
|
+
userId: string;
|
|
10
|
+
workspaceId: string;
|
|
11
|
+
worktreeId: string;
|
|
12
|
+
conversationId: string;
|
|
13
|
+
turnId: string | null;
|
|
14
|
+
eventId: string;
|
|
15
|
+
source: string;
|
|
16
|
+
eventType: string;
|
|
17
|
+
ts: string;
|
|
18
|
+
payloadJson: string;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
interface EventQuery {
|
|
22
|
+
tenantId: string;
|
|
23
|
+
userId: string;
|
|
24
|
+
conversationId?: string;
|
|
25
|
+
afterRowId?: number;
|
|
26
|
+
limit?: number;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
interface PersistedEvent {
|
|
30
|
+
rowId: number;
|
|
31
|
+
event: NormalizedEventEnvelope;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
function asObject(value: unknown): Record<string, unknown> {
|
|
35
|
+
if (typeof value !== 'object' || value === null) {
|
|
36
|
+
throw new Error('expected object row');
|
|
37
|
+
}
|
|
38
|
+
return value as Record<string, unknown>;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
function asString(value: unknown, field: string): string {
|
|
42
|
+
if (typeof value !== 'string') {
|
|
43
|
+
throw new Error(`expected string for ${field}`);
|
|
44
|
+
}
|
|
45
|
+
return value;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
function asNumber(value: unknown, field: string): number {
|
|
49
|
+
if (typeof value !== 'number') {
|
|
50
|
+
throw new Error(`expected number for ${field}`);
|
|
51
|
+
}
|
|
52
|
+
return value;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
function asStringOrNull(value: unknown, field: string): string | null {
|
|
56
|
+
if (value === null) {
|
|
57
|
+
return null;
|
|
58
|
+
}
|
|
59
|
+
return asString(value, field);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
function normalizeRow(value: unknown): EventRow {
|
|
63
|
+
const row = asObject(value);
|
|
64
|
+
return {
|
|
65
|
+
rowId: asNumber(row.row_id, 'row_id'),
|
|
66
|
+
tenantId: asString(row.tenant_id, 'tenant_id'),
|
|
67
|
+
userId: asString(row.user_id, 'user_id'),
|
|
68
|
+
workspaceId: asString(row.workspace_id, 'workspace_id'),
|
|
69
|
+
worktreeId: asString(row.worktree_id, 'worktree_id'),
|
|
70
|
+
conversationId: asString(row.conversation_id, 'conversation_id'),
|
|
71
|
+
turnId: asStringOrNull(row.turn_id, 'turn_id'),
|
|
72
|
+
eventId: asString(row.event_id, 'event_id'),
|
|
73
|
+
source: asString(row.source, 'source'),
|
|
74
|
+
eventType: asString(row.event_type, 'event_type'),
|
|
75
|
+
ts: asString(row.ts, 'ts'),
|
|
76
|
+
payloadJson: asString(row.payload_json, 'payload_json'),
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
export function normalizeStoredRow(value: unknown): {
|
|
81
|
+
rowId: number;
|
|
82
|
+
tenantId: string;
|
|
83
|
+
userId: string;
|
|
84
|
+
workspaceId: string;
|
|
85
|
+
worktreeId: string;
|
|
86
|
+
conversationId: string;
|
|
87
|
+
turnId: string | null;
|
|
88
|
+
eventId: string;
|
|
89
|
+
source: string;
|
|
90
|
+
eventType: string;
|
|
91
|
+
ts: string;
|
|
92
|
+
payloadJson: string;
|
|
93
|
+
} {
|
|
94
|
+
return normalizeRow(value);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
export class SqliteEventStore {
|
|
98
|
+
private readonly db: DatabaseSync;
|
|
99
|
+
|
|
100
|
+
constructor(filePath = ':memory:') {
|
|
101
|
+
const dbPath = this.preparePath(filePath);
|
|
102
|
+
this.db = new DatabaseSync(dbPath);
|
|
103
|
+
this.configureConnection();
|
|
104
|
+
this.initializeSchema();
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
close(): void {
|
|
108
|
+
this.db.close();
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
appendEvents(events: readonly NormalizedEventEnvelope[]): void {
|
|
112
|
+
if (events.length === 0) {
|
|
113
|
+
return;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
const insertStatement = this.db.prepare(`
|
|
117
|
+
INSERT INTO events (
|
|
118
|
+
tenant_id,
|
|
119
|
+
user_id,
|
|
120
|
+
workspace_id,
|
|
121
|
+
worktree_id,
|
|
122
|
+
conversation_id,
|
|
123
|
+
turn_id,
|
|
124
|
+
event_id,
|
|
125
|
+
source,
|
|
126
|
+
event_type,
|
|
127
|
+
ts,
|
|
128
|
+
payload_json
|
|
129
|
+
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
130
|
+
`);
|
|
131
|
+
|
|
132
|
+
this.db.exec('BEGIN IMMEDIATE TRANSACTION');
|
|
133
|
+
try {
|
|
134
|
+
for (const event of events) {
|
|
135
|
+
insertStatement.run(
|
|
136
|
+
event.scope.tenantId,
|
|
137
|
+
event.scope.userId,
|
|
138
|
+
event.scope.workspaceId,
|
|
139
|
+
event.scope.worktreeId,
|
|
140
|
+
event.scope.conversationId,
|
|
141
|
+
event.scope.turnId ?? null,
|
|
142
|
+
event.eventId,
|
|
143
|
+
event.source,
|
|
144
|
+
event.type,
|
|
145
|
+
event.ts,
|
|
146
|
+
JSON.stringify(event.payload),
|
|
147
|
+
);
|
|
148
|
+
}
|
|
149
|
+
this.db.exec('COMMIT');
|
|
150
|
+
} catch (error) {
|
|
151
|
+
this.db.exec('ROLLBACK');
|
|
152
|
+
throw error;
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
listEvents(query: EventQuery): PersistedEvent[] {
|
|
157
|
+
const limit = query.limit ?? 100;
|
|
158
|
+
const afterRowId = query.afterRowId ?? 0;
|
|
159
|
+
|
|
160
|
+
const clauses = ['tenant_id = ?', 'user_id = ?', 'row_id > ?'];
|
|
161
|
+
const args: Array<number | string> = [query.tenantId, query.userId, afterRowId];
|
|
162
|
+
|
|
163
|
+
if (query.conversationId !== undefined) {
|
|
164
|
+
clauses.push('conversation_id = ?');
|
|
165
|
+
args.push(query.conversationId);
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
const sql = `
|
|
169
|
+
SELECT
|
|
170
|
+
row_id,
|
|
171
|
+
tenant_id,
|
|
172
|
+
user_id,
|
|
173
|
+
workspace_id,
|
|
174
|
+
worktree_id,
|
|
175
|
+
conversation_id,
|
|
176
|
+
turn_id,
|
|
177
|
+
event_id,
|
|
178
|
+
source,
|
|
179
|
+
event_type,
|
|
180
|
+
ts,
|
|
181
|
+
payload_json
|
|
182
|
+
FROM events
|
|
183
|
+
WHERE ${clauses.join(' AND ')}
|
|
184
|
+
ORDER BY row_id ASC
|
|
185
|
+
LIMIT ?
|
|
186
|
+
`;
|
|
187
|
+
args.push(limit);
|
|
188
|
+
|
|
189
|
+
const rows = this.db.prepare(sql).all(...args);
|
|
190
|
+
return rows.map((row) => {
|
|
191
|
+
const normalizedRow = normalizeStoredRow(row);
|
|
192
|
+
const payload = JSON.parse(normalizedRow.payloadJson) as NormalizedEventEnvelope['payload'];
|
|
193
|
+
const event: NormalizedEventEnvelope = {
|
|
194
|
+
schemaVersion: '1',
|
|
195
|
+
eventId: normalizedRow.eventId,
|
|
196
|
+
source: normalizedRow.source as NormalizedEventEnvelope['source'],
|
|
197
|
+
type: normalizedRow.eventType as NormalizedEventEnvelope['type'],
|
|
198
|
+
ts: normalizedRow.ts,
|
|
199
|
+
scope: {
|
|
200
|
+
tenantId: normalizedRow.tenantId,
|
|
201
|
+
userId: normalizedRow.userId,
|
|
202
|
+
workspaceId: normalizedRow.workspaceId,
|
|
203
|
+
worktreeId: normalizedRow.worktreeId,
|
|
204
|
+
conversationId: normalizedRow.conversationId,
|
|
205
|
+
...(normalizedRow.turnId === null ? {} : { turnId: normalizedRow.turnId }),
|
|
206
|
+
},
|
|
207
|
+
payload,
|
|
208
|
+
};
|
|
209
|
+
return {
|
|
210
|
+
rowId: normalizedRow.rowId,
|
|
211
|
+
event,
|
|
212
|
+
};
|
|
213
|
+
});
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
private initializeSchema(): void {
|
|
217
|
+
this.db.exec(`
|
|
218
|
+
CREATE TABLE IF NOT EXISTS events (
|
|
219
|
+
row_id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
220
|
+
tenant_id TEXT NOT NULL,
|
|
221
|
+
user_id TEXT NOT NULL,
|
|
222
|
+
workspace_id TEXT NOT NULL,
|
|
223
|
+
worktree_id TEXT NOT NULL,
|
|
224
|
+
conversation_id TEXT NOT NULL,
|
|
225
|
+
turn_id TEXT,
|
|
226
|
+
event_id TEXT NOT NULL UNIQUE,
|
|
227
|
+
source TEXT NOT NULL,
|
|
228
|
+
event_type TEXT NOT NULL,
|
|
229
|
+
ts TEXT NOT NULL,
|
|
230
|
+
payload_json TEXT NOT NULL
|
|
231
|
+
);
|
|
232
|
+
`);
|
|
233
|
+
this.db.exec(`
|
|
234
|
+
CREATE INDEX IF NOT EXISTS idx_events_scope_cursor
|
|
235
|
+
ON events (tenant_id, user_id, conversation_id, row_id);
|
|
236
|
+
`);
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
private configureConnection(): void {
|
|
240
|
+
this.db.exec('PRAGMA journal_mode = WAL;');
|
|
241
|
+
this.db.exec('PRAGMA synchronous = NORMAL;');
|
|
242
|
+
this.db.exec('PRAGMA busy_timeout = 2000;');
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
private preparePath(filePath: string): string {
|
|
246
|
+
if (filePath === ':memory:') {
|
|
247
|
+
return filePath;
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
mkdirSync(dirname(filePath), { recursive: true });
|
|
251
|
+
return filePath;
|
|
252
|
+
}
|
|
253
|
+
}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import { createRequire } from 'node:module';
|
|
2
|
+
|
|
3
|
+
interface StatementLike {
|
|
4
|
+
run: (...params: unknown[]) => unknown;
|
|
5
|
+
get: (...params: unknown[]) => unknown;
|
|
6
|
+
all: (...params: unknown[]) => unknown[];
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
class WrappedStatement {
|
|
10
|
+
private readonly statement: StatementLike;
|
|
11
|
+
|
|
12
|
+
constructor(statement: StatementLike) {
|
|
13
|
+
this.statement = statement;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
run(...params: unknown[]): unknown {
|
|
17
|
+
return this.statement.run(...params);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
get(...params: unknown[]): unknown {
|
|
21
|
+
const value = this.statement.get(...params);
|
|
22
|
+
return value === null ? undefined : value;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
all(...params: unknown[]): unknown[] {
|
|
26
|
+
return this.statement.all(...params);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
interface SqliteDatabaseLike {
|
|
31
|
+
close: () => void;
|
|
32
|
+
exec: (sql: string) => unknown;
|
|
33
|
+
prepare: (sql: string) => StatementLike;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
type BunSqliteModule = {
|
|
37
|
+
Database: new (path: string) => SqliteDatabaseLike;
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
const require = createRequire(import.meta.url);
|
|
41
|
+
|
|
42
|
+
interface SqliteRuntime {
|
|
43
|
+
readonly bunVersion: string | undefined;
|
|
44
|
+
readonly loadModule: (specifier: 'bun:sqlite') => unknown;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
const defaultRuntime: SqliteRuntime = {
|
|
48
|
+
bunVersion: process.versions.bun,
|
|
49
|
+
loadModule: (specifier) => require(specifier) as unknown,
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
export function createDatabaseForRuntime(
|
|
53
|
+
path: string,
|
|
54
|
+
runtime: SqliteRuntime = defaultRuntime,
|
|
55
|
+
): SqliteDatabaseLike {
|
|
56
|
+
if (runtime.bunVersion === undefined) {
|
|
57
|
+
throw new Error('bun runtime is required for sqlite access');
|
|
58
|
+
}
|
|
59
|
+
const module = runtime.loadModule('bun:sqlite') as BunSqliteModule;
|
|
60
|
+
return new module.Database(path);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
export class DatabaseSync {
|
|
64
|
+
private readonly database: SqliteDatabaseLike;
|
|
65
|
+
|
|
66
|
+
constructor(path: string, runtime: SqliteRuntime = defaultRuntime) {
|
|
67
|
+
this.database = createDatabaseForRuntime(path, runtime);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
close(): void {
|
|
71
|
+
this.database.close();
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
exec(sql: string): void {
|
|
75
|
+
this.database.exec(sql);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
prepare(sql: string): WrappedStatement {
|
|
79
|
+
return new WrappedStatement(this.database.prepare(sql));
|
|
80
|
+
}
|
|
81
|
+
}
|
|
@@ -0,0 +1,345 @@
|
|
|
1
|
+
export type TerminalCompatLevelStatus = 'complete' | 'in-progress' | 'planned';
|
|
2
|
+
|
|
3
|
+
export type TerminalCompatEntryStatus = 'implemented' | 'passthrough' | 'unsupported';
|
|
4
|
+
|
|
5
|
+
export type TerminalCompatPriority = 'p0-codex-vim' | 'p1-important' | 'p2-optional';
|
|
6
|
+
|
|
7
|
+
export type TerminalCompatLevelId =
|
|
8
|
+
| 'l0-grammar-core'
|
|
9
|
+
| 'l1-screen-state'
|
|
10
|
+
| 'l2-dec-modes'
|
|
11
|
+
| 'l3-query-reply'
|
|
12
|
+
| 'l4-unicode-fidelity'
|
|
13
|
+
| 'l5-external-diff'
|
|
14
|
+
| 'l6-modern-extensions';
|
|
15
|
+
|
|
16
|
+
export interface TerminalCompatLevel {
|
|
17
|
+
readonly id: TerminalCompatLevelId;
|
|
18
|
+
readonly title: string;
|
|
19
|
+
readonly gate: string;
|
|
20
|
+
readonly status: TerminalCompatLevelStatus;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export interface TerminalCompatEntry {
|
|
24
|
+
readonly id: string;
|
|
25
|
+
readonly levelId: TerminalCompatLevelId;
|
|
26
|
+
readonly feature: string;
|
|
27
|
+
readonly sequences: readonly string[];
|
|
28
|
+
readonly status: TerminalCompatEntryStatus;
|
|
29
|
+
readonly priority: TerminalCompatPriority;
|
|
30
|
+
readonly ownerTests: readonly string[];
|
|
31
|
+
readonly notes: string;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export const TERMINAL_COMPAT_CHECKPOINT_DATE = '2026-02-19';
|
|
35
|
+
|
|
36
|
+
export const TERMINAL_COMPAT_LEVELS: readonly TerminalCompatLevel[] = [
|
|
37
|
+
{
|
|
38
|
+
id: 'l0-grammar-core',
|
|
39
|
+
title: 'Grammar + Core Controls',
|
|
40
|
+
gate: 'Stable parser framing for ESC/CSI/OSC/DCS plus core control-flow semantics.',
|
|
41
|
+
status: 'complete',
|
|
42
|
+
},
|
|
43
|
+
{
|
|
44
|
+
id: 'l1-screen-state',
|
|
45
|
+
title: 'Screen State Model',
|
|
46
|
+
gate: 'Deterministic snapshots for cursor, viewport, color/style, wrap, and scrollback.',
|
|
47
|
+
status: 'complete',
|
|
48
|
+
},
|
|
49
|
+
{
|
|
50
|
+
id: 'l2-dec-modes',
|
|
51
|
+
title: 'DEC TUI Modes',
|
|
52
|
+
gate: 'Codex/Vim-critical DEC private modes are implemented and parity tested.',
|
|
53
|
+
status: 'in-progress',
|
|
54
|
+
},
|
|
55
|
+
{
|
|
56
|
+
id: 'l3-query-reply',
|
|
57
|
+
title: 'Query + Reply Engine',
|
|
58
|
+
gate: 'Deterministic DA/DSR/OSC/keyboard replies for runtime negotiation and probing.',
|
|
59
|
+
status: 'in-progress',
|
|
60
|
+
},
|
|
61
|
+
{
|
|
62
|
+
id: 'l4-unicode-fidelity',
|
|
63
|
+
title: 'Unicode Fidelity',
|
|
64
|
+
gate: 'Display width, combining, and grapheme behavior stay stable under resize/wrap/edit.',
|
|
65
|
+
status: 'in-progress',
|
|
66
|
+
},
|
|
67
|
+
{
|
|
68
|
+
id: 'l5-external-diff',
|
|
69
|
+
title: 'External + Differential Conformance',
|
|
70
|
+
gate: 'vttest and direct-terminal differential checkpoints are automated and blocking.',
|
|
71
|
+
status: 'planned',
|
|
72
|
+
},
|
|
73
|
+
{
|
|
74
|
+
id: 'l6-modern-extensions',
|
|
75
|
+
title: 'Modern Extensions',
|
|
76
|
+
gate: 'Intentional extension set (hyperlinks/graphics/sync output) is explicit and tested.',
|
|
77
|
+
status: 'planned',
|
|
78
|
+
},
|
|
79
|
+
] as const;
|
|
80
|
+
|
|
81
|
+
export const TERMINAL_COMPAT_MATRIX: readonly TerminalCompatEntry[] = [
|
|
82
|
+
{
|
|
83
|
+
id: 'c0-basic-controls',
|
|
84
|
+
levelId: 'l0-grammar-core',
|
|
85
|
+
feature: 'C0 handling for LF/CR/BS/TAB and print filtering',
|
|
86
|
+
sequences: ['LF', 'CR', 'BS', 'TAB'],
|
|
87
|
+
status: 'implemented',
|
|
88
|
+
priority: 'p0-codex-vim',
|
|
89
|
+
ownerTests: ['test/terminal-snapshot-oracle.test.ts', 'test/terminal-parity-suite.test.ts'],
|
|
90
|
+
notes: 'Core movement and wrapping behavior is covered in snapshot/parity tests.',
|
|
91
|
+
},
|
|
92
|
+
{
|
|
93
|
+
id: 'esc-csi-framing',
|
|
94
|
+
levelId: 'l0-grammar-core',
|
|
95
|
+
feature: 'ESC and CSI parser state machine framing',
|
|
96
|
+
sequences: ['ESC', 'CSI ... final-byte'],
|
|
97
|
+
status: 'implemented',
|
|
98
|
+
priority: 'p0-codex-vim',
|
|
99
|
+
ownerTests: ['test/terminal-snapshot-oracle.test.ts'],
|
|
100
|
+
notes: 'Supports interrupted CSI streams and state resets.',
|
|
101
|
+
},
|
|
102
|
+
{
|
|
103
|
+
id: 'osc-framing-bel-st',
|
|
104
|
+
levelId: 'l0-grammar-core',
|
|
105
|
+
feature: 'OSC parsing with BEL and ST terminators',
|
|
106
|
+
sequences: ['OSC ... BEL', 'OSC ... ST'],
|
|
107
|
+
status: 'passthrough',
|
|
108
|
+
priority: 'p1-important',
|
|
109
|
+
ownerTests: ['test/codex-live-session.test.ts'],
|
|
110
|
+
notes: 'Parsed and routed to query hooks; display-state effects are intentionally minimal.',
|
|
111
|
+
},
|
|
112
|
+
{
|
|
113
|
+
id: 'dcs-framing-st',
|
|
114
|
+
levelId: 'l0-grammar-core',
|
|
115
|
+
feature: 'DCS parsing with ST terminator',
|
|
116
|
+
sequences: ['DCS ... ST'],
|
|
117
|
+
status: 'passthrough',
|
|
118
|
+
priority: 'p1-important',
|
|
119
|
+
ownerTests: ['test/codex-live-session.test.ts'],
|
|
120
|
+
notes: 'Observed for telemetry/query handling; not interpreted into render-state changes.',
|
|
121
|
+
},
|
|
122
|
+
{
|
|
123
|
+
id: 'cursor-erase-moves',
|
|
124
|
+
levelId: 'l1-screen-state',
|
|
125
|
+
feature: 'Cursor addressing and erase semantics',
|
|
126
|
+
sequences: ['CSI A/B/C/D', 'CSI G', 'CSI H/f', 'CSI J', 'CSI K'],
|
|
127
|
+
status: 'implemented',
|
|
128
|
+
priority: 'p0-codex-vim',
|
|
129
|
+
ownerTests: ['test/terminal-snapshot-oracle.test.ts'],
|
|
130
|
+
notes: 'Cursor and clear operations are part of canonical snapshot hashing.',
|
|
131
|
+
},
|
|
132
|
+
{
|
|
133
|
+
id: 'line-char-editing',
|
|
134
|
+
levelId: 'l1-screen-state',
|
|
135
|
+
feature: 'Line/char insert-delete and regional scroll operations',
|
|
136
|
+
sequences: ['CSI L', 'CSI M', 'CSI @', 'CSI P', 'CSI S', 'CSI T'],
|
|
137
|
+
status: 'implemented',
|
|
138
|
+
priority: 'p0-codex-vim',
|
|
139
|
+
ownerTests: ['test/terminal-snapshot-oracle.test.ts', 'test/terminal-parity-suite.test.ts'],
|
|
140
|
+
notes: 'Hot-path edit operations are validated with parity scenes.',
|
|
141
|
+
},
|
|
142
|
+
{
|
|
143
|
+
id: 'sgr-color-style',
|
|
144
|
+
levelId: 'l1-screen-state',
|
|
145
|
+
feature: 'SGR color/style for default, indexed, and truecolor',
|
|
146
|
+
sequences: ['CSI ... m', '38;5;n', '48;5;n', '38;2;r;g;b', '48;2;r;g;b'],
|
|
147
|
+
status: 'implemented',
|
|
148
|
+
priority: 'p0-codex-vim',
|
|
149
|
+
ownerTests: ['test/terminal-snapshot-oracle.test.ts', 'test/terminal-parity-suite.test.ts'],
|
|
150
|
+
notes: 'Style diff and terminal GIF rendering consume this snapshot model directly.',
|
|
151
|
+
},
|
|
152
|
+
{
|
|
153
|
+
id: 'wrap-scrollback-viewport',
|
|
154
|
+
levelId: 'l1-screen-state',
|
|
155
|
+
feature: 'Pending-wrap, scrollback retention, and viewport follow behavior',
|
|
156
|
+
sequences: ['autowrap', 'linefeed at margins', 'viewport scroll controls'],
|
|
157
|
+
status: 'implemented',
|
|
158
|
+
priority: 'p0-codex-vim',
|
|
159
|
+
ownerTests: [
|
|
160
|
+
'test/terminal-snapshot-oracle.test.ts',
|
|
161
|
+
'test/ui-selection-copy-scrollback.integration.test.ts',
|
|
162
|
+
],
|
|
163
|
+
notes: 'Selection and copy behavior depend on deterministic buffer indexing.',
|
|
164
|
+
},
|
|
165
|
+
{
|
|
166
|
+
id: 'dec-origin-scroll-region',
|
|
167
|
+
levelId: 'l2-dec-modes',
|
|
168
|
+
feature: 'DEC origin mode + scroll region correctness',
|
|
169
|
+
sequences: ['CSI ? 6 h/l', 'CSI r', 'ESC M'],
|
|
170
|
+
status: 'implemented',
|
|
171
|
+
priority: 'p0-codex-vim',
|
|
172
|
+
ownerTests: ['test/terminal-snapshot-oracle.test.ts', 'test/terminal-parity-suite.test.ts'],
|
|
173
|
+
notes: 'Pinned footer + Vim reverse-index flows rely on this behavior.',
|
|
174
|
+
},
|
|
175
|
+
{
|
|
176
|
+
id: 'dec-alt-screen-save-restore',
|
|
177
|
+
levelId: 'l2-dec-modes',
|
|
178
|
+
feature: 'Alternate screen and cursor save/restore',
|
|
179
|
+
sequences: ['CSI ? 1047 h/l', 'CSI ? 1048 h/l', 'CSI ? 1049 h/l', 'ESC 7', 'ESC 8'],
|
|
180
|
+
status: 'implemented',
|
|
181
|
+
priority: 'p0-codex-vim',
|
|
182
|
+
ownerTests: ['test/terminal-snapshot-oracle.test.ts'],
|
|
183
|
+
notes: 'Codex/Vim mode switches depend on stable alt-screen transitions.',
|
|
184
|
+
},
|
|
185
|
+
{
|
|
186
|
+
id: 'dec-bracketed-paste',
|
|
187
|
+
levelId: 'l2-dec-modes',
|
|
188
|
+
feature: 'Bracketed paste mode tracking',
|
|
189
|
+
sequences: ['CSI ? 2004 h/l'],
|
|
190
|
+
status: 'implemented',
|
|
191
|
+
priority: 'p0-codex-vim',
|
|
192
|
+
ownerTests: ['test/terminal-snapshot-oracle.test.ts'],
|
|
193
|
+
notes: 'Mode state is included in snapshot diff diagnostics.',
|
|
194
|
+
},
|
|
195
|
+
{
|
|
196
|
+
id: 'dec-mouse-focus-tracking',
|
|
197
|
+
levelId: 'l2-dec-modes',
|
|
198
|
+
feature: 'Mouse + focus tracking modes',
|
|
199
|
+
sequences: [
|
|
200
|
+
'CSI ? 1000 h/l',
|
|
201
|
+
'CSI ? 1002 h/l',
|
|
202
|
+
'CSI ? 1003 h/l',
|
|
203
|
+
'CSI ? 1004 h/l',
|
|
204
|
+
'CSI ? 1006 h/l',
|
|
205
|
+
],
|
|
206
|
+
status: 'unsupported',
|
|
207
|
+
priority: 'p0-codex-vim',
|
|
208
|
+
ownerTests: [],
|
|
209
|
+
notes:
|
|
210
|
+
'Required climb item for complex TUI parity; currently not modeled as terminal mode state.',
|
|
211
|
+
},
|
|
212
|
+
{
|
|
213
|
+
id: 'cursor-visibility-style-control',
|
|
214
|
+
levelId: 'l2-dec-modes',
|
|
215
|
+
feature: 'Cursor visibility and DECSCUSR style controls',
|
|
216
|
+
sequences: ['CSI ? 25 h/l', 'CSI Ps SP q'],
|
|
217
|
+
status: 'implemented',
|
|
218
|
+
priority: 'p1-important',
|
|
219
|
+
ownerTests: ['test/terminal-snapshot-oracle.test.ts', 'test/terminal-gif-e2e.test.ts'],
|
|
220
|
+
notes: 'Cursor style stability matters for pseudo-screenshot and GIF tooling.',
|
|
221
|
+
},
|
|
222
|
+
{
|
|
223
|
+
id: 'csi-device-status-replies',
|
|
224
|
+
levelId: 'l3-query-reply',
|
|
225
|
+
feature: 'Device/status query replies',
|
|
226
|
+
sequences: ['CSI c', 'CSI > c', 'CSI 5 n', 'CSI 6 n', 'CSI 14 t', 'CSI 16 t', 'CSI 18 t'],
|
|
227
|
+
status: 'implemented',
|
|
228
|
+
priority: 'p0-codex-vim',
|
|
229
|
+
ownerTests: ['test/codex-live-session.test.ts'],
|
|
230
|
+
notes: 'Handled via terminal query responder with deterministic replies.',
|
|
231
|
+
},
|
|
232
|
+
{
|
|
233
|
+
id: 'keyboard-query-reply-csi-u',
|
|
234
|
+
levelId: 'l3-query-reply',
|
|
235
|
+
feature: 'Keyboard capability query reply surface',
|
|
236
|
+
sequences: ['CSI ? u'],
|
|
237
|
+
status: 'implemented',
|
|
238
|
+
priority: 'p1-important',
|
|
239
|
+
ownerTests: ['test/codex-live-session.test.ts'],
|
|
240
|
+
notes: 'Query path is implemented; full negotiate/enable matrix remains open.',
|
|
241
|
+
},
|
|
242
|
+
{
|
|
243
|
+
id: 'osc-color-queries',
|
|
244
|
+
levelId: 'l3-query-reply',
|
|
245
|
+
feature: 'OSC terminal color query replies',
|
|
246
|
+
sequences: ['OSC 10 ; ?', 'OSC 11 ; ?', 'OSC 4 ; index ; ?'],
|
|
247
|
+
status: 'implemented',
|
|
248
|
+
priority: 'p1-important',
|
|
249
|
+
ownerTests: ['test/codex-live-session.test.ts', 'test/mux-live-mux-terminal-palette.test.ts'],
|
|
250
|
+
notes: 'Palette replies are deterministic and mapped from config/theme colors.',
|
|
251
|
+
},
|
|
252
|
+
{
|
|
253
|
+
id: 'modifyotherkeys-negotiation',
|
|
254
|
+
levelId: 'l3-query-reply',
|
|
255
|
+
feature: 'modifyOtherKeys and CSI-u negotiation/enable flows',
|
|
256
|
+
sequences: ['CSI > 4 ; ... m', 'CSI > u', 'CSI u protocol enable'],
|
|
257
|
+
status: 'implemented',
|
|
258
|
+
priority: 'p0-codex-vim',
|
|
259
|
+
ownerTests: ['test/codex-live-session.test.ts', 'test/terminal-snapshot-oracle.test.ts'],
|
|
260
|
+
notes:
|
|
261
|
+
'Negotiation/query state is tracked in the reply engine and ignored by render-state parser paths.',
|
|
262
|
+
},
|
|
263
|
+
{
|
|
264
|
+
id: 'unicode-wide-combining',
|
|
265
|
+
levelId: 'l4-unicode-fidelity',
|
|
266
|
+
feature: 'Wide glyph placement and combining mark attachment',
|
|
267
|
+
sequences: ['double-width glyphs', 'combining code points'],
|
|
268
|
+
status: 'implemented',
|
|
269
|
+
priority: 'p0-codex-vim',
|
|
270
|
+
ownerTests: ['test/terminal-snapshot-oracle.test.ts', 'test/terminal-gif-e2e.test.ts'],
|
|
271
|
+
notes: 'Current width policy is deterministic and used by snapshot hash generation.',
|
|
272
|
+
},
|
|
273
|
+
{
|
|
274
|
+
id: 'unicode-grapheme-clusters',
|
|
275
|
+
levelId: 'l4-unicode-fidelity',
|
|
276
|
+
feature: 'Extended grapheme cluster width behavior',
|
|
277
|
+
sequences: ['ZWJ emoji sequences', 'variation selectors'],
|
|
278
|
+
status: 'unsupported',
|
|
279
|
+
priority: 'p1-important',
|
|
280
|
+
ownerTests: [],
|
|
281
|
+
notes: 'Needs explicit UAX #29 driven tests to avoid width regressions.',
|
|
282
|
+
},
|
|
283
|
+
{
|
|
284
|
+
id: 'vttest-automation',
|
|
285
|
+
levelId: 'l5-external-diff',
|
|
286
|
+
feature: 'Automated vttest conformance suite integration',
|
|
287
|
+
sequences: ['VT100/VT220/xterm selected cases'],
|
|
288
|
+
status: 'unsupported',
|
|
289
|
+
priority: 'p1-important',
|
|
290
|
+
ownerTests: [],
|
|
291
|
+
notes: 'Must be run in CI for the declared supported behavior subset.',
|
|
292
|
+
},
|
|
293
|
+
{
|
|
294
|
+
id: 'differential-terminal-checkpoints',
|
|
295
|
+
levelId: 'l5-external-diff',
|
|
296
|
+
feature: 'Direct-terminal vs harness snapshot differential checks',
|
|
297
|
+
sequences: ['Codex traces', 'Vim traces', 'fixture corpus replay'],
|
|
298
|
+
status: 'unsupported',
|
|
299
|
+
priority: 'p0-codex-vim',
|
|
300
|
+
ownerTests: ['test/terminal-differential-checkpoints.test.ts'],
|
|
301
|
+
notes:
|
|
302
|
+
'Runner exists, but direct-terminal captured fixtures are not wired as a blocking parity corpus yet.',
|
|
303
|
+
},
|
|
304
|
+
{
|
|
305
|
+
id: 'osc-title-cwd-hyperlink',
|
|
306
|
+
levelId: 'l6-modern-extensions',
|
|
307
|
+
feature: 'OSC title/cwd/hyperlink handling',
|
|
308
|
+
sequences: ['OSC 0', 'OSC 1', 'OSC 2', 'OSC 7', 'OSC 8'],
|
|
309
|
+
status: 'unsupported',
|
|
310
|
+
priority: 'p1-important',
|
|
311
|
+
ownerTests: [],
|
|
312
|
+
notes: 'Useful for modern CLI UX; not required for base render-state correctness.',
|
|
313
|
+
},
|
|
314
|
+
{
|
|
315
|
+
id: 'sync-output-mode',
|
|
316
|
+
levelId: 'l6-modern-extensions',
|
|
317
|
+
feature: 'Synchronized output mode',
|
|
318
|
+
sequences: ['CSI ? 2026 h/l'],
|
|
319
|
+
status: 'unsupported',
|
|
320
|
+
priority: 'p2-optional',
|
|
321
|
+
ownerTests: [],
|
|
322
|
+
notes: 'Optional performance/stability enhancement for bursty render workloads.',
|
|
323
|
+
},
|
|
324
|
+
{
|
|
325
|
+
id: 'graphics-protocols',
|
|
326
|
+
levelId: 'l6-modern-extensions',
|
|
327
|
+
feature: 'Inline graphics protocols',
|
|
328
|
+
sequences: ['SIXEL', 'kitty graphics'],
|
|
329
|
+
status: 'unsupported',
|
|
330
|
+
priority: 'p2-optional',
|
|
331
|
+
ownerTests: [],
|
|
332
|
+
notes: 'Out of current scope; keep explicit as intentionally unsupported.',
|
|
333
|
+
},
|
|
334
|
+
{
|
|
335
|
+
id: 'keyboard-encoding-ingress',
|
|
336
|
+
levelId: 'l6-modern-extensions',
|
|
337
|
+
feature: 'Kitty/modifyOtherKeys input decoding for client hotkeys',
|
|
338
|
+
sequences: ['CSI ... u', 'CSI 27 ; ... ~'],
|
|
339
|
+
status: 'implemented',
|
|
340
|
+
priority: 'p1-important',
|
|
341
|
+
ownerTests: ['test/mux-input-shortcuts.test.ts', 'test/task-screen-keybindings.test.ts'],
|
|
342
|
+
notes:
|
|
343
|
+
'Ingress decode parity is implemented for shortcuts; terminal-side negotiation is separate.',
|
|
344
|
+
},
|
|
345
|
+
] as const;
|