@devflow-tools/database 0.17.8 → 0.18.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/dist/data/LocalDataProvider.d.ts +63 -0
- package/dist/data/LocalDataProvider.js +332 -0
- package/dist/data/default-enforcer-rules.d.ts +3 -0
- package/dist/data/default-enforcer-rules.js +170 -0
- package/dist/data/devflow-schema.d.ts +2 -0
- package/dist/data/devflow-schema.js +80 -0
- package/dist/database.d.ts +45 -7
- package/dist/database.js +583 -125
- package/dist/index.d.ts +8 -4
- package/dist/index.js +11 -5
- package/dist/retrieval-ledger.d.ts +16 -1
- package/dist/retrieval-ledger.js +6 -0
- package/dist/retrieval-runtime.d.ts +39 -0
- package/dist/retrieval-runtime.js +2 -0
- package/dist/task-aggregate.d.ts +49 -0
- package/dist/task-aggregate.js +2 -0
- package/dist/task-semantic-control.d.ts +8 -1
- package/dist/task-semantic-control.js +2 -4
- package/package.json +15 -3
- package/CHANGELOG.md +0 -844
- package/__tests__/database.failure-category.test.ts +0 -44
- package/__tests__/database.host-actions.test.ts +0 -405
- package/__tests__/database.learning-candidates.test.ts +0 -93
- package/__tests__/database.memory-turn-receipts.test.ts +0 -98
- package/__tests__/database.retrieval-ledger.test.ts +0 -68
- package/__tests__/database.retrieval-sessions.test.ts +0 -79
- package/__tests__/database.semantic-resolution.test.ts +0 -87
- package/__tests__/database.skill-executions.test.ts +0 -456
- package/__tests__/database.task-runtime.test.ts +0 -73
- package/__tests__/database.test.ts +0 -177
- package/__tests__/database.work-queue.test.ts +0 -274
- package/__tests__/database.workflow-workers.test.ts +0 -60
- package/__tests__/node-sqlite.test.ts +0 -68
- package/src/database.ts +0 -5853
- package/src/host-actions.ts +0 -211
- package/src/index.ts +0 -153
- package/src/learning-candidates.ts +0 -181
- package/src/node-sqlite.ts +0 -60
- package/src/obligation-ledger.ts +0 -57
- package/src/retrieval-ledger.ts +0 -35
- package/src/retrieval-sessions.ts +0 -196
- package/src/semantic-resolution.ts +0 -181
- package/src/task-runtime.ts +0 -169
- package/src/task-semantic-control.ts +0 -270
- package/src/types.ts +0 -17
- package/src/work-queue.ts +0 -123
- package/src/workflow-workers.ts +0 -198
- package/tsconfig.json +0 -19
- package/tsconfig.tsbuildinfo +0 -1
- package/vitest.config.ts +0 -41
|
@@ -1,270 +0,0 @@
|
|
|
1
|
-
export interface TaskIdentityRecord {
|
|
2
|
-
projectRoot: string;
|
|
3
|
-
projectId: string;
|
|
4
|
-
hostId: string;
|
|
5
|
-
sessionId: string;
|
|
6
|
-
turnId: string;
|
|
7
|
-
requestId: string;
|
|
8
|
-
executionId?: string;
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
export interface TaskIntentArtifactRecord extends TaskIdentityRecord {
|
|
12
|
-
version: number;
|
|
13
|
-
supersedesHash?: string;
|
|
14
|
-
rawPrompt: string;
|
|
15
|
-
normalizedPrompt: string;
|
|
16
|
-
command?: string;
|
|
17
|
-
slashArgs: string[];
|
|
18
|
-
activeSkill?: string;
|
|
19
|
-
intent: string;
|
|
20
|
-
action: string;
|
|
21
|
-
entities: string[];
|
|
22
|
-
targetAnchors: string[];
|
|
23
|
-
policyConstraints: string[];
|
|
24
|
-
classificationEvidence: Array<Record<string, unknown>>;
|
|
25
|
-
sourceEventIds: string[];
|
|
26
|
-
sourceHash: string;
|
|
27
|
-
artifactHash: string;
|
|
28
|
-
createdAt: number;
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
export interface ChannelQueryPlanRecord extends TaskIdentityRecord {
|
|
32
|
-
sourceIntentHash: string;
|
|
33
|
-
planHash: string;
|
|
34
|
-
code: Array<Record<string, unknown>>;
|
|
35
|
-
memory: Array<Record<string, unknown>>;
|
|
36
|
-
knowledge: Array<Record<string, unknown>>;
|
|
37
|
-
generatedBy: 'deterministic' | 'host_semantic' | 'hybrid';
|
|
38
|
-
degradation?: Record<string, unknown>;
|
|
39
|
-
createdAt: number;
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
export type ToolNameResolutionStatus = 'canonical' | 'alias' | 'unsupported';
|
|
43
|
-
|
|
44
|
-
export interface ToolNameResolutionRecord extends TaskIdentityRecord {
|
|
45
|
-
id: string;
|
|
46
|
-
sourceHash: string;
|
|
47
|
-
requestedName: string;
|
|
48
|
-
canonicalName?: string;
|
|
49
|
-
projectedName?: string;
|
|
50
|
-
status: ToolNameResolutionStatus;
|
|
51
|
-
attempt: number;
|
|
52
|
-
capabilityMechanism?: string;
|
|
53
|
-
reason?: string;
|
|
54
|
-
createdAt: number;
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
export interface TerminalTransitionRecord extends TaskIdentityRecord {
|
|
58
|
-
sequence: number;
|
|
59
|
-
fromState?: string;
|
|
60
|
-
toState: string;
|
|
61
|
-
receiptId: string;
|
|
62
|
-
sourceReceiptId?: string;
|
|
63
|
-
reason: string;
|
|
64
|
-
payload: Record<string, unknown>;
|
|
65
|
-
createdAt: number;
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
export interface TranscriptCheckpointRecord {
|
|
69
|
-
id: string;
|
|
70
|
-
projectRoot: string;
|
|
71
|
-
hostId: string;
|
|
72
|
-
sessionId: string;
|
|
73
|
-
sourcePath: string;
|
|
74
|
-
sourceHash: string;
|
|
75
|
-
byteOffset: number;
|
|
76
|
-
eventCount: number;
|
|
77
|
-
createdAt: number;
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
export function stableSemanticJson(value: unknown): string {
|
|
81
|
-
return JSON.stringify(canonicalize(value));
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
export function mapTaskIntentArtifactRow(row: Record<string, unknown>): TaskIntentArtifactRecord {
|
|
85
|
-
return {
|
|
86
|
-
...mapTaskIdentityRow(row),
|
|
87
|
-
version: requiredPositiveInteger(row.version, 'version'),
|
|
88
|
-
supersedesHash: optionalString(row.supersedes_hash),
|
|
89
|
-
rawPrompt: requiredString(row.raw_prompt, 'raw_prompt'),
|
|
90
|
-
normalizedPrompt: requiredString(row.normalized_prompt, 'normalized_prompt'),
|
|
91
|
-
command: optionalString(row.command),
|
|
92
|
-
slashArgs: parseStringArray(row.slash_args_json, 'slash_args_json'),
|
|
93
|
-
activeSkill: optionalString(row.active_skill),
|
|
94
|
-
intent: requiredString(row.intent, 'intent'),
|
|
95
|
-
action: requiredString(row.action, 'action'),
|
|
96
|
-
entities: parseStringArray(row.entities_json, 'entities_json'),
|
|
97
|
-
targetAnchors: parseStringArray(row.target_anchors_json, 'target_anchors_json'),
|
|
98
|
-
policyConstraints: parseStringArray(row.policy_constraints_json, 'policy_constraints_json'),
|
|
99
|
-
classificationEvidence: parseObjectArray(row.classification_evidence_json, 'classification_evidence_json'),
|
|
100
|
-
sourceEventIds: parseStringArray(row.source_event_ids_json, 'source_event_ids_json'),
|
|
101
|
-
sourceHash: requiredString(row.source_hash, 'source_hash'),
|
|
102
|
-
artifactHash: requiredString(row.artifact_hash, 'artifact_hash'),
|
|
103
|
-
createdAt: requiredNonNegativeInteger(row.created_at, 'created_at'),
|
|
104
|
-
};
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
export function mapChannelQueryPlanRow(row: Record<string, unknown>): ChannelQueryPlanRecord {
|
|
108
|
-
const generatedBy = requiredString(row.generated_by, 'generated_by');
|
|
109
|
-
if (generatedBy !== 'deterministic' && generatedBy !== 'host_semantic' && generatedBy !== 'hybrid') {
|
|
110
|
-
throw new Error(`Invalid persisted generated_by: ${generatedBy}`);
|
|
111
|
-
}
|
|
112
|
-
return {
|
|
113
|
-
...mapTaskIdentityRow(row),
|
|
114
|
-
sourceIntentHash: requiredString(row.source_intent_hash, 'source_intent_hash'),
|
|
115
|
-
planHash: requiredString(row.plan_hash, 'plan_hash'),
|
|
116
|
-
code: parseObjectArray(row.code_queries_json, 'code_queries_json'),
|
|
117
|
-
memory: parseObjectArray(row.memory_queries_json, 'memory_queries_json'),
|
|
118
|
-
knowledge: parseObjectArray(row.knowledge_queries_json, 'knowledge_queries_json'),
|
|
119
|
-
generatedBy,
|
|
120
|
-
degradation: parseOptionalObject(row.degradation_json, 'degradation_json'),
|
|
121
|
-
createdAt: requiredNonNegativeInteger(row.created_at, 'created_at'),
|
|
122
|
-
};
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
export function mapToolNameResolutionRow(row: Record<string, unknown>): ToolNameResolutionRecord {
|
|
126
|
-
const status = requiredString(row.status, 'status');
|
|
127
|
-
if (status !== 'canonical' && status !== 'alias' && status !== 'unsupported') {
|
|
128
|
-
throw new Error(`Invalid persisted tool resolution status: ${status}`);
|
|
129
|
-
}
|
|
130
|
-
return {
|
|
131
|
-
...mapTaskIdentityRow(row),
|
|
132
|
-
id: requiredString(row.id, 'id'),
|
|
133
|
-
sourceHash: requiredString(row.source_hash, 'source_hash'),
|
|
134
|
-
requestedName: requiredString(row.requested_name, 'requested_name'),
|
|
135
|
-
canonicalName: optionalString(row.canonical_name),
|
|
136
|
-
projectedName: optionalString(row.projected_name),
|
|
137
|
-
status,
|
|
138
|
-
attempt: requiredNonNegativeInteger(row.attempt, 'attempt'),
|
|
139
|
-
capabilityMechanism: optionalString(row.capability_mechanism),
|
|
140
|
-
reason: optionalString(row.reason),
|
|
141
|
-
createdAt: requiredNonNegativeInteger(row.created_at, 'created_at'),
|
|
142
|
-
};
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
export function mapTerminalTransitionRow(row: Record<string, unknown>): TerminalTransitionRecord {
|
|
146
|
-
return {
|
|
147
|
-
...mapTaskIdentityRow(row),
|
|
148
|
-
sequence: requiredPositiveInteger(row.sequence, 'sequence'),
|
|
149
|
-
fromState: optionalString(row.from_state),
|
|
150
|
-
toState: requiredString(row.to_state, 'to_state'),
|
|
151
|
-
receiptId: requiredString(row.receipt_id, 'receipt_id'),
|
|
152
|
-
sourceReceiptId: optionalString(row.source_receipt_id),
|
|
153
|
-
reason: requiredString(row.reason, 'reason'),
|
|
154
|
-
payload: parseObject(row.payload_json, 'payload_json'),
|
|
155
|
-
createdAt: requiredNonNegativeInteger(row.created_at, 'created_at'),
|
|
156
|
-
};
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
export function mapTranscriptCheckpointRow(row: Record<string, unknown>): TranscriptCheckpointRecord {
|
|
160
|
-
return {
|
|
161
|
-
id: requiredString(row.id, 'id'),
|
|
162
|
-
projectRoot: requiredString(row.project_root, 'project_root'),
|
|
163
|
-
hostId: requiredString(row.host_id, 'host_id'),
|
|
164
|
-
sessionId: requiredString(row.session_id, 'session_id'),
|
|
165
|
-
sourcePath: requiredString(row.source_path, 'source_path'),
|
|
166
|
-
sourceHash: requiredString(row.source_hash, 'source_hash'),
|
|
167
|
-
byteOffset: requiredNonNegativeInteger(row.byte_offset, 'byte_offset'),
|
|
168
|
-
eventCount: requiredNonNegativeInteger(row.event_count, 'event_count'),
|
|
169
|
-
createdAt: requiredNonNegativeInteger(row.created_at, 'created_at'),
|
|
170
|
-
};
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
export function assertTaskIdentity(record: TaskIdentityRecord): void {
|
|
174
|
-
for (const [field, value] of Object.entries({
|
|
175
|
-
projectRoot: record.projectRoot,
|
|
176
|
-
projectId: record.projectId,
|
|
177
|
-
hostId: record.hostId,
|
|
178
|
-
sessionId: record.sessionId,
|
|
179
|
-
turnId: record.turnId,
|
|
180
|
-
requestId: record.requestId,
|
|
181
|
-
})) {
|
|
182
|
-
if (typeof value !== 'string' || value.trim().length === 0) {
|
|
183
|
-
throw new Error(`TASK_IDENTITY_INVALID:${field}`);
|
|
184
|
-
}
|
|
185
|
-
}
|
|
186
|
-
if (record.executionId !== undefined && record.executionId.trim().length === 0) {
|
|
187
|
-
throw new Error('TASK_IDENTITY_INVALID:executionId');
|
|
188
|
-
}
|
|
189
|
-
}
|
|
190
|
-
|
|
191
|
-
function mapTaskIdentityRow(row: Record<string, unknown>): TaskIdentityRecord {
|
|
192
|
-
return {
|
|
193
|
-
projectRoot: requiredString(row.project_root, 'project_root'),
|
|
194
|
-
projectId: requiredString(row.project_id, 'project_id'),
|
|
195
|
-
hostId: requiredString(row.host_id, 'host_id'),
|
|
196
|
-
sessionId: requiredString(row.session_id, 'session_id'),
|
|
197
|
-
turnId: requiredString(row.turn_id, 'turn_id'),
|
|
198
|
-
requestId: requiredString(row.request_id, 'request_id'),
|
|
199
|
-
executionId: optionalString(row.execution_id),
|
|
200
|
-
};
|
|
201
|
-
}
|
|
202
|
-
|
|
203
|
-
function canonicalize(value: unknown): unknown {
|
|
204
|
-
if (value === null || typeof value === 'string' || typeof value === 'boolean') return value;
|
|
205
|
-
if (typeof value === 'number') {
|
|
206
|
-
if (!Number.isFinite(value) || Object.is(value, -0)) throw new Error('Semantic control evidence must be lossless JSON');
|
|
207
|
-
return value;
|
|
208
|
-
}
|
|
209
|
-
if (Array.isArray(value)) return value.map(canonicalize);
|
|
210
|
-
if (!value || typeof value !== 'object' || Object.getPrototypeOf(value) !== Object.prototype) {
|
|
211
|
-
throw new Error('Semantic control evidence must be plain JSON');
|
|
212
|
-
}
|
|
213
|
-
const record = value as Record<string, unknown>;
|
|
214
|
-
return Object.fromEntries(Object.keys(record).sort().map(key => [key, canonicalize(record[key])]));
|
|
215
|
-
}
|
|
216
|
-
|
|
217
|
-
function parseJson(value: unknown, field: string): unknown {
|
|
218
|
-
if (typeof value !== 'string') throw new Error(`Invalid persisted ${field}: expected JSON text`);
|
|
219
|
-
try { return JSON.parse(value) as unknown; } catch { throw new Error(`Invalid persisted ${field}: malformed JSON`); }
|
|
220
|
-
}
|
|
221
|
-
|
|
222
|
-
function parseStringArray(value: unknown, field: string): string[] {
|
|
223
|
-
const parsed = parseJson(value, field);
|
|
224
|
-
if (!Array.isArray(parsed) || parsed.some(item => typeof item !== 'string')) {
|
|
225
|
-
throw new Error(`Invalid persisted ${field}: expected string array`);
|
|
226
|
-
}
|
|
227
|
-
return parsed as string[];
|
|
228
|
-
}
|
|
229
|
-
|
|
230
|
-
function parseObjectArray(value: unknown, field: string): Array<Record<string, unknown>> {
|
|
231
|
-
const parsed = parseJson(value, field);
|
|
232
|
-
if (!Array.isArray(parsed) || parsed.some(item => !item || typeof item !== 'object' || Array.isArray(item))) {
|
|
233
|
-
throw new Error(`Invalid persisted ${field}: expected object array`);
|
|
234
|
-
}
|
|
235
|
-
return parsed as Array<Record<string, unknown>>;
|
|
236
|
-
}
|
|
237
|
-
|
|
238
|
-
function parseObject(value: unknown, field: string): Record<string, unknown> {
|
|
239
|
-
const parsed = parseJson(value, field);
|
|
240
|
-
if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) {
|
|
241
|
-
throw new Error(`Invalid persisted ${field}: expected object`);
|
|
242
|
-
}
|
|
243
|
-
return parsed as Record<string, unknown>;
|
|
244
|
-
}
|
|
245
|
-
|
|
246
|
-
function parseOptionalObject(value: unknown, field: string): Record<string, unknown> | undefined {
|
|
247
|
-
if (value === null || value === undefined) return undefined;
|
|
248
|
-
return parseObject(value, field);
|
|
249
|
-
}
|
|
250
|
-
|
|
251
|
-
function requiredString(value: unknown, field: string): string {
|
|
252
|
-
if (typeof value !== 'string' || value.length === 0) throw new Error(`Invalid persisted ${field}`);
|
|
253
|
-
return value;
|
|
254
|
-
}
|
|
255
|
-
|
|
256
|
-
function optionalString(value: unknown): string | undefined {
|
|
257
|
-
return typeof value === 'string' && value.length > 0 ? value : undefined;
|
|
258
|
-
}
|
|
259
|
-
|
|
260
|
-
function requiredNonNegativeInteger(value: unknown, field: string): number {
|
|
261
|
-
const result = Number(value);
|
|
262
|
-
if (!Number.isSafeInteger(result) || result < 0) throw new Error(`Invalid persisted ${field}`);
|
|
263
|
-
return result;
|
|
264
|
-
}
|
|
265
|
-
|
|
266
|
-
function requiredPositiveInteger(value: unknown, field: string): number {
|
|
267
|
-
const result = requiredNonNegativeInteger(value, field);
|
|
268
|
-
if (result === 0) throw new Error(`Invalid persisted ${field}`);
|
|
269
|
-
return result;
|
|
270
|
-
}
|
package/src/types.ts
DELETED
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
export interface Database {
|
|
2
|
-
exec(sql: string): void;
|
|
3
|
-
prepare(sql: string): Statement;
|
|
4
|
-
transaction<T>(fn: () => T): T;
|
|
5
|
-
close(): void;
|
|
6
|
-
}
|
|
7
|
-
|
|
8
|
-
export interface Statement {
|
|
9
|
-
run(...params: any[]): RunResult;
|
|
10
|
-
get(...params: any[]): any;
|
|
11
|
-
all(...params: any[]): any[];
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
export interface RunResult {
|
|
15
|
-
changes: number;
|
|
16
|
-
lastInsertRowid: number | bigint;
|
|
17
|
-
}
|
package/src/work-queue.ts
DELETED
|
@@ -1,123 +0,0 @@
|
|
|
1
|
-
export type WorkKind =
|
|
2
|
-
| 'memory.explicit_commit'
|
|
3
|
-
| 'memory.explicit_enrichment'
|
|
4
|
-
| 'memory.turn_capture'
|
|
5
|
-
| 'memory.turn_distill'
|
|
6
|
-
| 'memory.vector_backfill'
|
|
7
|
-
| 'knowledge.ingest'
|
|
8
|
-
| 'knowledge.index_refresh'
|
|
9
|
-
| 'context.prefetch'
|
|
10
|
-
| 'verification.policy'
|
|
11
|
-
| 'learning.analyze_session'
|
|
12
|
-
| 'workflow.worker_start'
|
|
13
|
-
| 'workflow.worker_monitor'
|
|
14
|
-
| 'workflow.worker_verify'
|
|
15
|
-
| 'workflow.worker_merge'
|
|
16
|
-
| 'workflow.worker_cleanup'
|
|
17
|
-
| 'session.bootstrap'
|
|
18
|
-
| 'session.finalize'
|
|
19
|
-
| 'telemetry.reconcile';
|
|
20
|
-
|
|
21
|
-
export type WorkState = 'pending' | 'leased' | 'completed' | 'failed' | 'dead_letter' | 'cancelled';
|
|
22
|
-
|
|
23
|
-
export interface WorkError {
|
|
24
|
-
category: string;
|
|
25
|
-
message: string;
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
export interface WorkItemRecord {
|
|
29
|
-
id: string;
|
|
30
|
-
idempotencyKey: string;
|
|
31
|
-
kind: WorkKind;
|
|
32
|
-
projectRoot: string;
|
|
33
|
-
sessionId?: string;
|
|
34
|
-
turnId?: string;
|
|
35
|
-
sourceHash?: string;
|
|
36
|
-
taskSpecHash?: string;
|
|
37
|
-
payload: unknown;
|
|
38
|
-
state: WorkState;
|
|
39
|
-
attempts: number;
|
|
40
|
-
maxAttempts: number;
|
|
41
|
-
leaseOwner?: string;
|
|
42
|
-
leaseExpiresAt?: number;
|
|
43
|
-
nextAttemptAt: number;
|
|
44
|
-
errorCategory?: string;
|
|
45
|
-
errorMessage?: string;
|
|
46
|
-
createdAt: number;
|
|
47
|
-
updatedAt: number;
|
|
48
|
-
completedAt?: number;
|
|
49
|
-
cancelledAt?: number;
|
|
50
|
-
cancellationReason?: string;
|
|
51
|
-
replayOfId?: string;
|
|
52
|
-
replayCount: number;
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
export interface EnqueueWorkInput {
|
|
56
|
-
idempotencyKey: string;
|
|
57
|
-
kind: WorkKind;
|
|
58
|
-
projectRoot: string;
|
|
59
|
-
sessionId?: string;
|
|
60
|
-
turnId?: string;
|
|
61
|
-
sourceHash?: string;
|
|
62
|
-
taskSpecHash?: string;
|
|
63
|
-
payload: unknown;
|
|
64
|
-
maxAttempts?: number;
|
|
65
|
-
nextAttemptAt?: number;
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
export interface ProjectMutationLeaseRecord {
|
|
69
|
-
projectRoot: string;
|
|
70
|
-
mutationKind: string;
|
|
71
|
-
owner: string;
|
|
72
|
-
leaseExpiresAt: number;
|
|
73
|
-
sourceHash?: string;
|
|
74
|
-
updatedAt: number;
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
export interface LeaseWorkInput {
|
|
78
|
-
projectRoot: string;
|
|
79
|
-
owner: string;
|
|
80
|
-
kinds?: WorkKind[];
|
|
81
|
-
workItemIds?: string[];
|
|
82
|
-
limit: number;
|
|
83
|
-
leaseMs: number;
|
|
84
|
-
now?: number;
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
export interface WorkQueueHealth {
|
|
88
|
-
projectRoot: string;
|
|
89
|
-
queueDepth: number;
|
|
90
|
-
pending: number;
|
|
91
|
-
leased: number;
|
|
92
|
-
failed: number;
|
|
93
|
-
expiredLeases: number;
|
|
94
|
-
deadLetters: number;
|
|
95
|
-
oldestPendingAgeMs: number;
|
|
96
|
-
lastSuccessfulDrainAt?: number;
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
export type SessionClosureState =
|
|
100
|
-
| 'active'
|
|
101
|
-
| 'closing'
|
|
102
|
-
| 'closed'
|
|
103
|
-
| 'closed_with_pending_work';
|
|
104
|
-
|
|
105
|
-
export interface SessionClosureRecord {
|
|
106
|
-
sessionId: string;
|
|
107
|
-
projectRoot: string;
|
|
108
|
-
state: SessionClosureState;
|
|
109
|
-
receiptId: string;
|
|
110
|
-
workItemId?: string;
|
|
111
|
-
pendingWorkCount: number;
|
|
112
|
-
requestedAt: number;
|
|
113
|
-
updatedAt: number;
|
|
114
|
-
closedAt?: number;
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
export interface RequestSessionClosureInput {
|
|
118
|
-
sessionId: string;
|
|
119
|
-
projectRoot: string;
|
|
120
|
-
receiptId: string;
|
|
121
|
-
payload: unknown;
|
|
122
|
-
maxAttempts?: number;
|
|
123
|
-
}
|
package/src/workflow-workers.ts
DELETED
|
@@ -1,198 +0,0 @@
|
|
|
1
|
-
export type WorkflowWorkerState =
|
|
2
|
-
| 'planned'
|
|
3
|
-
| 'leased'
|
|
4
|
-
| 'starting'
|
|
5
|
-
| 'running'
|
|
6
|
-
| 'reported'
|
|
7
|
-
| 'verifying'
|
|
8
|
-
| 'merge_ready'
|
|
9
|
-
| 'merged'
|
|
10
|
-
| 'hold'
|
|
11
|
-
| 'failed'
|
|
12
|
-
| 'cancelled';
|
|
13
|
-
|
|
14
|
-
export type WorkflowMergeState = 'waiting' | 'ready' | 'conflict' | 'merged' | 'rejected';
|
|
15
|
-
|
|
16
|
-
export interface WorkflowWorkerRecord {
|
|
17
|
-
workerId: string;
|
|
18
|
-
runId: string;
|
|
19
|
-
stepId: string;
|
|
20
|
-
projectRoot: string;
|
|
21
|
-
branch: string;
|
|
22
|
-
worktreePath: string;
|
|
23
|
-
host: string;
|
|
24
|
-
state: WorkflowWorkerState;
|
|
25
|
-
leaseOwner?: string;
|
|
26
|
-
leaseExpiresAt?: number;
|
|
27
|
-
heartbeatAt?: number;
|
|
28
|
-
contextReceipt: string;
|
|
29
|
-
retrievalSessionId?: string;
|
|
30
|
-
sessionId?: string;
|
|
31
|
-
executionId?: string;
|
|
32
|
-
baseRevision: string;
|
|
33
|
-
finalRevision?: string;
|
|
34
|
-
allowedFiles: string[];
|
|
35
|
-
handoff: Record<string, unknown>;
|
|
36
|
-
holdReason?: string;
|
|
37
|
-
failureReason?: string;
|
|
38
|
-
createdAt: number;
|
|
39
|
-
updatedAt: number;
|
|
40
|
-
finishedAt?: number;
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
export interface CreateWorkflowWorkerInput {
|
|
44
|
-
workerId?: string;
|
|
45
|
-
runId: string;
|
|
46
|
-
stepId: string;
|
|
47
|
-
projectRoot: string;
|
|
48
|
-
branch: string;
|
|
49
|
-
worktreePath: string;
|
|
50
|
-
host: string;
|
|
51
|
-
contextReceipt: string;
|
|
52
|
-
retrievalSessionId?: string;
|
|
53
|
-
sessionId?: string;
|
|
54
|
-
executionId?: string;
|
|
55
|
-
baseRevision: string;
|
|
56
|
-
allowedFiles?: string[];
|
|
57
|
-
handoff?: Record<string, unknown>;
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
export interface TransitionWorkflowWorkerInput {
|
|
61
|
-
projectRoot: string;
|
|
62
|
-
workerId: string;
|
|
63
|
-
target: WorkflowWorkerState;
|
|
64
|
-
leaseOwner?: string;
|
|
65
|
-
leaseExpiresAt?: number;
|
|
66
|
-
heartbeatAt?: number;
|
|
67
|
-
finalRevision?: string;
|
|
68
|
-
handoff?: Record<string, unknown>;
|
|
69
|
-
reason?: string;
|
|
70
|
-
now?: number;
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
export interface WorkflowWorkerEventRecord {
|
|
74
|
-
eventId: string;
|
|
75
|
-
workerId: string;
|
|
76
|
-
projectRoot: string;
|
|
77
|
-
fromState?: WorkflowWorkerState;
|
|
78
|
-
toState: WorkflowWorkerState;
|
|
79
|
-
reason?: string;
|
|
80
|
-
payload: Record<string, unknown>;
|
|
81
|
-
createdAt: number;
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
export interface WorkflowMergeRecord {
|
|
85
|
-
mergeId: string;
|
|
86
|
-
workerId: string;
|
|
87
|
-
projectRoot: string;
|
|
88
|
-
state: WorkflowMergeState;
|
|
89
|
-
baseRevision: string;
|
|
90
|
-
parentRevision: string;
|
|
91
|
-
candidateRevision: string;
|
|
92
|
-
graderReceipts: string[];
|
|
93
|
-
simulationHash?: string;
|
|
94
|
-
mergeCommit?: string;
|
|
95
|
-
reason?: string;
|
|
96
|
-
createdAt: number;
|
|
97
|
-
updatedAt: number;
|
|
98
|
-
finishedAt?: number;
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
export interface EnqueueWorkflowMergeInput {
|
|
102
|
-
mergeId?: string;
|
|
103
|
-
workerId: string;
|
|
104
|
-
projectRoot: string;
|
|
105
|
-
baseRevision: string;
|
|
106
|
-
parentRevision: string;
|
|
107
|
-
candidateRevision: string;
|
|
108
|
-
graderReceipts?: string[];
|
|
109
|
-
simulationHash?: string;
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
export const TERMINAL_WORKFLOW_WORKER_STATES = new Set<WorkflowWorkerState>([
|
|
113
|
-
'merged', 'failed', 'cancelled',
|
|
114
|
-
]);
|
|
115
|
-
|
|
116
|
-
export const LEGAL_WORKFLOW_WORKER_TRANSITIONS: Record<WorkflowWorkerState, WorkflowWorkerState[]> = {
|
|
117
|
-
planned: ['leased', 'cancelled', 'hold', 'failed'],
|
|
118
|
-
leased: ['starting', 'hold', 'cancelled', 'failed'],
|
|
119
|
-
starting: ['running', 'reported', 'hold', 'cancelled', 'failed'],
|
|
120
|
-
running: ['reported', 'hold', 'cancelled', 'failed'],
|
|
121
|
-
reported: ['verifying', 'hold', 'cancelled', 'failed'],
|
|
122
|
-
verifying: ['merge_ready', 'hold', 'cancelled', 'failed'],
|
|
123
|
-
merge_ready: ['merged', 'hold', 'cancelled', 'failed'],
|
|
124
|
-
merged: [],
|
|
125
|
-
hold: ['leased', 'cancelled', 'failed'],
|
|
126
|
-
failed: [],
|
|
127
|
-
cancelled: [],
|
|
128
|
-
};
|
|
129
|
-
|
|
130
|
-
export function mapWorkflowWorkerRow(row: any): WorkflowWorkerRecord {
|
|
131
|
-
return {
|
|
132
|
-
workerId: row.worker_id,
|
|
133
|
-
runId: row.run_id,
|
|
134
|
-
stepId: row.step_id,
|
|
135
|
-
projectRoot: row.project_root,
|
|
136
|
-
branch: row.branch,
|
|
137
|
-
worktreePath: row.worktree_path,
|
|
138
|
-
host: row.host,
|
|
139
|
-
state: row.state,
|
|
140
|
-
leaseOwner: row.lease_owner ?? undefined,
|
|
141
|
-
leaseExpiresAt: row.lease_expires_at ?? undefined,
|
|
142
|
-
heartbeatAt: row.heartbeat_at ?? undefined,
|
|
143
|
-
contextReceipt: row.context_receipt,
|
|
144
|
-
retrievalSessionId: row.retrieval_session_id ?? undefined,
|
|
145
|
-
sessionId: row.session_id ?? undefined,
|
|
146
|
-
executionId: row.execution_id ?? undefined,
|
|
147
|
-
baseRevision: row.base_revision,
|
|
148
|
-
finalRevision: row.final_revision ?? undefined,
|
|
149
|
-
allowedFiles: parseJson(row.allowed_files, []),
|
|
150
|
-
handoff: parseJson(row.handoff_json, {}),
|
|
151
|
-
holdReason: row.hold_reason ?? undefined,
|
|
152
|
-
failureReason: row.failure_reason ?? undefined,
|
|
153
|
-
createdAt: row.created_at,
|
|
154
|
-
updatedAt: row.updated_at,
|
|
155
|
-
finishedAt: row.finished_at ?? undefined,
|
|
156
|
-
};
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
export function mapWorkflowWorkerEventRow(row: any): WorkflowWorkerEventRecord {
|
|
160
|
-
return {
|
|
161
|
-
eventId: row.event_id,
|
|
162
|
-
workerId: row.worker_id,
|
|
163
|
-
projectRoot: row.project_root,
|
|
164
|
-
fromState: row.from_state ?? undefined,
|
|
165
|
-
toState: row.to_state,
|
|
166
|
-
reason: row.reason ?? undefined,
|
|
167
|
-
payload: parseJson(row.payload_json, {}),
|
|
168
|
-
createdAt: row.created_at,
|
|
169
|
-
};
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
export function mapWorkflowMergeRow(row: any): WorkflowMergeRecord {
|
|
173
|
-
return {
|
|
174
|
-
mergeId: row.merge_id,
|
|
175
|
-
workerId: row.worker_id,
|
|
176
|
-
projectRoot: row.project_root,
|
|
177
|
-
state: row.state,
|
|
178
|
-
baseRevision: row.base_revision,
|
|
179
|
-
parentRevision: row.parent_revision,
|
|
180
|
-
candidateRevision: row.candidate_revision,
|
|
181
|
-
graderReceipts: parseJson(row.grader_receipts, []),
|
|
182
|
-
simulationHash: row.simulation_hash ?? undefined,
|
|
183
|
-
mergeCommit: row.merge_commit ?? undefined,
|
|
184
|
-
reason: row.reason ?? undefined,
|
|
185
|
-
createdAt: row.created_at,
|
|
186
|
-
updatedAt: row.updated_at,
|
|
187
|
-
finishedAt: row.finished_at ?? undefined,
|
|
188
|
-
};
|
|
189
|
-
}
|
|
190
|
-
|
|
191
|
-
function parseJson<T>(value: unknown, fallback: T): T {
|
|
192
|
-
if (typeof value !== 'string' || value.length === 0) return fallback;
|
|
193
|
-
try {
|
|
194
|
-
return JSON.parse(value) as T;
|
|
195
|
-
} catch {
|
|
196
|
-
return fallback;
|
|
197
|
-
}
|
|
198
|
-
}
|
package/tsconfig.json
DELETED
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"compilerOptions": {
|
|
3
|
-
"target": "ES2020",
|
|
4
|
-
"module": "commonjs",
|
|
5
|
-
"lib": ["ES2020"],
|
|
6
|
-
"declaration": true,
|
|
7
|
-
"outDir": "./dist",
|
|
8
|
-
"rootDir": "./src",
|
|
9
|
-
"strict": true,
|
|
10
|
-
"esModuleInterop": true,
|
|
11
|
-
"skipLibCheck": true,
|
|
12
|
-
"forceConsistentCasingInFileNames": true,
|
|
13
|
-
"composite": true,
|
|
14
|
-
"moduleResolution": "node",
|
|
15
|
-
"resolveJsonModule": true
|
|
16
|
-
},
|
|
17
|
-
"include": ["src/**/*"],
|
|
18
|
-
"exclude": ["node_modules", "dist", "__tests__"]
|
|
19
|
-
}
|