@knpkv/herdr-fleet 0.4.0 → 0.5.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/README.md +5 -0
- package/dist/service.d.ts +117 -117
- package/dist/sqlite.d.ts +86 -0
- package/dist/sqlite.d.ts.map +1 -0
- package/dist/sqlite.js +148 -0
- package/dist/sqlite.js.map +1 -0
- package/dist/store.d.ts +2 -2
- package/dist/store.d.ts.map +1 -1
- package/dist/store.js +24 -42
- package/dist/store.js.map +1 -1
- package/package.json +5 -1
package/README.md
CHANGED
|
@@ -15,6 +15,11 @@ The package exports:
|
|
|
15
15
|
- `JobStore`, the local SQLite persistence boundary
|
|
16
16
|
- `makeFleetService`, the approval and execution state machine
|
|
17
17
|
- typed validation, storage, approval, authorization, and operation errors
|
|
18
|
+
- `@knpkv/herdr-fleet/sqlite`, the private on-disk database opener for the `node:sqlite` Herdr stores, and the path checks the orchestrator database reuses
|
|
19
|
+
|
|
20
|
+
The `node:sqlite` stores (Fleet jobs, approvals, coordinator chat, Connect activity and relationships, Work) open their database through `openPrivateSqlite` from `@knpkv/herdr-fleet/sqlite`. The state directory and the database, `-wal` and `-shm` files are refused, unchanged, when they are symbolic links, the wrong type, or group/other writable; otherwise the directory is restricted to `0700` (created if missing) and the files to `0600`, and WAL is enabled after the store's schema step. Symlinked ancestors such as macOS `/var` are allowed. `preparePrivateDatabasePath` does the same file-system work for other clients.
|
|
21
|
+
|
|
22
|
+
The coordinator's orchestrator database (`@effect/sql-sqlite-node`) keeps its own, different policy: it requires an existing state directory to be exactly `0700` and refuses it otherwise, refuses symbolic links through `verifyPrivatePathIdentity`, and then sets the files to `0600` with `securePrivateDatabaseFiles`. It does not refuse a group-writable database file; it restricts it.
|
|
18
23
|
|
|
19
24
|
`HostConfiguration.pushAllowedOrigins` is the explicit exact-origin allowlist used by the approval runtime for browser push delivery. It has no implicit defaults; deployment configuration owns the accepted push services.
|
|
20
25
|
|
package/dist/service.d.ts
CHANGED
|
@@ -74,20 +74,11 @@ type Options = {
|
|
|
74
74
|
export declare const makeFleetService: (options: Options) => Effect.Effect<{
|
|
75
75
|
submit: (request: {
|
|
76
76
|
readonly payload: {
|
|
77
|
-
readonly kind: "nix.check";
|
|
78
|
-
} | {
|
|
79
|
-
readonly kind: "nix.apply";
|
|
80
|
-
readonly ref: string;
|
|
81
|
-
} | {
|
|
82
77
|
readonly kind: "agent.delegate";
|
|
83
78
|
readonly repository: string;
|
|
84
79
|
readonly prompt: string;
|
|
85
80
|
readonly mode: "consult" | "review" | "transition_summary" | "work";
|
|
86
81
|
readonly channel?: "coordinator_chat";
|
|
87
|
-
} | {
|
|
88
|
-
readonly kind: "agent.message";
|
|
89
|
-
readonly session: string;
|
|
90
|
-
readonly message: string;
|
|
91
82
|
} | {
|
|
92
83
|
readonly kind: "work.reconcile";
|
|
93
84
|
readonly repository: string;
|
|
@@ -214,6 +205,15 @@ export declare const makeFleetService: (options: Options) => Effect.Effect<{
|
|
|
214
205
|
readonly expectedGoalUpdatedAt: number;
|
|
215
206
|
} | {
|
|
216
207
|
readonly kind: "browser.mcp.recover";
|
|
208
|
+
} | {
|
|
209
|
+
readonly kind: "nix.check";
|
|
210
|
+
} | {
|
|
211
|
+
readonly kind: "nix.apply";
|
|
212
|
+
readonly ref: string;
|
|
213
|
+
} | {
|
|
214
|
+
readonly kind: "agent.message";
|
|
215
|
+
readonly session: string;
|
|
216
|
+
readonly message: string;
|
|
217
217
|
};
|
|
218
218
|
}, actor: string, provenance?: SubmissionProvenance | undefined) => Effect.Effect<{
|
|
219
219
|
readonly id: string;
|
|
@@ -230,20 +230,11 @@ export declare const makeFleetService: (options: Options) => Effect.Effect<{
|
|
|
230
230
|
readonly expiredAt?: number | null;
|
|
231
231
|
readonly status: "expired" | "failed" | "interrupted" | "pending_approval" | "queued" | "rejected" | "running" | "succeeded";
|
|
232
232
|
readonly payload: {
|
|
233
|
-
readonly kind: "nix.check";
|
|
234
|
-
} | {
|
|
235
|
-
readonly kind: "nix.apply";
|
|
236
|
-
readonly ref: string;
|
|
237
|
-
} | {
|
|
238
233
|
readonly kind: "agent.delegate";
|
|
239
234
|
readonly repository: string;
|
|
240
235
|
readonly prompt: string;
|
|
241
236
|
readonly mode: "consult" | "review" | "transition_summary" | "work";
|
|
242
237
|
readonly channel?: "coordinator_chat";
|
|
243
|
-
} | {
|
|
244
|
-
readonly kind: "agent.message";
|
|
245
|
-
readonly session: string;
|
|
246
|
-
readonly message: string;
|
|
247
238
|
} | {
|
|
248
239
|
readonly kind: "work.reconcile";
|
|
249
240
|
readonly repository: string;
|
|
@@ -370,6 +361,15 @@ export declare const makeFleetService: (options: Options) => Effect.Effect<{
|
|
|
370
361
|
readonly expectedGoalUpdatedAt: number;
|
|
371
362
|
} | {
|
|
372
363
|
readonly kind: "browser.mcp.recover";
|
|
364
|
+
} | {
|
|
365
|
+
readonly kind: "nix.check";
|
|
366
|
+
} | {
|
|
367
|
+
readonly kind: "nix.apply";
|
|
368
|
+
readonly ref: string;
|
|
369
|
+
} | {
|
|
370
|
+
readonly kind: "agent.message";
|
|
371
|
+
readonly session: string;
|
|
372
|
+
readonly message: string;
|
|
373
373
|
};
|
|
374
374
|
readonly result: string | null;
|
|
375
375
|
readonly acceptedReceipt?: string | null;
|
|
@@ -407,20 +407,11 @@ export declare const makeFleetService: (options: Options) => Effect.Effect<{
|
|
|
407
407
|
readonly expiredAt?: number | null;
|
|
408
408
|
readonly status: "expired" | "failed" | "interrupted" | "pending_approval" | "queued" | "rejected" | "running" | "succeeded";
|
|
409
409
|
readonly payload: {
|
|
410
|
-
readonly kind: "nix.check";
|
|
411
|
-
} | {
|
|
412
|
-
readonly kind: "nix.apply";
|
|
413
|
-
readonly ref: string;
|
|
414
|
-
} | {
|
|
415
410
|
readonly kind: "agent.delegate";
|
|
416
411
|
readonly repository: string;
|
|
417
412
|
readonly prompt: string;
|
|
418
413
|
readonly mode: "consult" | "review" | "transition_summary" | "work";
|
|
419
414
|
readonly channel?: "coordinator_chat";
|
|
420
|
-
} | {
|
|
421
|
-
readonly kind: "agent.message";
|
|
422
|
-
readonly session: string;
|
|
423
|
-
readonly message: string;
|
|
424
415
|
} | {
|
|
425
416
|
readonly kind: "work.reconcile";
|
|
426
417
|
readonly repository: string;
|
|
@@ -547,6 +538,15 @@ export declare const makeFleetService: (options: Options) => Effect.Effect<{
|
|
|
547
538
|
readonly expectedGoalUpdatedAt: number;
|
|
548
539
|
} | {
|
|
549
540
|
readonly kind: "browser.mcp.recover";
|
|
541
|
+
} | {
|
|
542
|
+
readonly kind: "nix.check";
|
|
543
|
+
} | {
|
|
544
|
+
readonly kind: "nix.apply";
|
|
545
|
+
readonly ref: string;
|
|
546
|
+
} | {
|
|
547
|
+
readonly kind: "agent.message";
|
|
548
|
+
readonly session: string;
|
|
549
|
+
readonly message: string;
|
|
550
550
|
};
|
|
551
551
|
readonly result: string | null;
|
|
552
552
|
readonly acceptedReceipt?: string | null;
|
|
@@ -584,20 +584,11 @@ export declare const makeFleetService: (options: Options) => Effect.Effect<{
|
|
|
584
584
|
readonly expiredAt?: number | null;
|
|
585
585
|
readonly status: "expired" | "failed" | "interrupted" | "pending_approval" | "queued" | "rejected" | "running" | "succeeded";
|
|
586
586
|
readonly payload: {
|
|
587
|
-
readonly kind: "nix.check";
|
|
588
|
-
} | {
|
|
589
|
-
readonly kind: "nix.apply";
|
|
590
|
-
readonly ref: string;
|
|
591
|
-
} | {
|
|
592
587
|
readonly kind: "agent.delegate";
|
|
593
588
|
readonly repository: string;
|
|
594
589
|
readonly prompt: string;
|
|
595
590
|
readonly mode: "consult" | "review" | "transition_summary" | "work";
|
|
596
591
|
readonly channel?: "coordinator_chat";
|
|
597
|
-
} | {
|
|
598
|
-
readonly kind: "agent.message";
|
|
599
|
-
readonly session: string;
|
|
600
|
-
readonly message: string;
|
|
601
592
|
} | {
|
|
602
593
|
readonly kind: "work.reconcile";
|
|
603
594
|
readonly repository: string;
|
|
@@ -724,6 +715,15 @@ export declare const makeFleetService: (options: Options) => Effect.Effect<{
|
|
|
724
715
|
readonly expectedGoalUpdatedAt: number;
|
|
725
716
|
} | {
|
|
726
717
|
readonly kind: "browser.mcp.recover";
|
|
718
|
+
} | {
|
|
719
|
+
readonly kind: "nix.check";
|
|
720
|
+
} | {
|
|
721
|
+
readonly kind: "nix.apply";
|
|
722
|
+
readonly ref: string;
|
|
723
|
+
} | {
|
|
724
|
+
readonly kind: "agent.message";
|
|
725
|
+
readonly session: string;
|
|
726
|
+
readonly message: string;
|
|
727
727
|
};
|
|
728
728
|
readonly result: string | null;
|
|
729
729
|
readonly acceptedReceipt?: string | null;
|
|
@@ -761,20 +761,11 @@ export declare const makeFleetService: (options: Options) => Effect.Effect<{
|
|
|
761
761
|
readonly expiredAt?: number | null;
|
|
762
762
|
readonly status: "expired" | "failed" | "interrupted" | "pending_approval" | "queued" | "rejected" | "running" | "succeeded";
|
|
763
763
|
readonly payload: {
|
|
764
|
-
readonly kind: "nix.check";
|
|
765
|
-
} | {
|
|
766
|
-
readonly kind: "nix.apply";
|
|
767
|
-
readonly ref: string;
|
|
768
|
-
} | {
|
|
769
764
|
readonly kind: "agent.delegate";
|
|
770
765
|
readonly repository: string;
|
|
771
766
|
readonly prompt: string;
|
|
772
767
|
readonly mode: "consult" | "review" | "transition_summary" | "work";
|
|
773
768
|
readonly channel?: "coordinator_chat";
|
|
774
|
-
} | {
|
|
775
|
-
readonly kind: "agent.message";
|
|
776
|
-
readonly session: string;
|
|
777
|
-
readonly message: string;
|
|
778
769
|
} | {
|
|
779
770
|
readonly kind: "work.reconcile";
|
|
780
771
|
readonly repository: string;
|
|
@@ -901,6 +892,15 @@ export declare const makeFleetService: (options: Options) => Effect.Effect<{
|
|
|
901
892
|
readonly expectedGoalUpdatedAt: number;
|
|
902
893
|
} | {
|
|
903
894
|
readonly kind: "browser.mcp.recover";
|
|
895
|
+
} | {
|
|
896
|
+
readonly kind: "nix.check";
|
|
897
|
+
} | {
|
|
898
|
+
readonly kind: "nix.apply";
|
|
899
|
+
readonly ref: string;
|
|
900
|
+
} | {
|
|
901
|
+
readonly kind: "agent.message";
|
|
902
|
+
readonly session: string;
|
|
903
|
+
readonly message: string;
|
|
904
904
|
};
|
|
905
905
|
readonly result: string | null;
|
|
906
906
|
readonly acceptedReceipt?: string | null;
|
|
@@ -938,20 +938,11 @@ export declare const makeFleetService: (options: Options) => Effect.Effect<{
|
|
|
938
938
|
readonly expiredAt?: number | null;
|
|
939
939
|
readonly status: "expired" | "failed" | "interrupted" | "pending_approval" | "queued" | "rejected" | "running" | "succeeded";
|
|
940
940
|
readonly payload: {
|
|
941
|
-
readonly kind: "nix.check";
|
|
942
|
-
} | {
|
|
943
|
-
readonly kind: "nix.apply";
|
|
944
|
-
readonly ref: string;
|
|
945
|
-
} | {
|
|
946
941
|
readonly kind: "agent.delegate";
|
|
947
942
|
readonly repository: string;
|
|
948
943
|
readonly prompt: string;
|
|
949
944
|
readonly mode: "consult" | "review" | "transition_summary" | "work";
|
|
950
945
|
readonly channel?: "coordinator_chat";
|
|
951
|
-
} | {
|
|
952
|
-
readonly kind: "agent.message";
|
|
953
|
-
readonly session: string;
|
|
954
|
-
readonly message: string;
|
|
955
946
|
} | {
|
|
956
947
|
readonly kind: "work.reconcile";
|
|
957
948
|
readonly repository: string;
|
|
@@ -1078,6 +1069,15 @@ export declare const makeFleetService: (options: Options) => Effect.Effect<{
|
|
|
1078
1069
|
readonly expectedGoalUpdatedAt: number;
|
|
1079
1070
|
} | {
|
|
1080
1071
|
readonly kind: "browser.mcp.recover";
|
|
1072
|
+
} | {
|
|
1073
|
+
readonly kind: "nix.check";
|
|
1074
|
+
} | {
|
|
1075
|
+
readonly kind: "nix.apply";
|
|
1076
|
+
readonly ref: string;
|
|
1077
|
+
} | {
|
|
1078
|
+
readonly kind: "agent.message";
|
|
1079
|
+
readonly session: string;
|
|
1080
|
+
readonly message: string;
|
|
1081
1081
|
};
|
|
1082
1082
|
readonly result: string | null;
|
|
1083
1083
|
readonly acceptedReceipt?: string | null;
|
|
@@ -1115,20 +1115,11 @@ export declare const makeFleetService: (options: Options) => Effect.Effect<{
|
|
|
1115
1115
|
readonly expiredAt?: number | null;
|
|
1116
1116
|
readonly status: "expired" | "failed" | "interrupted" | "pending_approval" | "queued" | "rejected" | "running" | "succeeded";
|
|
1117
1117
|
readonly payload: {
|
|
1118
|
-
readonly kind: "nix.check";
|
|
1119
|
-
} | {
|
|
1120
|
-
readonly kind: "nix.apply";
|
|
1121
|
-
readonly ref: string;
|
|
1122
|
-
} | {
|
|
1123
1118
|
readonly kind: "agent.delegate";
|
|
1124
1119
|
readonly repository: string;
|
|
1125
1120
|
readonly prompt: string;
|
|
1126
1121
|
readonly mode: "consult" | "review" | "transition_summary" | "work";
|
|
1127
1122
|
readonly channel?: "coordinator_chat";
|
|
1128
|
-
} | {
|
|
1129
|
-
readonly kind: "agent.message";
|
|
1130
|
-
readonly session: string;
|
|
1131
|
-
readonly message: string;
|
|
1132
1123
|
} | {
|
|
1133
1124
|
readonly kind: "work.reconcile";
|
|
1134
1125
|
readonly repository: string;
|
|
@@ -1255,6 +1246,15 @@ export declare const makeFleetService: (options: Options) => Effect.Effect<{
|
|
|
1255
1246
|
readonly expectedGoalUpdatedAt: number;
|
|
1256
1247
|
} | {
|
|
1257
1248
|
readonly kind: "browser.mcp.recover";
|
|
1249
|
+
} | {
|
|
1250
|
+
readonly kind: "nix.check";
|
|
1251
|
+
} | {
|
|
1252
|
+
readonly kind: "nix.apply";
|
|
1253
|
+
readonly ref: string;
|
|
1254
|
+
} | {
|
|
1255
|
+
readonly kind: "agent.message";
|
|
1256
|
+
readonly session: string;
|
|
1257
|
+
readonly message: string;
|
|
1258
1258
|
};
|
|
1259
1259
|
readonly result: string | null;
|
|
1260
1260
|
readonly acceptedReceipt?: string | null;
|
|
@@ -1292,20 +1292,11 @@ export declare const makeFleetService: (options: Options) => Effect.Effect<{
|
|
|
1292
1292
|
readonly expiredAt?: number | null;
|
|
1293
1293
|
readonly status: "expired" | "failed" | "interrupted" | "pending_approval" | "queued" | "rejected" | "running" | "succeeded";
|
|
1294
1294
|
readonly payload: {
|
|
1295
|
-
readonly kind: "nix.check";
|
|
1296
|
-
} | {
|
|
1297
|
-
readonly kind: "nix.apply";
|
|
1298
|
-
readonly ref: string;
|
|
1299
|
-
} | {
|
|
1300
1295
|
readonly kind: "agent.delegate";
|
|
1301
1296
|
readonly repository: string;
|
|
1302
1297
|
readonly prompt: string;
|
|
1303
1298
|
readonly mode: "consult" | "review" | "transition_summary" | "work";
|
|
1304
1299
|
readonly channel?: "coordinator_chat";
|
|
1305
|
-
} | {
|
|
1306
|
-
readonly kind: "agent.message";
|
|
1307
|
-
readonly session: string;
|
|
1308
|
-
readonly message: string;
|
|
1309
1300
|
} | {
|
|
1310
1301
|
readonly kind: "work.reconcile";
|
|
1311
1302
|
readonly repository: string;
|
|
@@ -1432,6 +1423,15 @@ export declare const makeFleetService: (options: Options) => Effect.Effect<{
|
|
|
1432
1423
|
readonly expectedGoalUpdatedAt: number;
|
|
1433
1424
|
} | {
|
|
1434
1425
|
readonly kind: "browser.mcp.recover";
|
|
1426
|
+
} | {
|
|
1427
|
+
readonly kind: "nix.check";
|
|
1428
|
+
} | {
|
|
1429
|
+
readonly kind: "nix.apply";
|
|
1430
|
+
readonly ref: string;
|
|
1431
|
+
} | {
|
|
1432
|
+
readonly kind: "agent.message";
|
|
1433
|
+
readonly session: string;
|
|
1434
|
+
readonly message: string;
|
|
1435
1435
|
};
|
|
1436
1436
|
readonly result: string | null;
|
|
1437
1437
|
readonly acceptedReceipt?: string | null;
|
|
@@ -1472,20 +1472,11 @@ export declare const makeFleetService: (options: Options) => Effect.Effect<{
|
|
|
1472
1472
|
readonly expiredAt?: number | null;
|
|
1473
1473
|
readonly status: "expired" | "failed" | "interrupted" | "pending_approval" | "queued" | "rejected" | "running" | "succeeded";
|
|
1474
1474
|
readonly payload: {
|
|
1475
|
-
readonly kind: "nix.check";
|
|
1476
|
-
} | {
|
|
1477
|
-
readonly kind: "nix.apply";
|
|
1478
|
-
readonly ref: string;
|
|
1479
|
-
} | {
|
|
1480
1475
|
readonly kind: "agent.delegate";
|
|
1481
1476
|
readonly repository: string;
|
|
1482
1477
|
readonly prompt: string;
|
|
1483
1478
|
readonly mode: "consult" | "review" | "transition_summary" | "work";
|
|
1484
1479
|
readonly channel?: "coordinator_chat";
|
|
1485
|
-
} | {
|
|
1486
|
-
readonly kind: "agent.message";
|
|
1487
|
-
readonly session: string;
|
|
1488
|
-
readonly message: string;
|
|
1489
1480
|
} | {
|
|
1490
1481
|
readonly kind: "work.reconcile";
|
|
1491
1482
|
readonly repository: string;
|
|
@@ -1612,6 +1603,15 @@ export declare const makeFleetService: (options: Options) => Effect.Effect<{
|
|
|
1612
1603
|
readonly expectedGoalUpdatedAt: number;
|
|
1613
1604
|
} | {
|
|
1614
1605
|
readonly kind: "browser.mcp.recover";
|
|
1606
|
+
} | {
|
|
1607
|
+
readonly kind: "nix.check";
|
|
1608
|
+
} | {
|
|
1609
|
+
readonly kind: "nix.apply";
|
|
1610
|
+
readonly ref: string;
|
|
1611
|
+
} | {
|
|
1612
|
+
readonly kind: "agent.message";
|
|
1613
|
+
readonly session: string;
|
|
1614
|
+
readonly message: string;
|
|
1615
1615
|
};
|
|
1616
1616
|
readonly result: string | null;
|
|
1617
1617
|
readonly acceptedReceipt?: string | null;
|
|
@@ -1653,20 +1653,11 @@ export declare const makeFleetService: (options: Options) => Effect.Effect<{
|
|
|
1653
1653
|
readonly expiredAt?: number | null;
|
|
1654
1654
|
readonly status: "expired" | "failed" | "interrupted" | "pending_approval" | "queued" | "rejected" | "running" | "succeeded";
|
|
1655
1655
|
readonly payload: {
|
|
1656
|
-
readonly kind: "nix.check";
|
|
1657
|
-
} | {
|
|
1658
|
-
readonly kind: "nix.apply";
|
|
1659
|
-
readonly ref: string;
|
|
1660
|
-
} | {
|
|
1661
1656
|
readonly kind: "agent.delegate";
|
|
1662
1657
|
readonly repository: string;
|
|
1663
1658
|
readonly prompt: string;
|
|
1664
1659
|
readonly mode: "consult" | "review" | "transition_summary" | "work";
|
|
1665
1660
|
readonly channel?: "coordinator_chat";
|
|
1666
|
-
} | {
|
|
1667
|
-
readonly kind: "agent.message";
|
|
1668
|
-
readonly session: string;
|
|
1669
|
-
readonly message: string;
|
|
1670
1661
|
} | {
|
|
1671
1662
|
readonly kind: "work.reconcile";
|
|
1672
1663
|
readonly repository: string;
|
|
@@ -1793,6 +1784,15 @@ export declare const makeFleetService: (options: Options) => Effect.Effect<{
|
|
|
1793
1784
|
readonly expectedGoalUpdatedAt: number;
|
|
1794
1785
|
} | {
|
|
1795
1786
|
readonly kind: "browser.mcp.recover";
|
|
1787
|
+
} | {
|
|
1788
|
+
readonly kind: "nix.check";
|
|
1789
|
+
} | {
|
|
1790
|
+
readonly kind: "nix.apply";
|
|
1791
|
+
readonly ref: string;
|
|
1792
|
+
} | {
|
|
1793
|
+
readonly kind: "agent.message";
|
|
1794
|
+
readonly session: string;
|
|
1795
|
+
readonly message: string;
|
|
1796
1796
|
};
|
|
1797
1797
|
readonly result: string | null;
|
|
1798
1798
|
readonly acceptedReceipt?: string | null;
|
|
@@ -1839,20 +1839,11 @@ export declare const makeFleetService: (options: Options) => Effect.Effect<{
|
|
|
1839
1839
|
readonly expiredAt?: number | null;
|
|
1840
1840
|
readonly status: "expired" | "failed" | "interrupted" | "pending_approval" | "queued" | "rejected" | "running" | "succeeded";
|
|
1841
1841
|
readonly payload: {
|
|
1842
|
-
readonly kind: "nix.check";
|
|
1843
|
-
} | {
|
|
1844
|
-
readonly kind: "nix.apply";
|
|
1845
|
-
readonly ref: string;
|
|
1846
|
-
} | {
|
|
1847
1842
|
readonly kind: "agent.delegate";
|
|
1848
1843
|
readonly repository: string;
|
|
1849
1844
|
readonly prompt: string;
|
|
1850
1845
|
readonly mode: "consult" | "review" | "transition_summary" | "work";
|
|
1851
1846
|
readonly channel?: "coordinator_chat";
|
|
1852
|
-
} | {
|
|
1853
|
-
readonly kind: "agent.message";
|
|
1854
|
-
readonly session: string;
|
|
1855
|
-
readonly message: string;
|
|
1856
1847
|
} | {
|
|
1857
1848
|
readonly kind: "work.reconcile";
|
|
1858
1849
|
readonly repository: string;
|
|
@@ -1979,6 +1970,15 @@ export declare const makeFleetService: (options: Options) => Effect.Effect<{
|
|
|
1979
1970
|
readonly expectedGoalUpdatedAt: number;
|
|
1980
1971
|
} | {
|
|
1981
1972
|
readonly kind: "browser.mcp.recover";
|
|
1973
|
+
} | {
|
|
1974
|
+
readonly kind: "nix.check";
|
|
1975
|
+
} | {
|
|
1976
|
+
readonly kind: "nix.apply";
|
|
1977
|
+
readonly ref: string;
|
|
1978
|
+
} | {
|
|
1979
|
+
readonly kind: "agent.message";
|
|
1980
|
+
readonly session: string;
|
|
1981
|
+
readonly message: string;
|
|
1982
1982
|
};
|
|
1983
1983
|
readonly result: string | null;
|
|
1984
1984
|
readonly acceptedReceipt?: string | null;
|
|
@@ -2021,20 +2021,11 @@ export declare const makeFleetService: (options: Options) => Effect.Effect<{
|
|
|
2021
2021
|
readonly expiredAt?: number | null;
|
|
2022
2022
|
readonly status: "expired" | "failed" | "interrupted" | "pending_approval" | "queued" | "rejected" | "running" | "succeeded";
|
|
2023
2023
|
readonly payload: {
|
|
2024
|
-
readonly kind: "nix.check";
|
|
2025
|
-
} | {
|
|
2026
|
-
readonly kind: "nix.apply";
|
|
2027
|
-
readonly ref: string;
|
|
2028
|
-
} | {
|
|
2029
2024
|
readonly kind: "agent.delegate";
|
|
2030
2025
|
readonly repository: string;
|
|
2031
2026
|
readonly prompt: string;
|
|
2032
2027
|
readonly mode: "consult" | "review" | "transition_summary" | "work";
|
|
2033
2028
|
readonly channel?: "coordinator_chat";
|
|
2034
|
-
} | {
|
|
2035
|
-
readonly kind: "agent.message";
|
|
2036
|
-
readonly session: string;
|
|
2037
|
-
readonly message: string;
|
|
2038
2029
|
} | {
|
|
2039
2030
|
readonly kind: "work.reconcile";
|
|
2040
2031
|
readonly repository: string;
|
|
@@ -2161,6 +2152,15 @@ export declare const makeFleetService: (options: Options) => Effect.Effect<{
|
|
|
2161
2152
|
readonly expectedGoalUpdatedAt: number;
|
|
2162
2153
|
} | {
|
|
2163
2154
|
readonly kind: "browser.mcp.recover";
|
|
2155
|
+
} | {
|
|
2156
|
+
readonly kind: "nix.check";
|
|
2157
|
+
} | {
|
|
2158
|
+
readonly kind: "nix.apply";
|
|
2159
|
+
readonly ref: string;
|
|
2160
|
+
} | {
|
|
2161
|
+
readonly kind: "agent.message";
|
|
2162
|
+
readonly session: string;
|
|
2163
|
+
readonly message: string;
|
|
2164
2164
|
};
|
|
2165
2165
|
readonly result: string | null;
|
|
2166
2166
|
readonly acceptedReceipt?: string | null;
|
|
@@ -2250,20 +2250,11 @@ export declare const makeFleetService: (options: Options) => Effect.Effect<{
|
|
|
2250
2250
|
readonly expiredAt?: number | null;
|
|
2251
2251
|
readonly status: "expired" | "failed" | "interrupted" | "pending_approval" | "queued" | "rejected" | "running" | "succeeded";
|
|
2252
2252
|
readonly payload: {
|
|
2253
|
-
readonly kind: "nix.check";
|
|
2254
|
-
} | {
|
|
2255
|
-
readonly kind: "nix.apply";
|
|
2256
|
-
readonly ref: string;
|
|
2257
|
-
} | {
|
|
2258
2253
|
readonly kind: "agent.delegate";
|
|
2259
2254
|
readonly repository: string;
|
|
2260
2255
|
readonly prompt: string;
|
|
2261
2256
|
readonly mode: "consult" | "review" | "transition_summary" | "work";
|
|
2262
2257
|
readonly channel?: "coordinator_chat";
|
|
2263
|
-
} | {
|
|
2264
|
-
readonly kind: "agent.message";
|
|
2265
|
-
readonly session: string;
|
|
2266
|
-
readonly message: string;
|
|
2267
2258
|
} | {
|
|
2268
2259
|
readonly kind: "work.reconcile";
|
|
2269
2260
|
readonly repository: string;
|
|
@@ -2390,6 +2381,15 @@ export declare const makeFleetService: (options: Options) => Effect.Effect<{
|
|
|
2390
2381
|
readonly expectedGoalUpdatedAt: number;
|
|
2391
2382
|
} | {
|
|
2392
2383
|
readonly kind: "browser.mcp.recover";
|
|
2384
|
+
} | {
|
|
2385
|
+
readonly kind: "nix.check";
|
|
2386
|
+
} | {
|
|
2387
|
+
readonly kind: "nix.apply";
|
|
2388
|
+
readonly ref: string;
|
|
2389
|
+
} | {
|
|
2390
|
+
readonly kind: "agent.message";
|
|
2391
|
+
readonly session: string;
|
|
2392
|
+
readonly message: string;
|
|
2393
2393
|
};
|
|
2394
2394
|
readonly result: string | null;
|
|
2395
2395
|
readonly acceptedReceipt?: string | null;
|
package/dist/sqlite.d.ts
ADDED
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Private on-disk SQLite databases for Herdr stores.
|
|
3
|
+
*
|
|
4
|
+
* **Mental model**
|
|
5
|
+
*
|
|
6
|
+
* - **Refuse, never repair.** A state directory or database file that other users
|
|
7
|
+
* could write is refused, and left exactly as found. Repairing it would hide that
|
|
8
|
+
* someone could already have changed it.
|
|
9
|
+
* - **Owner-only once accepted.** The state directory ends `0700` and the database
|
|
10
|
+
* files `0600`; an existing directory is checked before it is restricted, so a
|
|
11
|
+
* writable one is refused rather than quietly fixed.
|
|
12
|
+
* - **Only the last path component is checked for a symlink.** Symlinked ancestors
|
|
13
|
+
* (macOS `/var`, a Nix-managed home) are normal and allowed; a database or state
|
|
14
|
+
* directory that is itself a link is refused.
|
|
15
|
+
* - **Two layers.** {@link preparePrivateDatabasePath} and
|
|
16
|
+
* {@link securePrivateDatabaseFiles} only touch the file system, so any SQLite
|
|
17
|
+
* client can use them; {@link openPrivateSqlite} adds the `node:sqlite` connection.
|
|
18
|
+
*
|
|
19
|
+
* @example
|
|
20
|
+
* ```ts
|
|
21
|
+
* const opened = yield* openPrivateSqlite(path, {
|
|
22
|
+
* initialize: (database) => database.exec("CREATE TABLE IF NOT EXISTS jobs (id TEXT PRIMARY KEY)")
|
|
23
|
+
* })
|
|
24
|
+
* // after each write, WAL may have created -wal/-shm:
|
|
25
|
+
* yield* opened.secureFiles
|
|
26
|
+
* ```
|
|
27
|
+
*
|
|
28
|
+
* @module
|
|
29
|
+
*/
|
|
30
|
+
import { Effect, FileSystem, Path, Schema } from "effect";
|
|
31
|
+
import { DatabaseSync } from "node:sqlite";
|
|
32
|
+
declare const PrivateDatabaseError_base: Schema.Class<PrivateDatabaseError, Schema.TaggedStruct<"PrivateDatabaseError", {
|
|
33
|
+
readonly operation: Schema.String;
|
|
34
|
+
readonly cause: Schema.Defect;
|
|
35
|
+
}>, import("effect/Cause").YieldableError>;
|
|
36
|
+
/** One step of opening or securing a private database failed; `operation` names the step. */
|
|
37
|
+
export declare class PrivateDatabaseError extends PrivateDatabaseError_base {
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Refuse `path` if it is itself a symlink or does not resolve to its real parent
|
|
41
|
+
* joined with its name; a missing component is checked through its parent.
|
|
42
|
+
* Failures carry `operation` (sub-steps append `.readlink`, `.exists`, …).
|
|
43
|
+
*/
|
|
44
|
+
export declare const verifyPrivatePathIdentity: (path: string, operation: string) => Effect.Effect<void, PrivateDatabaseError, FileSystem.FileSystem | Path.Path>;
|
|
45
|
+
/**
|
|
46
|
+
* Make `path`'s directory and any existing database files safe to open, or refuse.
|
|
47
|
+
*
|
|
48
|
+
* Refuses a directory or file that is a symlink, the wrong type, or group/other
|
|
49
|
+
* writable, without changing it. Otherwise restricts the directory (created if
|
|
50
|
+
* missing) to `0700` and existing db/-wal/-shm files to `0600`.
|
|
51
|
+
*/
|
|
52
|
+
export declare const preparePrivateDatabasePath: (path: string) => Effect.Effect<undefined, PrivateDatabaseError, FileSystem.FileSystem | Path.Path>;
|
|
53
|
+
/**
|
|
54
|
+
* Set the database file and its `-wal`/`-shm` siblings, whichever exist, to `0600`.
|
|
55
|
+
*
|
|
56
|
+
* SQLite creates the siblings lazily, so call this after writes as well as after
|
|
57
|
+
* opening. A sibling that has become a symlink is refused rather than followed.
|
|
58
|
+
*/
|
|
59
|
+
export declare const securePrivateDatabaseFiles: (path: string) => Effect.Effect<void, PrivateDatabaseError, FileSystem.FileSystem | Path.Path>;
|
|
60
|
+
/** An open `node:sqlite` connection to a private database. */
|
|
61
|
+
export interface PrivateSqlite {
|
|
62
|
+
readonly database: DatabaseSync;
|
|
63
|
+
/** {@link securePrivateDatabaseFiles} for this database; run after writes. */
|
|
64
|
+
readonly secureFiles: Effect.Effect<void, PrivateDatabaseError>;
|
|
65
|
+
}
|
|
66
|
+
export interface OpenPrivateSqliteOptions {
|
|
67
|
+
/**
|
|
68
|
+
* Creates or migrates the schema; a throw closes the connection. Runs before WAL
|
|
69
|
+
* is enabled, so a legacy rollback-journal database migrates in its own mode first
|
|
70
|
+
* (Work's legacy authority-table migration fails with "database is locked" otherwise).
|
|
71
|
+
*/
|
|
72
|
+
readonly initialize: (database: DatabaseSync) => void;
|
|
73
|
+
/** Wait up to this long for another connection's lock instead of failing at once. */
|
|
74
|
+
readonly busyTimeoutMillis?: number;
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Prepare `path` (see {@link preparePrivateDatabasePath}), open it in WAL mode,
|
|
78
|
+
* initialize the schema and secure the files. The caller owns the returned
|
|
79
|
+
* connection and must close it.
|
|
80
|
+
*/
|
|
81
|
+
export declare const openPrivateSqlite: (path: string, options: OpenPrivateSqliteOptions) => Effect.Effect<{
|
|
82
|
+
database: DatabaseSync;
|
|
83
|
+
secureFiles: Effect.Effect<void, PrivateDatabaseError, never>;
|
|
84
|
+
}, PrivateDatabaseError, FileSystem.FileSystem | Path.Path>;
|
|
85
|
+
export {};
|
|
86
|
+
//# sourceMappingURL=sqlite.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sqlite.d.ts","sourceRoot":"","sources":["../src/sqlite.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAA;AACzD,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAA;;;;;AAE1C,6FAA6F;AAC7F,qBAAa,oBAAqB,SAAQ,yBAMzC;CAAG;AA2CJ;;;;GAIG;AACH,eAAO,MAAM,yBAAyB,mHAOpC,CAAA;AAEF;;;;;;GAMG;AACH,eAAO,MAAM,0BAA0B,qGAwCrC,CAAA;AAEF;;;;;GAKG;AACH,eAAO,MAAM,0BAA0B,gGAcrC,CAAA;AAEF,8DAA8D;AAC9D,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,QAAQ,EAAE,YAAY,CAAA;IAC/B,8EAA8E;IAC9E,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,oBAAoB,CAAC,CAAA;CAChE;AAED,MAAM,WAAW,wBAAwB;IACvC;;;;OAIG;IACH,QAAQ,CAAC,UAAU,EAAE,CAAC,QAAQ,EAAE,YAAY,KAAK,IAAI,CAAA;IACrD,qFAAqF;IACrF,QAAQ,CAAC,iBAAiB,CAAC,EAAE,MAAM,CAAA;CACpC;AAED;;;;GAIG;AACH,eAAO,MAAM,iBAAiB;;;2DA8B5B,CAAA"}
|
package/dist/sqlite.js
ADDED
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Private on-disk SQLite databases for Herdr stores.
|
|
3
|
+
*
|
|
4
|
+
* **Mental model**
|
|
5
|
+
*
|
|
6
|
+
* - **Refuse, never repair.** A state directory or database file that other users
|
|
7
|
+
* could write is refused, and left exactly as found. Repairing it would hide that
|
|
8
|
+
* someone could already have changed it.
|
|
9
|
+
* - **Owner-only once accepted.** The state directory ends `0700` and the database
|
|
10
|
+
* files `0600`; an existing directory is checked before it is restricted, so a
|
|
11
|
+
* writable one is refused rather than quietly fixed.
|
|
12
|
+
* - **Only the last path component is checked for a symlink.** Symlinked ancestors
|
|
13
|
+
* (macOS `/var`, a Nix-managed home) are normal and allowed; a database or state
|
|
14
|
+
* directory that is itself a link is refused.
|
|
15
|
+
* - **Two layers.** {@link preparePrivateDatabasePath} and
|
|
16
|
+
* {@link securePrivateDatabaseFiles} only touch the file system, so any SQLite
|
|
17
|
+
* client can use them; {@link openPrivateSqlite} adds the `node:sqlite` connection.
|
|
18
|
+
*
|
|
19
|
+
* @example
|
|
20
|
+
* ```ts
|
|
21
|
+
* const opened = yield* openPrivateSqlite(path, {
|
|
22
|
+
* initialize: (database) => database.exec("CREATE TABLE IF NOT EXISTS jobs (id TEXT PRIMARY KEY)")
|
|
23
|
+
* })
|
|
24
|
+
* // after each write, WAL may have created -wal/-shm:
|
|
25
|
+
* yield* opened.secureFiles
|
|
26
|
+
* ```
|
|
27
|
+
*
|
|
28
|
+
* @module
|
|
29
|
+
*/
|
|
30
|
+
import { Effect, FileSystem, Path, Schema } from "effect";
|
|
31
|
+
import { DatabaseSync } from "node:sqlite";
|
|
32
|
+
/** One step of opening or securing a private database failed; `operation` names the step. */
|
|
33
|
+
export class PrivateDatabaseError extends Schema.TaggedError()("PrivateDatabaseError", {
|
|
34
|
+
operation: Schema.String,
|
|
35
|
+
cause: Schema.Defect()
|
|
36
|
+
}) {
|
|
37
|
+
}
|
|
38
|
+
const failWith = (operation) => (cause) => new PrivateDatabaseError({ operation, cause });
|
|
39
|
+
const groupOrOtherWritable = (paths, mode) => paths.sep === "/" && (mode & 0o022) !== 0;
|
|
40
|
+
const databaseFiles = (path) => [path, `${path}-wal`, `${path}-shm`];
|
|
41
|
+
// Refuses `path` when it is itself a symlink — including a dangling one — or when
|
|
42
|
+
// its real path is not its real parent joined with its name. A component that does
|
|
43
|
+
// not exist yet is checked through its parent.
|
|
44
|
+
const verifyPathIdentity = (path, fileSystem, paths, operation) => fileSystem.readLink(path).pipe(Effect.matchEffect({
|
|
45
|
+
onFailure: (cause) => cause.reason._tag === "NotFound" || cause.reason._tag === "Unknown"
|
|
46
|
+
? Effect.void
|
|
47
|
+
: Effect.fail(new PrivateDatabaseError({ cause, operation: `${operation}.readlink` })),
|
|
48
|
+
onSuccess: (target) => Effect.fail(new PrivateDatabaseError({ cause: { path, target }, operation }))
|
|
49
|
+
}), Effect.andThen(fileSystem.exists(path).pipe(Effect.mapError(failWith(`${operation}.exists`)))), Effect.flatMap((exists) => {
|
|
50
|
+
const parent = paths.dirname(path);
|
|
51
|
+
if (!exists) {
|
|
52
|
+
return parent === path ? Effect.void : verifyPathIdentity(parent, fileSystem, paths, operation);
|
|
53
|
+
}
|
|
54
|
+
return Effect.all({
|
|
55
|
+
realPath: fileSystem.realPath(path).pipe(Effect.mapError(failWith(`${operation}.realpath`))),
|
|
56
|
+
realParentPath: fileSystem.realPath(parent).pipe(Effect.mapError(failWith(`${operation}.parent-realpath`)))
|
|
57
|
+
}).pipe(Effect.flatMap(({ realParentPath, realPath }) => {
|
|
58
|
+
const expectedPath = paths.join(realParentPath, paths.basename(path));
|
|
59
|
+
return realPath === expectedPath
|
|
60
|
+
? Effect.void
|
|
61
|
+
: Effect.fail(new PrivateDatabaseError({ cause: { expectedPath, path, realPath }, operation }));
|
|
62
|
+
}));
|
|
63
|
+
}));
|
|
64
|
+
/**
|
|
65
|
+
* Refuse `path` if it is itself a symlink or does not resolve to its real parent
|
|
66
|
+
* joined with its name; a missing component is checked through its parent.
|
|
67
|
+
* Failures carry `operation` (sub-steps append `.readlink`, `.exists`, …).
|
|
68
|
+
*/
|
|
69
|
+
export const verifyPrivatePathIdentity = Effect.fn("PrivateDatabase.verifyPathIdentity")(function* (path, operation) {
|
|
70
|
+
const fileSystem = yield* FileSystem.FileSystem;
|
|
71
|
+
const paths = yield* Path.Path;
|
|
72
|
+
yield* verifyPathIdentity(path, fileSystem, paths, operation);
|
|
73
|
+
});
|
|
74
|
+
/**
|
|
75
|
+
* Make `path`'s directory and any existing database files safe to open, or refuse.
|
|
76
|
+
*
|
|
77
|
+
* Refuses a directory or file that is a symlink, the wrong type, or group/other
|
|
78
|
+
* writable, without changing it. Otherwise restricts the directory (created if
|
|
79
|
+
* missing) to `0700` and existing db/-wal/-shm files to `0600`.
|
|
80
|
+
*/
|
|
81
|
+
export const preparePrivateDatabasePath = Effect.fn("PrivateDatabase.prepare")(function* (path) {
|
|
82
|
+
const fileSystem = yield* FileSystem.FileSystem;
|
|
83
|
+
const paths = yield* Path.Path;
|
|
84
|
+
const directory = paths.dirname(path);
|
|
85
|
+
yield* fileSystem.makeDirectory(directory, { recursive: true, mode: 0o700 }).pipe(Effect.mapError(failWith("open.directory")));
|
|
86
|
+
const directoryInfo = yield* fileSystem.stat(directory).pipe(Effect.mapError(failWith("open.directory.stat")));
|
|
87
|
+
if (directoryInfo.type !== "Directory" || groupOrOtherWritable(paths, directoryInfo.mode)) {
|
|
88
|
+
return yield* new PrivateDatabaseError({
|
|
89
|
+
cause: { directory, mode: directoryInfo.mode, type: directoryInfo.type },
|
|
90
|
+
operation: "open.directory.unsafe"
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
yield* verifyPathIdentity(directory, fileSystem, paths, "open.directory.path-identity");
|
|
94
|
+
yield* fileSystem.chmod(directory, 0o700).pipe(Effect.mapError(failWith("open.secureDirectory")));
|
|
95
|
+
yield* Effect.forEach(databaseFiles(path), (file) => verifyPathIdentity(file, fileSystem, paths, "open.path-identity").pipe(Effect.andThen(fileSystem.exists(file).pipe(Effect.mapError(failWith("open.file.exists")))), Effect.flatMap((exists) => {
|
|
96
|
+
if (!exists)
|
|
97
|
+
return Effect.void;
|
|
98
|
+
return fileSystem.stat(file).pipe(Effect.mapError(failWith("open.file.stat")), Effect.flatMap((info) => info.type !== "File" || groupOrOtherWritable(paths, info.mode)
|
|
99
|
+
? Effect.fail(new PrivateDatabaseError({
|
|
100
|
+
cause: { file, mode: info.mode, type: info.type },
|
|
101
|
+
operation: "open.file.unsafe"
|
|
102
|
+
}))
|
|
103
|
+
: fileSystem.chmod(file, 0o600).pipe(Effect.mapError(failWith("open.file.secure")))));
|
|
104
|
+
})), { discard: true });
|
|
105
|
+
});
|
|
106
|
+
/**
|
|
107
|
+
* Set the database file and its `-wal`/`-shm` siblings, whichever exist, to `0600`.
|
|
108
|
+
*
|
|
109
|
+
* SQLite creates the siblings lazily, so call this after writes as well as after
|
|
110
|
+
* opening. A sibling that has become a symlink is refused rather than followed.
|
|
111
|
+
*/
|
|
112
|
+
export const securePrivateDatabaseFiles = Effect.fn("PrivateDatabase.secureFiles")(function* (path) {
|
|
113
|
+
const fileSystem = yield* FileSystem.FileSystem;
|
|
114
|
+
const paths = yield* Path.Path;
|
|
115
|
+
yield* Effect.forEach(databaseFiles(path), (file) => verifyPathIdentity(file, fileSystem, paths, "secure.path-identity").pipe(Effect.andThen(fileSystem.exists(file).pipe(Effect.mapError(failWith("secure.exists")))), Effect.flatMap((exists) => exists ? fileSystem.chmod(file, 0o600).pipe(Effect.mapError(failWith("secure.chmod"))) : Effect.void)), { discard: true });
|
|
116
|
+
});
|
|
117
|
+
/**
|
|
118
|
+
* Prepare `path` (see {@link preparePrivateDatabasePath}), open it in WAL mode,
|
|
119
|
+
* initialize the schema and secure the files. The caller owns the returned
|
|
120
|
+
* connection and must close it.
|
|
121
|
+
*/
|
|
122
|
+
export const openPrivateSqlite = Effect.fn("PrivateDatabase.openSqlite")(function* (path, options) {
|
|
123
|
+
const fileSystem = yield* FileSystem.FileSystem;
|
|
124
|
+
const paths = yield* Path.Path;
|
|
125
|
+
yield* preparePrivateDatabasePath(path);
|
|
126
|
+
const database = yield* Effect.try({
|
|
127
|
+
try: () => {
|
|
128
|
+
const database = new DatabaseSync(path);
|
|
129
|
+
try {
|
|
130
|
+
if (options.busyTimeoutMillis !== undefined) {
|
|
131
|
+
database.exec(`PRAGMA busy_timeout = ${options.busyTimeoutMillis}`);
|
|
132
|
+
}
|
|
133
|
+
options.initialize(database);
|
|
134
|
+
database.exec("PRAGMA journal_mode = WAL");
|
|
135
|
+
return database;
|
|
136
|
+
}
|
|
137
|
+
catch (error) {
|
|
138
|
+
database.close();
|
|
139
|
+
throw error;
|
|
140
|
+
}
|
|
141
|
+
},
|
|
142
|
+
catch: failWith("open.database")
|
|
143
|
+
});
|
|
144
|
+
const secureFiles = securePrivateDatabaseFiles(path).pipe(Effect.provideService(FileSystem.FileSystem, fileSystem), Effect.provideService(Path.Path, paths));
|
|
145
|
+
yield* secureFiles.pipe(Effect.onError(() => Effect.sync(() => database.close())));
|
|
146
|
+
return { database, secureFiles };
|
|
147
|
+
});
|
|
148
|
+
//# sourceMappingURL=sqlite.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sqlite.js","sourceRoot":"","sources":["../src/sqlite.ts"],"names":[],"mappings":"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"}
|
package/dist/store.d.ts
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import { Effect
|
|
1
|
+
import { Effect } from "effect";
|
|
2
2
|
import { FleetJobConflictError, FleetStoreError, FleetTransitionConflictError } from "./errors.js";
|
|
3
3
|
export declare class JobStore {
|
|
4
4
|
#private;
|
|
5
5
|
readonly path: string;
|
|
6
6
|
private constructor();
|
|
7
|
-
static readonly open: (path: string) => Effect.Effect<JobStore, FleetStoreError, FileSystem.FileSystem | Path.Path>;
|
|
7
|
+
static readonly open: (path: string) => Effect.Effect<JobStore, FleetStoreError, import("effect/FileSystem").FileSystem | import("effect/Path").Path>;
|
|
8
8
|
readonly put: (this: JobStore, record: {
|
|
9
9
|
readonly id: string;
|
|
10
10
|
readonly createdAt: number;
|
package/dist/store.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"store.d.ts","sourceRoot":"","sources":["../src/store.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"store.d.ts","sourceRoot":"","sources":["../src/store.ts"],"names":[],"mappings":"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"}
|
package/dist/store.js
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
|
-
import { Effect,
|
|
2
|
-
import { DatabaseSync } from "node:sqlite";
|
|
1
|
+
import { Effect, Schema } from "effect";
|
|
3
2
|
import { FleetJobConflictError, FleetStoreError, FleetTransitionConflictError } from "./errors.js";
|
|
4
3
|
import { JobRecord } from "./model.js";
|
|
4
|
+
import { openPrivateSqlite } from "./sqlite.js";
|
|
5
5
|
const storeError = (operation) => (cause) => new FleetStoreError({ operation, detail: String(cause), cause });
|
|
6
|
+
const fromPrivateDatabaseError = (error) => new FleetStoreError({ operation: error.operation, detail: String(error.cause), cause: error.cause });
|
|
6
7
|
const decodeRecord = (text) => Effect.try({
|
|
7
8
|
try: () => Schema.decodeUnknownSync(JobRecord)(JSON.parse(text)),
|
|
8
9
|
catch: storeError("decode")
|
|
@@ -11,45 +12,30 @@ const encodeRecord = (record) => JSON.stringify(Schema.encodeSync(JobRecord)(rec
|
|
|
11
12
|
const decodeRows = (operation, rows) => Effect.forEach(rows, (row) => Schema.decodeUnknownEffect(Schema.Struct({ record: Schema.String }))(row).pipe(Effect.mapError(storeError(operation)), Effect.flatMap(({ record }) => decodeRecord(record))));
|
|
12
13
|
export class JobStore {
|
|
13
14
|
#database;
|
|
14
|
-
#
|
|
15
|
+
#secureFiles;
|
|
15
16
|
path;
|
|
16
|
-
constructor(path,
|
|
17
|
+
constructor(path, opened) {
|
|
17
18
|
this.path = path;
|
|
18
|
-
this.#
|
|
19
|
-
this.#
|
|
20
|
-
try {
|
|
21
|
-
this.#database.exec(`
|
|
22
|
-
PRAGMA journal_mode = WAL;
|
|
23
|
-
CREATE TABLE IF NOT EXISTS jobs (
|
|
24
|
-
id TEXT PRIMARY KEY,
|
|
25
|
-
created_at INTEGER NOT NULL,
|
|
26
|
-
record TEXT NOT NULL
|
|
27
|
-
);
|
|
28
|
-
CREATE INDEX IF NOT EXISTS jobs_record_status_idx ON jobs (
|
|
29
|
-
CASE
|
|
30
|
-
WHEN json_valid(record)
|
|
31
|
-
THEN json_extract(record, '$.status')
|
|
32
|
-
END
|
|
33
|
-
);
|
|
34
|
-
`);
|
|
35
|
-
}
|
|
36
|
-
catch (error) {
|
|
37
|
-
this.#database.close();
|
|
38
|
-
throw error;
|
|
39
|
-
}
|
|
19
|
+
this.#database = opened.database;
|
|
20
|
+
this.#secureFiles = opened.secureFiles.pipe(Effect.mapError(fromPrivateDatabaseError));
|
|
40
21
|
}
|
|
41
22
|
static open = Effect.fn("JobStore.open")(function* (path) {
|
|
42
|
-
const
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
23
|
+
const opened = yield* openPrivateSqlite(path, {
|
|
24
|
+
initialize: (database) => database.exec(`
|
|
25
|
+
CREATE TABLE IF NOT EXISTS jobs (
|
|
26
|
+
id TEXT PRIMARY KEY,
|
|
27
|
+
created_at INTEGER NOT NULL,
|
|
28
|
+
record TEXT NOT NULL
|
|
29
|
+
);
|
|
30
|
+
CREATE INDEX IF NOT EXISTS jobs_record_status_idx ON jobs (
|
|
31
|
+
CASE
|
|
32
|
+
WHEN json_valid(record)
|
|
33
|
+
THEN json_extract(record, '$.status')
|
|
34
|
+
END
|
|
35
|
+
);
|
|
36
|
+
`)
|
|
37
|
+
}).pipe(Effect.mapError(fromPrivateDatabaseError));
|
|
38
|
+
return new JobStore(path, opened);
|
|
53
39
|
});
|
|
54
40
|
put = Effect.fn("JobStore.put")(function* (record) {
|
|
55
41
|
const database = this.#database;
|
|
@@ -196,11 +182,7 @@ export class JobStore {
|
|
|
196
182
|
return yield* decodeRows("listWorkers", rows);
|
|
197
183
|
});
|
|
198
184
|
secureFiles() {
|
|
199
|
-
|
|
200
|
-
const files = [this.path, `${this.path}-wal`, `${this.path}-shm`];
|
|
201
|
-
return Effect.forEach(files, (path) => fileSystem.exists(path).pipe(Effect.mapError(storeError("secure.exists")), Effect.flatMap((exists) => exists
|
|
202
|
-
? fileSystem.chmod(path, 0o600).pipe(Effect.mapError(storeError("secure.chmod")))
|
|
203
|
-
: Effect.void)), { discard: true });
|
|
185
|
+
return this.#secureFiles;
|
|
204
186
|
}
|
|
205
187
|
close() {
|
|
206
188
|
this.#database.close();
|
package/dist/store.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"store.js","sourceRoot":"","sources":["../src/store.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,
|
|
1
|
+
{"version":3,"file":"store.js","sourceRoot":"","sources":["../src/store.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@knpkv/herdr-fleet",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.5.0",
|
|
4
4
|
"description": "Typed job protocol and local authority runtime for Herdr fleets",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "knpkv",
|
|
@@ -25,6 +25,10 @@
|
|
|
25
25
|
"./response": {
|
|
26
26
|
"types": "./dist/response.d.ts",
|
|
27
27
|
"import": "./dist/response.js"
|
|
28
|
+
},
|
|
29
|
+
"./sqlite": {
|
|
30
|
+
"types": "./dist/sqlite.d.ts",
|
|
31
|
+
"import": "./dist/sqlite.js"
|
|
28
32
|
}
|
|
29
33
|
},
|
|
30
34
|
"files": [
|