@usine/durable 0.0.0-stage → 0.2.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.
Files changed (83) hide show
  1. package/LICENSE +661 -0
  2. package/README.md +83 -2
  3. package/dist/attempt/documents.d.ts +86 -0
  4. package/dist/attempt/documents.d.ts.map +1 -0
  5. package/dist/attempt/documents.js +30 -0
  6. package/dist/attempt/documents.js.map +1 -0
  7. package/dist/attempt/events.d.ts +22 -0
  8. package/dist/attempt/events.d.ts.map +1 -0
  9. package/dist/attempt/events.js +110 -0
  10. package/dist/attempt/events.js.map +1 -0
  11. package/dist/attempt/extension.d.ts +48 -0
  12. package/dist/attempt/extension.d.ts.map +1 -0
  13. package/dist/attempt/extension.js +34 -0
  14. package/dist/attempt/extension.js.map +1 -0
  15. package/dist/attempt/hubs.d.ts +133 -0
  16. package/dist/attempt/hubs.d.ts.map +1 -0
  17. package/dist/attempt/hubs.js +146 -0
  18. package/dist/attempt/hubs.js.map +1 -0
  19. package/dist/attempt/outcome.d.ts +22 -0
  20. package/dist/attempt/outcome.d.ts.map +1 -0
  21. package/dist/attempt/outcome.js +84 -0
  22. package/dist/attempt/outcome.js.map +1 -0
  23. package/dist/attempt/parent.d.ts +27 -0
  24. package/dist/attempt/parent.d.ts.map +1 -0
  25. package/dist/attempt/parent.js +109 -0
  26. package/dist/attempt/parent.js.map +1 -0
  27. package/dist/attempt/relay.d.ts +41 -0
  28. package/dist/attempt/relay.d.ts.map +1 -0
  29. package/dist/attempt/relay.js +457 -0
  30. package/dist/attempt/relay.js.map +1 -0
  31. package/dist/attempt/repair.d.ts +14 -0
  32. package/dist/attempt/repair.d.ts.map +1 -0
  33. package/dist/attempt/repair.js +150 -0
  34. package/dist/attempt/repair.js.map +1 -0
  35. package/dist/attempt/request.d.ts +18 -0
  36. package/dist/attempt/request.d.ts.map +1 -0
  37. package/dist/attempt/request.js +24 -0
  38. package/dist/attempt/request.js.map +1 -0
  39. package/dist/attempt/runtime.d.ts +10 -0
  40. package/dist/attempt/runtime.d.ts.map +1 -0
  41. package/dist/attempt/runtime.js +429 -0
  42. package/dist/attempt/runtime.js.map +1 -0
  43. package/dist/attempt/services.d.ts +15 -0
  44. package/dist/attempt/services.d.ts.map +1 -0
  45. package/dist/attempt/services.js +2 -0
  46. package/dist/attempt/services.js.map +1 -0
  47. package/dist/attempt/subagent.d.ts +17 -0
  48. package/dist/attempt/subagent.d.ts.map +1 -0
  49. package/dist/attempt/subagent.js +208 -0
  50. package/dist/attempt/subagent.js.map +1 -0
  51. package/dist/attempt/task.d.ts +61 -0
  52. package/dist/attempt/task.d.ts.map +1 -0
  53. package/dist/attempt/task.js +302 -0
  54. package/dist/attempt/task.js.map +1 -0
  55. package/dist/attempt/watch.d.ts +8 -0
  56. package/dist/attempt/watch.d.ts.map +1 -0
  57. package/dist/attempt/watch.js +25 -0
  58. package/dist/attempt/watch.js.map +1 -0
  59. package/dist/attempt-runtime.d.ts +128 -0
  60. package/dist/attempt-runtime.d.ts.map +1 -0
  61. package/dist/attempt-runtime.js +78 -0
  62. package/dist/attempt-runtime.js.map +1 -0
  63. package/dist/backup.d.ts +26 -0
  64. package/dist/backup.d.ts.map +1 -0
  65. package/dist/backup.js +100 -0
  66. package/dist/backup.js.map +1 -0
  67. package/dist/harness.d.ts +101 -0
  68. package/dist/harness.d.ts.map +1 -0
  69. package/dist/harness.js +298 -0
  70. package/dist/harness.js.map +1 -0
  71. package/dist/live.d.ts +15 -0
  72. package/dist/live.d.ts.map +1 -0
  73. package/dist/live.js +51 -0
  74. package/dist/live.js.map +1 -0
  75. package/dist/storage-path.d.ts +4 -0
  76. package/dist/storage-path.d.ts.map +1 -0
  77. package/dist/storage-path.js +2 -0
  78. package/dist/storage-path.js.map +1 -0
  79. package/dist/testing.d.ts +116 -0
  80. package/dist/testing.d.ts.map +1 -0
  81. package/dist/testing.js +314 -0
  82. package/dist/testing.js.map +1 -0
  83. package/package.json +72 -3
@@ -0,0 +1 @@
1
+ {"version":3,"file":"watch.d.ts","sourceRoot":"","sources":["../../src/attempt/watch.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,IAAI,YAAY,EAAE,MAAM,uBAAuB,CAAC;AACrE,OAAO,KAAK,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,4BAA4B,CAAC;AAE5E;;;GAGG;AACH,eAAO,MAAM,aAAa,GAAI,CAAC,SAAS,UAAU,SACzC,aAAa,CAAC,CAAC,CAAC,UACf,CAAC,KAAK,EAAE,QAAQ,CAAC,CAAC,CAAC,KAAK,OAAO,WAC9B,YAAY,KACpB,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,CAmBlB,CAAC"}
@@ -0,0 +1,25 @@
1
+ /**
2
+ * Resolves with the first committed document value that `accept` matches, starting with the current
3
+ * value. Rejects if the context is aborted or the watch ends, and stops the watch in every case.
4
+ */
5
+ export const firstAccepted = (watch, accept, context) => new Promise((resolve, reject) => {
6
+ const signal = context.abortSignal;
7
+ const settle = (finish) => {
8
+ signal?.removeEventListener("abort", onAbort);
9
+ void watch.stop();
10
+ finish();
11
+ };
12
+ const onAbort = () => settle(() => reject(signal?.reason));
13
+ const initial = watch.value;
14
+ if (initial !== null && accept(initial))
15
+ return settle(() => resolve(initial));
16
+ if (signal?.aborted === true)
17
+ return onAbort();
18
+ signal?.addEventListener("abort", onAbort, { once: true });
19
+ watch.start(async (value) => {
20
+ if (value !== null && accept(value))
21
+ settle(() => resolve(value));
22
+ });
23
+ void watch.closed.then((end) => settle(() => reject(new Error(`The document watch ended: ${end.reason}`))));
24
+ });
25
+ //# sourceMappingURL=watch.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"watch.js","sourceRoot":"","sources":["../../src/attempt/watch.ts"],"names":[],"mappings":"AAGA;;;GAGG;AACH,MAAM,CAAC,MAAM,aAAa,GAAG,CAC3B,KAAuB,EACvB,MAAuC,EACvC,OAAqB,EACC,EAAE,CACxB,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;IAC9B,MAAM,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC;IACnC,MAAM,MAAM,GAAG,CAAC,MAAkB,EAAE,EAAE;QACpC,MAAM,EAAE,mBAAmB,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;QAC9C,KAAK,KAAK,CAAC,IAAI,EAAE,CAAC;QAClB,MAAM,EAAE,CAAC;IACX,CAAC,CAAC;IACF,MAAM,OAAO,GAAG,GAAG,EAAE,CAAC,MAAM,CAAC,GAAG,EAAE,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;IAC3D,MAAM,OAAO,GAAG,KAAK,CAAC,KAAK,CAAC;IAC5B,IAAI,OAAO,KAAK,IAAI,IAAI,MAAM,CAAC,OAAO,CAAC;QAAE,OAAO,MAAM,CAAC,GAAG,EAAE,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC;IAC/E,IAAI,MAAM,EAAE,OAAO,KAAK,IAAI;QAAE,OAAO,OAAO,EAAE,CAAC;IAC/C,MAAM,EAAE,gBAAgB,CAAC,OAAO,EAAE,OAAO,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;IAC3D,KAAK,CAAC,KAAK,CAAC,KAAK,EAAE,KAAK,EAAE,EAAE;QAC1B,IAAI,KAAK,KAAK,IAAI,IAAI,MAAM,CAAC,KAAK,CAAC;YAAE,MAAM,CAAC,GAAG,EAAE,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC;IACpE,CAAC,CAAC,CAAC;IACH,KAAK,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,GAAG,EAAE,EAAE,CAC7B,MAAM,CAAC,GAAG,EAAE,CAAC,MAAM,CAAC,IAAI,KAAK,CAAC,6BAA6B,GAAG,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,CAC3E,CAAC;AACJ,CAAC,CAAC,CAAC"}
@@ -0,0 +1,128 @@
1
+ import * as AttemptChannel from "@usine/core/attempt/channel";
2
+ import { AttemptId } from "@usine/core/attempt";
3
+ import { AgentFailure, AttemptFailure } from "@usine/core/attempt/failure";
4
+ import { StepResult, type StepResultFact } from "@usine/core/step/result";
5
+ import { Context, type Duration, Effect, type Option, Result, Schema } from "effect";
6
+ declare const StoredRequest_base: Schema.Class<StoredRequest, Schema.Struct<{
7
+ readonly spec: typeof AttemptChannel.RunSpec;
8
+ readonly worker: Schema.brand<Schema.String, "WorkerName">;
9
+ /** The absolute path of the Attempt's worktree on the Worker's machine. */
10
+ readonly cwd: Schema.NonEmptyString;
11
+ }>, {}>;
12
+ /** The persisted part of an Attempt's request, without `host`, `machine`, and `environment`. */
13
+ export declare class StoredRequest extends StoredRequest_base {
14
+ }
15
+ declare const AttemptRequest_base: Schema.Class<AttemptRequest, Schema.Struct<{
16
+ readonly spec: typeof AttemptChannel.RunSpec;
17
+ readonly worker: Schema.brand<Schema.String, "WorkerName">;
18
+ /** The absolute path of the Attempt's worktree on the Worker's machine. */
19
+ readonly cwd: Schema.NonEmptyString;
20
+ readonly host: Schema.Union<readonly [typeof import("@usine/agents/child-host").LocalProcess, typeof import("@usine/agents/child-host").RemoteShell]>;
21
+ /**
22
+ * The provider's ID of the machine that a provisioned Worker created for the Attempt, or `None`
23
+ * on other Workers.
24
+ */
25
+ readonly machine: Schema.Option<Schema.brand<Schema.String, "MachineId">>;
26
+ /**
27
+ * The environment variables passed to the children: the Worker's allowlisted variables plus the
28
+ * Attempt's credential configuration (ADR 0011).
29
+ */
30
+ readonly environment: Schema.$Record<Schema.String, Schema.String>;
31
+ /**
32
+ * Returns the credential kind that the Worker's Gateway injects (ADR 0027), or `None` if the
33
+ * Worker has no Gateway or the harness uses its own login.
34
+ */
35
+ readonly gatewayCredential: Schema.declare<Effect.Effect<Option.Option<"api-key" | "subscription">, never, never>, unknown>;
36
+ }>, {}>;
37
+ export declare class AttemptRequest extends AttemptRequest_base {
38
+ }
39
+ declare const AttemptReport_base: Schema.Class<AttemptReport, Schema.Struct<{
40
+ readonly message: Schema.NonEmptyString;
41
+ /**
42
+ * Whether the parent's last turn replied to an operator message or steer and delegated nothing
43
+ * after it. Decodes as `false` for older reports.
44
+ */
45
+ readonly answeredOperator: Schema.withConstructorDefault<Schema.withDecodingDefaultKey<Schema.Boolean, never>>;
46
+ }>, {}>;
47
+ /** The parent's final report, without the harvested commits, pull requests, and comments. */
48
+ export declare class AttemptReport extends AttemptReport_base {
49
+ }
50
+ /**
51
+ * Returns the Attempt's StepResult. Fails with `AgentFailure` if `answeredOperator` is true and
52
+ * `facts` is empty (ADR 0018).
53
+ */
54
+ export declare const harvestedResult: (report: AttemptReport, facts: ReadonlyArray<StepResultFact>) => Result.Result<StepResult, AgentFailure>;
55
+ declare const ParentReported_base: Schema.Class<ParentReported, Schema.TaggedStruct<"ParentReported", {
56
+ readonly report: typeof AttemptReport;
57
+ }>, {}>;
58
+ /** A successful parent report with no stored harvested result. */
59
+ export declare class ParentReported extends ParentReported_base {
60
+ }
61
+ declare const ResultRecorded_base: Schema.Class<ResultRecorded, Schema.TaggedStruct<"ResultRecorded", {
62
+ readonly result: typeof StepResult;
63
+ }>, {}>;
64
+ /** A harvested result stored with `recordResult`. */
65
+ export declare class ResultRecorded extends ResultRecorded_base {
66
+ }
67
+ declare const ParentFailed_base: Schema.Class<ParentFailed, Schema.TaggedStruct<"ParentFailed", {
68
+ /** The failure that `execute` returned. */
69
+ readonly failure: Schema.Union<readonly [typeof import("@usine/core/attempt/failure").InfraFailure, typeof import("@usine/core/attempt/failure").DefectFailure, typeof AgentFailure, typeof import("@usine/core/attempt/failure").BlockedFailure, typeof import("@usine/core/attempt/failure").QuestionFailure, typeof import("@usine/core/attempt/failure").RunawayFailure, typeof import("@usine/core/attempt/failure").ChildSessionBudgetFailure]>;
70
+ }>, {}>;
71
+ export declare class ParentFailed extends ParentFailed_base {
72
+ }
73
+ /** The stored state of an Attempt whose terminal envelope was relayed. */
74
+ export declare const FinishedAttempt: Schema.Union<readonly [typeof ParentReported, typeof ResultRecorded, typeof ParentFailed]>;
75
+ export type FinishedAttempt = typeof FinishedAttempt.Type;
76
+ declare const AttemptRuntime_base: Context.ServiceClass<AttemptRuntime, "@usine/durable/AttemptRuntime", {
77
+ /**
78
+ * Creates or reattaches the parent task, appends its activity to `io`, and returns its report.
79
+ */
80
+ readonly execute: (request: AttemptRequest, io: AttemptChannel.Sink) => Effect.Effect<AttemptReport, AttemptFailure>;
81
+ /**
82
+ * Whether the Attempt is open in durable storage: true until `execute` relays the terminal
83
+ * envelope, and false for a canceled task.
84
+ */
85
+ readonly isLive: (attemptId: AttemptId) => Effect.Effect<boolean, AttemptFailure>;
86
+ /**
87
+ * Returns the parent task's final state after `execute` relays the terminal envelope. Returns
88
+ * `None` while the task runs, after `cancel`, or if the Attempt has no task.
89
+ */
90
+ readonly finished: (attemptId: AttemptId) => Effect.Effect<Option.Option<FinishedAttempt>, AttemptFailure>;
91
+ /** Stores the harvested result, which `finished` then returns as `ResultRecorded`. */
92
+ readonly recordResult: (attemptId: AttemptId, result: StepResult) => Effect.Effect<void, AttemptFailure>;
93
+ /**
94
+ * Stores the runaway guard's unsupervised time so a reattached guard resumes from it (#178).
95
+ * Ignores a value shorter than the stored one.
96
+ */
97
+ readonly recordUnsupervised: (attemptId: AttemptId, unsupervised: Duration.Duration) => Effect.Effect<void, AttemptFailure>;
98
+ /** Returns the time stored by `recordUnsupervised`, or `None` if none was stored. */
99
+ readonly unsupervised: (attemptId: AttemptId) => Effect.Effect<Option.Option<Duration.Duration>, AttemptFailure>;
100
+ /** Returns the request the task was created with, or `None` if the Attempt has no task. */
101
+ readonly request: (attemptId: AttemptId) => Effect.Effect<Option.Option<StoredRequest>, AttemptFailure>;
102
+ /**
103
+ * Applies an operator intervention to the live parent or a child and records it in the
104
+ * Attempt's sink, so the sink's `append` must not wait on this call. Fails if no `execute` call
105
+ * in this process is relaying the Attempt.
106
+ */
107
+ readonly intervene: (attemptId: AttemptId, intervention: AttemptChannel.Intervention) => Effect.Effect<void, AttemptFailure>;
108
+ /**
109
+ * Completes when an `execute` call in this process is relaying the Attempt. Never fails or
110
+ * times out, so callers must bound it.
111
+ */
112
+ readonly attached: (attemptId: AttemptId) => Effect.Effect<void>;
113
+ /** Aborts the children, then the parent conversation, and ends the pending `execute` call. */
114
+ readonly cancel: (attemptId: AttemptId) => Effect.Effect<void, AttemptFailure>;
115
+ /**
116
+ * Appends a Worker notice to the transcript. If the parent hasn't started, keeps only the
117
+ * latest notice (and a preceding `WorkerUnresponsive`) until `Started`.
118
+ */
119
+ readonly notify: (attemptId: AttemptId, notice: AttemptChannel.WorkerNotice) => Effect.Effect<void>;
120
+ }>;
121
+ /**
122
+ * Runs each Attempt's Pi parent as a durable task in the orchestrator process. `execute` is
123
+ * idempotent per Attempt ID.
124
+ */
125
+ export declare class AttemptRuntime extends AttemptRuntime_base {
126
+ }
127
+ export {};
128
+ //# sourceMappingURL=attempt-runtime.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"attempt-runtime.d.ts","sourceRoot":"","sources":["../src/attempt-runtime.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,78 @@
1
+ import { ChildHost } from "@usine/agents/child-host";
2
+ import * as AttemptChannel from "@usine/core/attempt/channel";
3
+ import { AttemptId } from "@usine/core/attempt";
4
+ import { AgentFailure, AttemptFailure } from "@usine/core/attempt/failure";
5
+ import { StepResult } from "@usine/core/step/result";
6
+ import { GatewayCredentialKind, MachineId, WorkerName } from "@usine/core/worker";
7
+ import { Context, Effect, Result, Schema } from "effect";
8
+ /** The persisted part of an Attempt's request, without `host`, `machine`, and `environment`. */
9
+ export class StoredRequest extends Schema.Class("@usine/durable/StoredRequest")({
10
+ spec: AttemptChannel.RunSpec,
11
+ worker: WorkerName,
12
+ /** The absolute path of the Attempt's worktree on the Worker's machine. */
13
+ cwd: Schema.NonEmptyString,
14
+ }) {
15
+ }
16
+ export class AttemptRequest extends Schema.Class("@usine/durable/AttemptRequest")({
17
+ ...StoredRequest.fields,
18
+ host: ChildHost,
19
+ /**
20
+ * The provider's ID of the machine that a provisioned Worker created for the Attempt, or `None`
21
+ * on other Workers.
22
+ */
23
+ machine: Schema.Option(MachineId),
24
+ /**
25
+ * The environment variables passed to the children: the Worker's allowlisted variables plus the
26
+ * Attempt's credential configuration (ADR 0011).
27
+ */
28
+ environment: Schema.Record(Schema.String, Schema.String),
29
+ /**
30
+ * Returns the credential kind that the Worker's Gateway injects (ADR 0027), or `None` if the
31
+ * Worker has no Gateway or the harness uses its own login.
32
+ */
33
+ gatewayCredential: Schema.declare((u) => Effect.isEffect(u), { expected: "an Effect that reads the gateway's credential kind" }),
34
+ }) {
35
+ }
36
+ /** The parent's final report, without the harvested commits, pull requests, and comments. */
37
+ export class AttemptReport extends Schema.Class("@usine/durable/AttemptReport")({
38
+ message: Schema.NonEmptyString,
39
+ /**
40
+ * Whether the parent's last turn replied to an operator message or steer and delegated nothing
41
+ * after it. Decodes as `false` for older reports.
42
+ */
43
+ answeredOperator: Schema.Boolean.pipe(Schema.withDecodingDefaultKey(Effect.succeed(false)), Schema.withConstructorDefault(Effect.succeed(false))),
44
+ }) {
45
+ }
46
+ /**
47
+ * Returns the Attempt's StepResult. Fails with `AgentFailure` if `answeredOperator` is true and
48
+ * `facts` is empty (ADR 0018).
49
+ */
50
+ export const harvestedResult = (report, facts) => report.answeredOperator && facts.length === 0
51
+ ? Result.fail(new AgentFailure({
52
+ message: `The parent ended with an answer to the operator, and the attempt produced no commit, pull request, or comment. Answer: ${report.message}`,
53
+ }))
54
+ : Result.succeed(new StepResult({ message: report.message, facts }));
55
+ /** A successful parent report with no stored harvested result. */
56
+ export class ParentReported extends Schema.TaggedClass("@usine/durable/ParentReported")("ParentReported", {
57
+ report: AttemptReport,
58
+ }) {
59
+ }
60
+ /** A harvested result stored with `recordResult`. */
61
+ export class ResultRecorded extends Schema.TaggedClass("@usine/durable/ResultRecorded")("ResultRecorded", {
62
+ result: StepResult,
63
+ }) {
64
+ }
65
+ export class ParentFailed extends Schema.TaggedClass("@usine/durable/ParentFailed")("ParentFailed", {
66
+ /** The failure that `execute` returned. */
67
+ failure: AttemptFailure,
68
+ }) {
69
+ }
70
+ /** The stored state of an Attempt whose terminal envelope was relayed. */
71
+ export const FinishedAttempt = Schema.Union([ParentReported, ResultRecorded, ParentFailed]);
72
+ /**
73
+ * Runs each Attempt's Pi parent as a durable task in the orchestrator process. `execute` is
74
+ * idempotent per Attempt ID.
75
+ */
76
+ export class AttemptRuntime extends Context.Service()("@usine/durable/AttemptRuntime") {
77
+ }
78
+ //# sourceMappingURL=attempt-runtime.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"attempt-runtime.js","sourceRoot":"","sources":["../src/attempt-runtime.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,26 @@
1
+ import { Effect, Schema } from "effect";
2
+ declare const DurableStorageBackupError_base: Schema.Class<DurableStorageBackupError, Schema.TaggedStruct<"DurableStorageBackupError", {
3
+ /**
4
+ * The failed step: `open` (the storage file), `stage` (the temporary copy), `copy` (SQLite's
5
+ * backup), or `publish` (the hard link to `destination`, which fails if the file exists).
6
+ */
7
+ readonly operation: Schema.Literals<readonly ["open", "stage", "copy", "publish"]>;
8
+ /** The path of `.usine/durable.sqlite` in the instance directory. */
9
+ readonly source: Schema.String;
10
+ readonly destination: Schema.String;
11
+ /** A short operator-facing description of the failure. */
12
+ readonly reason: Schema.String;
13
+ readonly cause: Schema.Defect;
14
+ }>, import("effect/Cause").YieldableError>;
15
+ /**
16
+ * A failed durable storage backup, with both paths because a copy error can come from either file.
17
+ */
18
+ export declare class DurableStorageBackupError extends DurableStorageBackupError_base {
19
+ }
20
+ /**
21
+ * Copies `.usine/durable.sqlite`, including its WAL, to `destination` without overwriting an
22
+ * existing file. Returns `false` if the instance has no durable storage.
23
+ */
24
+ export declare const backup: (instanceDirectory: string & import("effect/Brand").Brand<"InstanceDirectory">, destination: string) => Effect.Effect<boolean, DurableStorageBackupError, never>;
25
+ export {};
26
+ //# sourceMappingURL=backup.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"backup.d.ts","sourceRoot":"","sources":["../src/backup.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,MAAM,EAAgD,MAAM,EAAE,MAAM,QAAQ,CAAC;;IASpF;;;OAGG;;IAEH,qEAAqE;;;IAGrE,0DAA0D;;;;AAd5D;;GAEG;AACH,qBAAa,yBAA0B,SAAQ,8BAc7C;CAAG;AAgBL;;;GAGG;AACH,eAAO,MAAM,MAAM,kKA6ElB,CAAC"}
package/dist/backup.js ADDED
@@ -0,0 +1,100 @@
1
+ import { backup as backupDatabase, DatabaseSync } from "node:sqlite";
2
+ import { NodeServices } from "@effect/platform-node";
3
+ import { Effect, FileSystem, Option, Path, Schema } from "effect";
4
+ import { durableStoragePath } from "./storage-path.js";
5
+ /**
6
+ * A failed durable storage backup, with both paths because a copy error can come from either file.
7
+ */
8
+ export class DurableStorageBackupError extends Schema.TaggedError("@usine/durable/DurableStorageBackupError")("DurableStorageBackupError", {
9
+ /**
10
+ * The failed step: `open` (the storage file), `stage` (the temporary copy), `copy` (SQLite's
11
+ * backup), or `publish` (the hard link to `destination`, which fails if the file exists).
12
+ */
13
+ operation: Schema.Literals(["open", "stage", "copy", "publish"]),
14
+ /** The path of `.usine/durable.sqlite` in the instance directory. */
15
+ source: Schema.String,
16
+ destination: Schema.String,
17
+ /** A short operator-facing description of the failure. */
18
+ reason: Schema.String,
19
+ cause: Schema.Defect(),
20
+ }) {
21
+ }
22
+ const errnoCode = Schema.decodeUnknownOption(Schema.Struct({ code: Schema.NonEmptyString }));
23
+ const platformReason = (cause) => {
24
+ if (cause.reason.description !== undefined)
25
+ return cause.reason.description;
26
+ if (cause.reason._tag !== "Unknown")
27
+ return cause.reason._tag;
28
+ return Option.match(errnoCode(cause.reason.cause), {
29
+ onNone: () => cause.reason._tag,
30
+ onSome: ({ code }) => code,
31
+ });
32
+ };
33
+ const sqliteReason = (cause) => cause instanceof Error && cause.message.length > 0 ? cause.message : String(cause);
34
+ /**
35
+ * Copies `.usine/durable.sqlite`, including its WAL, to `destination` without overwriting an
36
+ * existing file. Returns `false` if the instance has no durable storage.
37
+ */
38
+ export const backup = Effect.fn("DurableStorage.backup")(function* (instanceDirectory, destination) {
39
+ const fileSystem = yield* FileSystem.FileSystem;
40
+ const path = yield* Path.Path;
41
+ const source = durableStoragePath(path, instanceDirectory);
42
+ yield* Effect.annotateCurrentSpan({ instanceDirectory, source, destination });
43
+ const failed = (operation, reasonOf) => (cause) => new DurableStorageBackupError({
44
+ operation,
45
+ source,
46
+ destination,
47
+ reason: reasonOf(cause),
48
+ cause,
49
+ });
50
+ if (!(yield* fileSystem.exists(source).pipe(Effect.mapError(failed("open", platformReason))))) {
51
+ yield* Effect.logInfo("The instance has no durable storage to back up", { source });
52
+ return false;
53
+ }
54
+ const info = yield* fileSystem
55
+ .stat(source)
56
+ .pipe(Effect.mapError(failed("open", platformReason)));
57
+ if (info.type !== "File") {
58
+ return yield* new DurableStorageBackupError({
59
+ operation: "open",
60
+ source,
61
+ destination,
62
+ reason: `Expected a regular SQLite file, found ${info.type}`,
63
+ cause: new Error(info.type),
64
+ });
65
+ }
66
+ yield* Effect.logInfo("Durable storage backup started", { source, destination });
67
+ const totalPages = yield* Effect.scoped(Effect.gen(function* () {
68
+ const temporary = yield* fileSystem
69
+ .makeTempDirectoryScoped({
70
+ directory: path.dirname(destination),
71
+ prefix: ".usine-backup-",
72
+ })
73
+ .pipe(Effect.mapError(failed("stage", platformReason)));
74
+ const staged = path.join(temporary, "durable.sqlite");
75
+ yield* fileSystem
76
+ .writeFile(staged, new Uint8Array(), { mode: 0o600 })
77
+ .pipe(Effect.mapError(failed("stage", platformReason)));
78
+ // The backup cannot be canceled; it completes before the connection is closed and the
79
+ // staged file removed.
80
+ const pages = yield* Effect.acquireUseRelease(Effect.try({
81
+ try: () => new DatabaseSync(source, { readOnly: true, timeout: 5_000 }),
82
+ catch: failed("open", sqliteReason),
83
+ }), (database) => Effect.tryPromise({
84
+ try: () => backupDatabase(database, staged),
85
+ catch: failed("copy", sqliteReason),
86
+ }), (database) => Effect.sync(() => database.close())).pipe(Effect.uninterruptible);
87
+ yield* fileSystem
88
+ .link(staged, destination)
89
+ .pipe(Effect.mapError(failed("publish", platformReason)));
90
+ return pages;
91
+ }));
92
+ yield* Effect.logInfo("Durable storage backup completed", { source, destination, totalPages });
93
+ return true;
94
+ }, Effect.tapError((error) => Effect.logWarning("Durable storage backup failed", {
95
+ operation: error.operation,
96
+ source: error.source,
97
+ destination: error.destination,
98
+ reason: error.reason,
99
+ })), Effect.provide(NodeServices.layer));
100
+ //# sourceMappingURL=backup.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"backup.js","sourceRoot":"","sources":["../src/backup.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,101 @@
1
+ import type { Context as ChordContext } from "@earendil-works/chord";
2
+ import type { Models } from "@earendil-works/pi-ai";
3
+ import { type CommitPublication, type Extension, Harness, type ModelRef, type Storage } from "@earendil-works/pi-durable";
4
+ import { Context, Effect, Layer, Option, Schema, type Scope } from "effect";
5
+ declare const DurableHarnessError_base: Schema.Class<DurableHarnessError, Schema.TaggedStruct<"DurableHarnessError", {
6
+ /**
7
+ * A description of the failed operation, such as `open the durable harness`, or the
8
+ * `operation` passed to `use`.
9
+ */
10
+ readonly operation: Schema.NonEmptyString;
11
+ /** The error message, or the storage error's message if a storage error failed the harness. */
12
+ readonly message: Schema.NonEmptyString;
13
+ readonly cause: Schema.Defect;
14
+ }>, import("effect/Cause").YieldableError>;
15
+ /** A failed pi-durable call. */
16
+ export declare class DurableHarnessError extends DurableHarnessError_base {
17
+ }
18
+ declare const DurableStorageFailed_base: Schema.Class<DurableStorageFailed, Schema.TaggedStruct<"DurableStorageFailed", {
19
+ /** The failed harness's generation: 1 for the first open, and one more for each reopen. */
20
+ readonly generation: Schema.Int;
21
+ /** The storage error's message. */
22
+ readonly message: Schema.NonEmptyString;
23
+ readonly cause: Schema.Defect;
24
+ }>, import("effect/Cause").YieldableError>;
25
+ /**
26
+ * A storage error that failed the pi-durable Session. pi-durable then aborts the harness's running
27
+ * tasks and closes it, and every later call on it fails.
28
+ */
29
+ export declare class DurableStorageFailed extends DurableStorageFailed_base {
30
+ }
31
+ /** Callbacks for harness events, kept across reopens. */
32
+ export interface HarnessListener {
33
+ /**
34
+ * Runs synchronously after every adopted commit, so it must not block, throw, or call the
35
+ * harness.
36
+ */
37
+ readonly onCommit: (publication: CommitPublication) => void;
38
+ /**
39
+ * Runs once a failed harness has closed, before the reopened one resumes its tasks. It must not
40
+ * block or throw.
41
+ */
42
+ readonly onFailure: (failure: DurableStorageFailed) => void;
43
+ }
44
+ /**
45
+ * A storage repair that runs on a newly opened harness before its tasks resume. `storage` is the
46
+ * storage that the harness opened. A failed read through it fails only that read; a failed read
47
+ * through `harness` fails the harness. It must log its own failures and never fail.
48
+ */
49
+ export type BeforeResume = (harness: Harness, storage: Storage) => Effect.Effect<void>;
50
+ export interface DurableHarnessOptions {
51
+ /** Opens the storage. Runs again on each reopen. */
52
+ readonly openStorage: Effect.Effect<Storage, DurableHarnessError>;
53
+ /** The pi-ai model access for generation and parent model resolution. */
54
+ readonly models: Models;
55
+ /**
56
+ * The parent model for Attempts that name none. If `None`, the first model with a configured
57
+ * credential is used.
58
+ */
59
+ readonly defaultModel: Option.Option<ModelRef>;
60
+ }
61
+ declare const DurableHarness_base: Context.ServiceClass<DurableHarness, "@usine/durable/DurableHarness", {
62
+ readonly models: Models;
63
+ readonly defaultModel: Option.Option<ModelRef>;
64
+ /**
65
+ * Installs or replaces an extension. Conversations that select it use the new code from their
66
+ * next phase.
67
+ */
68
+ readonly install: (extension: Extension) => Effect.Effect<void>;
69
+ /**
70
+ * Runs `beforeResume`, then starts the task scheduler, and repeats both on each reopen. Call it
71
+ * after installing all extensions. Fails with the storage error if one fails the harness first.
72
+ */
73
+ readonly resume: (beforeResume: BeforeResume) => Effect.Effect<void, DurableHarnessError>;
74
+ /**
75
+ * Runs a call against the open harness. If a storage error fails the harness during the call,
76
+ * waits for the reopened harness and runs the call once more, so the call must be safe to
77
+ * repeat. Fails with the storage error before `resume` completes and after the harness stops.
78
+ */
79
+ readonly use: <A>(operation: string, run: (harness: Harness, context: ChordContext) => Promise<A>) => Effect.Effect<A, DurableHarnessError>;
80
+ /** Registers `listener` until the scope closes. */
81
+ readonly subscribe: (listener: HarnessListener) => Effect.Effect<void, never, Scope.Scope>;
82
+ }>;
83
+ /**
84
+ * The pi-durable Harness over one storage. After a storage error fails the harness, reopens the
85
+ * storage and resumes the tasks, unless `resume` hasn't completed yet. Stops if the reopen fails
86
+ * or if the reopened harness fails within a minute.
87
+ */
88
+ export declare class DurableHarness extends DurableHarness_base {
89
+ }
90
+ /**
91
+ * Returns a `DurableHarnessError` with the message of `cause`. For a `SessionFailed`, uses the
92
+ * message of the storage error that failed the harness.
93
+ */
94
+ export declare const durableError: (operation: string, cause: unknown) => DurableHarnessError;
95
+ /**
96
+ * Opens the harness for the layer's lifetime. Closes it on release without writing any task
97
+ * outcome.
98
+ */
99
+ export declare const layer: (options: DurableHarnessOptions) => Layer.Layer<DurableHarness, DurableHarnessError>;
100
+ export {};
101
+ //# sourceMappingURL=harness.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"harness.d.ts","sourceRoot":"","sources":["../src/harness.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,IAAI,YAAY,EAAE,MAAM,uBAAuB,CAAC;AAErE,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,uBAAuB,CAAC;AACpD,OAAO,EACL,KAAK,iBAAiB,EAEtB,KAAK,SAAS,EACd,OAAO,EACP,KAAK,QAAQ,EAEb,KAAK,OAAO,EACb,MAAM,4BAA4B,CAAC;AACpC,OAAO,EAAE,OAAO,EAAY,MAAM,EAAE,KAAK,EAAE,MAAM,EAAU,MAAM,EAAE,KAAK,KAAK,EAAE,MAAM,QAAQ,CAAC;;IAM5F;;;OAGG;;IAEH,+FAA+F;;;;AATjG,gCAAgC;AAChC,qBAAa,mBAAoB,SAAQ,wBAWvC;CAAG;;IASH,2FAA2F;;IAE3F,mCAAmC;;;;AATrC;;;GAGG;AACH,qBAAa,oBAAqB,SAAQ,yBAQxC;CAAG;AAEL,yDAAyD;AACzD,MAAM,WAAW,eAAe;IAC9B;;;OAGG;IACH,QAAQ,CAAC,QAAQ,EAAE,CAAC,WAAW,EAAE,iBAAiB,KAAK,IAAI,CAAC;IAC5D;;;OAGG;IACH,QAAQ,CAAC,SAAS,EAAE,CAAC,OAAO,EAAE,oBAAoB,KAAK,IAAI,CAAC;CAC7D;AAED;;;;GAIG;AACH,MAAM,MAAM,YAAY,GAAG,CAAC,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,KAAK,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;AAEvF,MAAM,WAAW,qBAAqB;IACpC,oDAAoD;IACpD,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC,MAAM,CAAC,OAAO,EAAE,mBAAmB,CAAC,CAAC;IAClE,yEAAyE;IACzE,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB;;;OAGG;IACH,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;CAChD;;qBAUoB,MAAM;2BACA,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC;IAC9C;;;OAGG;sBACe,CAAC,SAAS,EAAE,SAAS,KAAK,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC;IAC/D;;;OAGG;qBACc,CAAC,YAAY,EAAE,YAAY,KAAK,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,mBAAmB,CAAC;IACzF;;;;OAIG;kBACW,CAAC,CAAC,EACd,SAAS,EAAE,MAAM,EACjB,GAAG,EAAE,CAAC,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,YAAY,KAAK,OAAO,CAAC,CAAC,CAAC,KACzD,MAAM,CAAC,MAAM,CAAC,CAAC,EAAE,mBAAmB,CAAC;IAC1C,mDAAmD;wBAC/B,CAAC,QAAQ,EAAE,eAAe,KAAK,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,KAAK,EAAE,KAAK,CAAC,KAAK,CAAC;;AA9B9F;;;;GAIG;AACH,qBAAa,cAAe,SAAQ,mBA2BA;CAAG;AAavC;;;GAGG;AACH,eAAO,MAAM,YAAY,cAAe,MAAM,SAAS,OAAO,wBAK1D,CAAC;AAgVL;;;GAGG;AACH,eAAO,MAAM,KAAK,YACP,qBAAqB,KAC7B,KAAK,CAAC,KAAK,CAAC,cAAc,EAAE,mBAAmB,CAAgD,CAAC"}