@devflow-tools/database 0.17.1 → 0.17.3

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/dist/index.js CHANGED
@@ -1,10 +1,11 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.stableLearningJson = exports.mapLearningVersionRow = exports.mapLearningEvidenceRow = exports.mapLearningCandidateRow = exports.mapWorkflowWorkerRow = exports.mapWorkflowWorkerEventRow = exports.mapWorkflowMergeRow = exports.TERMINAL_WORKFLOW_WORKER_STATES = exports.LEGAL_WORKFLOW_WORKER_TRANSITIONS = exports.stableSemanticJson = exports.mapTranscriptCheckpointRow = exports.mapToolNameResolutionRow = exports.mapTerminalTransitionRow = exports.mapTaskIntentArtifactRow = exports.mapChannelQueryPlanRow = exports.assertTaskIdentity = exports.normalizeTurnId = exports.mapSessionObligationRow = exports.isRetrievalSessionState = exports.RETRIEVAL_MAX_CYCLES = exports.serializeHostActionReport = exports.mapHostActionRow = exports.isHostActionState = exports.hostActionReportsEqual = exports.openGlobalDevFlowDatabase = exports.getGlobalDevFlowDbPath = exports.DevFlowDatabase = void 0;
3
+ exports.stableLearningJson = exports.mapLearningVersionRow = exports.mapLearningEvidenceRow = exports.mapLearningCandidateRow = exports.mapWorkflowWorkerRow = exports.mapWorkflowWorkerEventRow = exports.mapWorkflowMergeRow = exports.TERMINAL_WORKFLOW_WORKER_STATES = exports.LEGAL_WORKFLOW_WORKER_TRANSITIONS = exports.stableTaskRuntimeJson = exports.stableTaskRuntimeHash = exports.mapTaskRuntimeSnapshotRow = exports.mapTaskRuntimeEventRow = exports.stableSemanticJson = exports.mapTranscriptCheckpointRow = exports.mapToolNameResolutionRow = exports.mapTerminalTransitionRow = exports.mapTaskIntentArtifactRow = exports.mapChannelQueryPlanRow = exports.assertTaskIdentity = exports.normalizeTurnId = exports.mapSessionObligationRow = exports.isRetrievalSessionState = exports.RETRIEVAL_MAX_CYCLES = exports.serializeHostActionReport = exports.mapHostActionRow = exports.isHostActionState = exports.hostActionReportsEqual = exports.openGlobalDevFlowReadOnlyDatabase = exports.openGlobalDevFlowDatabase = exports.getGlobalDevFlowDbPath = exports.DevFlowDatabase = void 0;
4
4
  var database_1 = require("./database");
5
5
  Object.defineProperty(exports, "DevFlowDatabase", { enumerable: true, get: function () { return database_1.DevFlowDatabase; } });
6
6
  Object.defineProperty(exports, "getGlobalDevFlowDbPath", { enumerable: true, get: function () { return database_1.getGlobalDevFlowDbPath; } });
7
7
  Object.defineProperty(exports, "openGlobalDevFlowDatabase", { enumerable: true, get: function () { return database_1.openGlobalDevFlowDatabase; } });
8
+ Object.defineProperty(exports, "openGlobalDevFlowReadOnlyDatabase", { enumerable: true, get: function () { return database_1.openGlobalDevFlowReadOnlyDatabase; } });
8
9
  var host_actions_1 = require("./host-actions");
9
10
  Object.defineProperty(exports, "hostActionReportsEqual", { enumerable: true, get: function () { return host_actions_1.hostActionReportsEqual; } });
10
11
  Object.defineProperty(exports, "isHostActionState", { enumerable: true, get: function () { return host_actions_1.isHostActionState; } });
@@ -24,6 +25,11 @@ Object.defineProperty(exports, "mapTerminalTransitionRow", { enumerable: true, g
24
25
  Object.defineProperty(exports, "mapToolNameResolutionRow", { enumerable: true, get: function () { return task_semantic_control_1.mapToolNameResolutionRow; } });
25
26
  Object.defineProperty(exports, "mapTranscriptCheckpointRow", { enumerable: true, get: function () { return task_semantic_control_1.mapTranscriptCheckpointRow; } });
26
27
  Object.defineProperty(exports, "stableSemanticJson", { enumerable: true, get: function () { return task_semantic_control_1.stableSemanticJson; } });
28
+ var task_runtime_1 = require("./task-runtime");
29
+ Object.defineProperty(exports, "mapTaskRuntimeEventRow", { enumerable: true, get: function () { return task_runtime_1.mapTaskRuntimeEventRow; } });
30
+ Object.defineProperty(exports, "mapTaskRuntimeSnapshotRow", { enumerable: true, get: function () { return task_runtime_1.mapTaskRuntimeSnapshotRow; } });
31
+ Object.defineProperty(exports, "stableTaskRuntimeHash", { enumerable: true, get: function () { return task_runtime_1.stableTaskRuntimeHash; } });
32
+ Object.defineProperty(exports, "stableTaskRuntimeJson", { enumerable: true, get: function () { return task_runtime_1.stableTaskRuntimeJson; } });
27
33
  var workflow_workers_1 = require("./workflow-workers");
28
34
  Object.defineProperty(exports, "LEGAL_WORKFLOW_WORKER_TRANSITIONS", { enumerable: true, get: function () { return workflow_workers_1.LEGAL_WORKFLOW_WORKER_TRANSITIONS; } });
29
35
  Object.defineProperty(exports, "TERMINAL_WORKFLOW_WORKER_STATES", { enumerable: true, get: function () { return workflow_workers_1.TERMINAL_WORKFLOW_WORKER_STATES; } });
@@ -1,7 +1,7 @@
1
1
  import type { Database, Statement } from './types';
2
2
  export declare class NodeSqliteDatabase implements Database {
3
3
  private db;
4
- constructor(path: string, busyTimeoutMs?: number);
4
+ constructor(path: string, busyTimeoutMs?: number, readOnly?: boolean);
5
5
  exec(sql: string): void;
6
6
  prepare(sql: string): Statement;
7
7
  transaction<T>(fn: () => T): T;
@@ -3,11 +3,15 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.NodeSqliteDatabase = void 0;
4
4
  const node_sqlite_1 = require("node:sqlite");
5
5
  class NodeSqliteDatabase {
6
- constructor(path, busyTimeoutMs = 10000) {
7
- this.db = new node_sqlite_1.DatabaseSync(path);
6
+ constructor(path, busyTimeoutMs = 10000, readOnly = false) {
7
+ this.db = readOnly
8
+ ? new node_sqlite_1.DatabaseSync(path, { readOnly: true })
9
+ : new node_sqlite_1.DatabaseSync(path);
8
10
  this.db.exec(`PRAGMA busy_timeout = ${Math.max(0, Math.floor(busyTimeoutMs))}`);
9
- this.db.exec('PRAGMA journal_mode = WAL');
10
- this.db.exec('PRAGMA synchronous = NORMAL');
11
+ if (!readOnly) {
12
+ this.db.exec('PRAGMA journal_mode = WAL');
13
+ this.db.exec('PRAGMA synchronous = NORMAL');
14
+ }
11
15
  }
12
16
  exec(sql) {
13
17
  this.db.exec(sql);
@@ -1,6 +1,7 @@
1
- export type RetrievalLedgerStage = 'eligible' | 'candidate' | 'selected' | 'exposed' | 'adopted' | 'positive_outcome' | 'negative_outcome' | 'unknown' | 'rejected';
1
+ export type RetrievalLedgerStage = 'eligible' | 'candidate' | 'selected' | 'exposed' | 'adopted' | 'consumed' | 'verified' | 'positive_outcome' | 'negative_outcome' | 'unknown' | 'unknown_outcome' | 'rejected';
2
2
  export type RetrievalLedgerSourceType = 'code' | 'memory' | 'knowledge' | 'action';
3
3
  export interface RetrievalLedgerEventRecord {
4
+ schemaVersion?: 'retrieval-ledger-event.v1';
4
5
  id: string;
5
6
  projectRoot: string;
6
7
  sessionId: string;
@@ -10,6 +11,12 @@ export interface RetrievalLedgerEventRecord {
10
11
  contextReceipt: string;
11
12
  sourceType: RetrievalLedgerSourceType;
12
13
  sourceId: string;
14
+ taskSpecHash?: string;
15
+ actor?: string;
16
+ sourceVersion?: string;
17
+ sourceContentHash?: string;
18
+ evidenceIds?: string[];
19
+ reasonCode?: string;
13
20
  stage: RetrievalLedgerStage;
14
21
  rank?: number;
15
22
  rawScore?: number;
@@ -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,14 +36,25 @@ 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;
40
56
  kinds?: WorkKind[];
57
+ workItemIds?: string[];
41
58
  limit: number;
42
59
  leaseMs: number;
43
60
  now?: number;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@devflow-tools/database",
3
- "version": "0.17.1",
3
+ "version": "0.17.3",
4
4
  "description": "DevFlow SQLite database package",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",