@devflow-tools/database 0.17.2 → 0.17.4

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.
@@ -0,0 +1,30 @@
1
+ export type PersistedSemanticResolutionState = 'provisional' | 'resolved' | 'abstained' | 'unavailable';
2
+ export type PersistedSemanticGeneratedBy = 'deterministic' | 'embedding_router' | 'host_semantic' | 'hybrid';
3
+ export interface SemanticResolutionRecord {
4
+ frameHash: string;
5
+ projectRoot: string;
6
+ projectId: string;
7
+ hostId: string;
8
+ sessionId: string;
9
+ turnId: string;
10
+ requestId: string;
11
+ sourceHash: string;
12
+ artifactHash: string;
13
+ artifactRevision: number;
14
+ supersedesFrameHash?: string;
15
+ state: PersistedSemanticResolutionState;
16
+ generatedBy: PersistedSemanticGeneratedBy;
17
+ modelId?: string;
18
+ modelRevision?: string;
19
+ routeCatalogVersion: string;
20
+ thresholdVersion: string;
21
+ route: Record<string, unknown>;
22
+ sampling: Record<string, unknown>;
23
+ conflicts: Array<Record<string, unknown>>;
24
+ frame: Record<string, unknown>;
25
+ durationMs: number;
26
+ createdAt: number;
27
+ }
28
+ export declare function assertSemanticResolutionRecord(record: SemanticResolutionRecord): void;
29
+ export declare function stableSemanticResolutionJson(value: unknown): string;
30
+ export declare function mapSemanticResolutionRow(row: Record<string, unknown>): SemanticResolutionRecord;
@@ -0,0 +1,156 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.assertSemanticResolutionRecord = assertSemanticResolutionRecord;
4
+ exports.stableSemanticResolutionJson = stableSemanticResolutionJson;
5
+ exports.mapSemanticResolutionRow = mapSemanticResolutionRow;
6
+ const STATES = new Set([
7
+ 'provisional', 'resolved', 'abstained', 'unavailable',
8
+ ]);
9
+ const GENERATORS = new Set([
10
+ 'deterministic', 'embedding_router', 'host_semantic', 'hybrid',
11
+ ]);
12
+ function assertSemanticResolutionRecord(record) {
13
+ for (const [field, value] of Object.entries({
14
+ frameHash: record.frameHash,
15
+ projectRoot: record.projectRoot,
16
+ projectId: record.projectId,
17
+ hostId: record.hostId,
18
+ sessionId: record.sessionId,
19
+ turnId: record.turnId,
20
+ requestId: record.requestId,
21
+ sourceHash: record.sourceHash,
22
+ artifactHash: record.artifactHash,
23
+ routeCatalogVersion: record.routeCatalogVersion,
24
+ thresholdVersion: record.thresholdVersion,
25
+ })) {
26
+ if (typeof value !== 'string' || value.length === 0) {
27
+ throw new Error(`SEMANTIC_RESOLUTION_INVALID:${field}`);
28
+ }
29
+ }
30
+ if (!Number.isSafeInteger(record.artifactRevision) || record.artifactRevision < 1) {
31
+ throw new Error('SEMANTIC_RESOLUTION_INVALID:artifactRevision');
32
+ }
33
+ if (!Number.isSafeInteger(record.durationMs) || record.durationMs < 0
34
+ || !Number.isSafeInteger(record.createdAt) || record.createdAt < 0) {
35
+ throw new Error('SEMANTIC_RESOLUTION_INVALID:timing');
36
+ }
37
+ if (!STATES.has(record.state) || !GENERATORS.has(record.generatedBy)) {
38
+ throw new Error('SEMANTIC_RESOLUTION_INVALID:enum');
39
+ }
40
+ if (record.frame.frameHash !== record.frameHash) {
41
+ throw new Error('SEMANTIC_RESOLUTION_FRAME_HASH_MISMATCH');
42
+ }
43
+ stableSemanticResolutionJson(record.route);
44
+ stableSemanticResolutionJson(record.sampling);
45
+ stableSemanticResolutionJson(record.conflicts);
46
+ stableSemanticResolutionJson(record.frame);
47
+ }
48
+ function stableSemanticResolutionJson(value) {
49
+ return JSON.stringify(canonicalize(value));
50
+ }
51
+ function mapSemanticResolutionRow(row) {
52
+ const state = requiredString(row.state, 'state');
53
+ const generatedBy = requiredString(row.generated_by, 'generated_by');
54
+ if (!STATES.has(state) || !GENERATORS.has(generatedBy)) {
55
+ throw new Error('SEMANTIC_RESOLUTION_ROW_INVALID:enum');
56
+ }
57
+ const result = {
58
+ frameHash: requiredString(row.frame_hash, 'frame_hash'),
59
+ projectRoot: requiredString(row.project_root, 'project_root'),
60
+ projectId: requiredString(row.project_id, 'project_id'),
61
+ hostId: requiredString(row.host_id, 'host_id'),
62
+ sessionId: requiredString(row.session_id, 'session_id'),
63
+ turnId: requiredString(row.turn_id, 'turn_id'),
64
+ requestId: requiredString(row.request_id, 'request_id'),
65
+ sourceHash: requiredString(row.source_hash, 'source_hash'),
66
+ artifactHash: requiredString(row.artifact_hash, 'artifact_hash'),
67
+ artifactRevision: requiredPositiveInteger(row.artifact_revision, 'artifact_revision'),
68
+ ...(optionalString(row.supersedes_frame_hash)
69
+ ? { supersedesFrameHash: optionalString(row.supersedes_frame_hash) }
70
+ : {}),
71
+ state,
72
+ generatedBy,
73
+ ...(optionalString(row.model_id) ? { modelId: optionalString(row.model_id) } : {}),
74
+ ...(optionalString(row.model_revision) ? { modelRevision: optionalString(row.model_revision) } : {}),
75
+ routeCatalogVersion: requiredString(row.route_catalog_version, 'route_catalog_version'),
76
+ thresholdVersion: requiredString(row.threshold_version, 'threshold_version'),
77
+ route: parseObject(row.route_json, 'route_json'),
78
+ sampling: parseObject(row.sampling_json, 'sampling_json'),
79
+ conflicts: parseObjectArray(row.conflicts_json, 'conflicts_json'),
80
+ frame: parseObject(row.frame_json, 'frame_json'),
81
+ durationMs: requiredNonNegativeInteger(row.duration_ms, 'duration_ms'),
82
+ createdAt: requiredNonNegativeInteger(row.created_at, 'created_at'),
83
+ };
84
+ assertSemanticResolutionRecord(result);
85
+ return result;
86
+ }
87
+ function canonicalize(value) {
88
+ if (value === undefined)
89
+ return undefined;
90
+ if (value === null || typeof value === 'string' || typeof value === 'boolean')
91
+ return value;
92
+ if (typeof value === 'number') {
93
+ if (!Number.isFinite(value) || Object.is(value, -0))
94
+ throw new Error('SEMANTIC_RESOLUTION_JSON_INVALID');
95
+ return value;
96
+ }
97
+ if (Array.isArray(value))
98
+ return value.map(item => {
99
+ if (item === undefined)
100
+ throw new Error('SEMANTIC_RESOLUTION_JSON_INVALID');
101
+ return canonicalize(item);
102
+ });
103
+ if (!value || typeof value !== 'object' || Object.getPrototypeOf(value) !== Object.prototype) {
104
+ throw new Error('SEMANTIC_RESOLUTION_JSON_INVALID');
105
+ }
106
+ const record = value;
107
+ return Object.fromEntries(Object.keys(record).sort()
108
+ .filter(key => record[key] !== undefined)
109
+ .map(key => [key, canonicalize(record[key])]));
110
+ }
111
+ function parseObject(value, field) {
112
+ const parsed = parseJson(value, field);
113
+ if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) {
114
+ throw new Error(`SEMANTIC_RESOLUTION_ROW_INVALID:${field}`);
115
+ }
116
+ return parsed;
117
+ }
118
+ function parseObjectArray(value, field) {
119
+ const parsed = parseJson(value, field);
120
+ if (!Array.isArray(parsed) || parsed.some(item => !item || typeof item !== 'object' || Array.isArray(item))) {
121
+ throw new Error(`SEMANTIC_RESOLUTION_ROW_INVALID:${field}`);
122
+ }
123
+ return parsed;
124
+ }
125
+ function parseJson(value, field) {
126
+ if (typeof value !== 'string')
127
+ throw new Error(`SEMANTIC_RESOLUTION_ROW_INVALID:${field}`);
128
+ try {
129
+ return JSON.parse(value);
130
+ }
131
+ catch {
132
+ throw new Error(`SEMANTIC_RESOLUTION_ROW_INVALID:${field}`);
133
+ }
134
+ }
135
+ function requiredString(value, field) {
136
+ if (typeof value !== 'string' || value.length === 0) {
137
+ throw new Error(`SEMANTIC_RESOLUTION_ROW_INVALID:${field}`);
138
+ }
139
+ return value;
140
+ }
141
+ function optionalString(value) {
142
+ return typeof value === 'string' && value.length > 0 ? value : undefined;
143
+ }
144
+ function requiredPositiveInteger(value, field) {
145
+ const result = requiredNonNegativeInteger(value, field);
146
+ if (result < 1)
147
+ throw new Error(`SEMANTIC_RESOLUTION_ROW_INVALID:${field}`);
148
+ return result;
149
+ }
150
+ function requiredNonNegativeInteger(value, field) {
151
+ const result = Number(value);
152
+ if (!Number.isSafeInteger(result) || result < 0) {
153
+ throw new Error(`SEMANTIC_RESOLUTION_ROW_INVALID:${field}`);
154
+ }
155
+ return result;
156
+ }
@@ -0,0 +1,64 @@
1
+ export interface TaskRuntimeIdentityRecord {
2
+ projectRoot: string;
3
+ projectId: string;
4
+ hostId: string;
5
+ sessionId: string;
6
+ turnId: string;
7
+ requestId: string;
8
+ executionId?: string;
9
+ }
10
+ export interface TaskRuntimeEventRecord {
11
+ schemaVersion: 'task-runtime-event.v1';
12
+ producer: string;
13
+ producerVersion: string;
14
+ eventId: string;
15
+ sequence: number;
16
+ identity: TaskRuntimeIdentityRecord;
17
+ taskSpecHash: string;
18
+ kind: string;
19
+ payload: Record<string, unknown>;
20
+ createdAt: number;
21
+ }
22
+ export type TaskRuntimeChannelRequirement = 'required' | 'optional' | 'not_required';
23
+ export type TaskRuntimeChannelStatus = 'satisfied' | 'intentional_abstention' | 'empty_valid' | 'degraded' | 'failed';
24
+ export type TaskRuntimeObligationState = 'pending' | 'satisfied' | 'degraded' | 'failed';
25
+ export interface TaskRuntimeChannelRecord {
26
+ requirement: TaskRuntimeChannelRequirement;
27
+ status: TaskRuntimeChannelStatus;
28
+ reasonCode: string;
29
+ evidenceIds: string[];
30
+ material: boolean;
31
+ }
32
+ export interface TaskRuntimeObligationRecord {
33
+ requirement: TaskRuntimeChannelRequirement;
34
+ state: TaskRuntimeObligationState;
35
+ receiptId?: string;
36
+ reasonCode?: string;
37
+ }
38
+ export interface TaskRuntimeSnapshotRecord {
39
+ schemaVersion: 'task-runtime-snapshot.v1';
40
+ producer: string;
41
+ producerVersion: string;
42
+ identity: TaskRuntimeIdentityRecord;
43
+ taskSpecHash: string;
44
+ lastEventSequence: number;
45
+ artifacts: {
46
+ requiredIdentityIds: string[];
47
+ resolvedIdentityIds: string[];
48
+ ambiguousIdentityIds: string[];
49
+ };
50
+ channels: Partial<Record<'code' | 'memory' | 'knowledge', TaskRuntimeChannelRecord>>;
51
+ contextReceiptId?: string;
52
+ action: TaskRuntimeObligationRecord;
53
+ verification: TaskRuntimeObligationRecord;
54
+ memory: TaskRuntimeObligationRecord;
55
+ durableWorkIds: string[];
56
+ terminal: 'running' | 'retry_pending' | 'completed' | 'completed_with_degradation' | 'failed';
57
+ runtimeHealth: 'healthy' | 'degraded' | 'unavailable';
58
+ snapshotHash: string;
59
+ updatedAt: number;
60
+ }
61
+ export declare function stableTaskRuntimeJson(value: unknown): string;
62
+ export declare function stableTaskRuntimeHash(value: unknown): string;
63
+ export declare function mapTaskRuntimeEventRow(row: Record<string, unknown>): TaskRuntimeEventRecord;
64
+ export declare function mapTaskRuntimeSnapshotRow(row: Record<string, unknown>): TaskRuntimeSnapshotRecord;
@@ -0,0 +1,106 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.stableTaskRuntimeJson = stableTaskRuntimeJson;
4
+ exports.stableTaskRuntimeHash = stableTaskRuntimeHash;
5
+ exports.mapTaskRuntimeEventRow = mapTaskRuntimeEventRow;
6
+ exports.mapTaskRuntimeSnapshotRow = mapTaskRuntimeSnapshotRow;
7
+ const node_crypto_1 = require("node:crypto");
8
+ function stableTaskRuntimeJson(value) {
9
+ return JSON.stringify(canonicalize(value));
10
+ }
11
+ function stableTaskRuntimeHash(value) {
12
+ return (0, node_crypto_1.createHash)('sha256').update(stableTaskRuntimeJson(value)).digest('hex');
13
+ }
14
+ function mapTaskRuntimeEventRow(row) {
15
+ return {
16
+ schemaVersion: requiredLiteral(row.schema_version, 'task-runtime-event.v1'),
17
+ producer: requiredString(row.producer, 'producer'),
18
+ producerVersion: requiredString(row.producer_version, 'producer_version'),
19
+ eventId: requiredString(row.event_id, 'event_id'),
20
+ sequence: requiredPositiveInteger(row.sequence, 'sequence'),
21
+ identity: mapIdentity(row),
22
+ taskSpecHash: requiredString(row.task_spec_hash, 'task_spec_hash'),
23
+ kind: requiredString(row.kind, 'kind'),
24
+ payload: parseObject(row.payload_json, 'payload_json'),
25
+ createdAt: requiredNonNegativeInteger(row.created_at, 'created_at'),
26
+ };
27
+ }
28
+ function mapTaskRuntimeSnapshotRow(row) {
29
+ const snapshot = parseObject(row.snapshot_json, 'snapshot_json');
30
+ if (snapshot.schemaVersion !== 'task-runtime-snapshot.v1') {
31
+ throw new Error(`TASK_RUNTIME_SCHEMA_UNSUPPORTED:${String(snapshot.schemaVersion)}`);
32
+ }
33
+ if (snapshot.snapshotHash !== requiredString(row.snapshot_hash, 'snapshot_hash')) {
34
+ throw new Error('TASK_RUNTIME_SNAPSHOT_HASH_MISMATCH');
35
+ }
36
+ const { snapshotHash: _snapshotHash, ...body } = snapshot;
37
+ if (stableTaskRuntimeHash(body) !== snapshot.snapshotHash) {
38
+ throw new Error('TASK_RUNTIME_SNAPSHOT_HASH_MISMATCH');
39
+ }
40
+ return snapshot;
41
+ }
42
+ function mapIdentity(row) {
43
+ return {
44
+ projectRoot: requiredString(row.project_root, 'project_root'),
45
+ projectId: requiredString(row.project_id, 'project_id'),
46
+ hostId: requiredString(row.host_id, 'host_id'),
47
+ sessionId: requiredString(row.session_id, 'session_id'),
48
+ turnId: requiredString(row.turn_id, 'turn_id'),
49
+ requestId: requiredString(row.request_id, 'request_id'),
50
+ ...(optionalString(row.execution_id) ? { executionId: optionalString(row.execution_id) } : {}),
51
+ };
52
+ }
53
+ function requiredLiteral(value, literal) {
54
+ if (value !== literal)
55
+ throw new Error(`TASK_RUNTIME_SCHEMA_UNSUPPORTED:${String(value)}`);
56
+ return literal;
57
+ }
58
+ function requiredString(value, field) {
59
+ if (typeof value !== 'string' || !value.trim())
60
+ throw new Error(`TASK_RUNTIME_ROW_INVALID:${field}`);
61
+ return value;
62
+ }
63
+ function optionalString(value) {
64
+ return typeof value === 'string' && value.length > 0 ? value : undefined;
65
+ }
66
+ function requiredPositiveInteger(value, field) {
67
+ const result = Number(value);
68
+ if (!Number.isSafeInteger(result) || result < 1)
69
+ throw new Error(`TASK_RUNTIME_ROW_INVALID:${field}`);
70
+ return result;
71
+ }
72
+ function requiredNonNegativeInteger(value, field) {
73
+ const result = Number(value);
74
+ if (!Number.isSafeInteger(result) || result < 0)
75
+ throw new Error(`TASK_RUNTIME_ROW_INVALID:${field}`);
76
+ return result;
77
+ }
78
+ function parseObject(value, field) {
79
+ if (typeof value !== 'string')
80
+ throw new Error(`TASK_RUNTIME_ROW_INVALID:${field}`);
81
+ try {
82
+ const parsed = JSON.parse(value);
83
+ if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed))
84
+ throw new Error('not object');
85
+ return parsed;
86
+ }
87
+ catch {
88
+ throw new Error(`TASK_RUNTIME_ROW_INVALID:${field}`);
89
+ }
90
+ }
91
+ function canonicalize(value) {
92
+ if (value === null || typeof value === 'string' || typeof value === 'boolean')
93
+ return value;
94
+ if (typeof value === 'number') {
95
+ if (!Number.isFinite(value) || Object.is(value, -0))
96
+ throw new Error('TASK_RUNTIME_JSON_INVALID');
97
+ return value;
98
+ }
99
+ if (Array.isArray(value))
100
+ return value.map(canonicalize);
101
+ if (!value || typeof value !== 'object' || Object.getPrototypeOf(value) !== Object.prototype) {
102
+ throw new Error('TASK_RUNTIME_JSON_INVALID');
103
+ }
104
+ return Object.fromEntries(Object.keys(value).sort()
105
+ .map(key => [key, canonicalize(value[key])]));
106
+ }
@@ -1,5 +1,5 @@
1
- export type WorkKind = 'memory.explicit_commit' | 'memory.explicit_enrichment' | 'memory.turn_capture' | 'memory.turn_distill' | 'memory.vector_backfill' | 'context.prefetch' | 'verification.policy' | 'learning.analyze_session' | 'workflow.worker_start' | 'workflow.worker_monitor' | 'workflow.worker_verify' | 'workflow.worker_merge' | 'workflow.worker_cleanup' | 'session.bootstrap' | 'session.finalize' | 'telemetry.reconcile';
2
- export type WorkState = 'pending' | 'leased' | 'completed' | 'failed' | 'dead_letter';
1
+ export type WorkKind = 'memory.explicit_commit' | 'memory.explicit_enrichment' | 'memory.turn_capture' | 'memory.turn_distill' | 'memory.vector_backfill' | 'knowledge.ingest' | 'knowledge.index_refresh' | 'context.prefetch' | 'verification.policy' | 'learning.analyze_session' | 'workflow.worker_start' | 'workflow.worker_monitor' | 'workflow.worker_verify' | 'workflow.worker_merge' | 'workflow.worker_cleanup' | 'session.bootstrap' | 'session.finalize' | 'telemetry.reconcile';
2
+ export type WorkState = 'pending' | 'leased' | 'completed' | 'failed' | 'dead_letter' | 'cancelled';
3
3
  export interface WorkError {
4
4
  category: string;
5
5
  message: string;
@@ -11,6 +11,8 @@ export interface WorkItemRecord {
11
11
  projectRoot: string;
12
12
  sessionId?: string;
13
13
  turnId?: string;
14
+ sourceHash?: string;
15
+ taskSpecHash?: string;
14
16
  payload: unknown;
15
17
  state: WorkState;
16
18
  attempts: number;
@@ -23,6 +25,10 @@ export interface WorkItemRecord {
23
25
  createdAt: number;
24
26
  updatedAt: number;
25
27
  completedAt?: number;
28
+ cancelledAt?: number;
29
+ cancellationReason?: string;
30
+ replayOfId?: string;
31
+ replayCount: number;
26
32
  }
27
33
  export interface EnqueueWorkInput {
28
34
  idempotencyKey: string;
@@ -30,10 +36,20 @@ export interface EnqueueWorkInput {
30
36
  projectRoot: string;
31
37
  sessionId?: string;
32
38
  turnId?: string;
39
+ sourceHash?: string;
40
+ taskSpecHash?: string;
33
41
  payload: unknown;
34
42
  maxAttempts?: number;
35
43
  nextAttemptAt?: number;
36
44
  }
45
+ export interface ProjectMutationLeaseRecord {
46
+ projectRoot: string;
47
+ mutationKind: string;
48
+ owner: string;
49
+ leaseExpiresAt: number;
50
+ sourceHash?: string;
51
+ updatedAt: number;
52
+ }
37
53
  export interface LeaseWorkInput {
38
54
  projectRoot: string;
39
55
  owner: string;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@devflow-tools/database",
3
- "version": "0.17.2",
3
+ "version": "0.17.4",
4
4
  "description": "DevFlow SQLite database package",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -13,5 +13,5 @@
13
13
  "typescript": "^5.5.0",
14
14
  "vitest": "^2.0.0"
15
15
  },
16
- "gitHead": "964af33767bf232606e63d973b3a29d7d53c8119"
16
+ "gitHead": "b880054f9cef4ed62b4d02544257c9f5cbd811bc"
17
17
  }