@sanoma-ai/workflows 0.6.0 → 0.7.1
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 +52 -14
- package/dist/apply.d.ts +2 -1
- package/dist/apply.js +29 -7
- package/dist/apply.js.map +1 -1
- package/dist/approvals.d.ts +27 -2
- package/dist/approvals.js +73 -9
- package/dist/approvals.js.map +1 -1
- package/dist/call.d.ts +3 -2
- package/dist/call.js +38 -30
- package/dist/call.js.map +1 -1
- package/dist/cedar.js +24 -9
- package/dist/cedar.js.map +1 -1
- package/dist/change.d.ts +219 -0
- package/dist/change.js +150 -0
- package/dist/change.js.map +1 -0
- package/dist/chats.d.ts +43 -0
- package/dist/chats.js +48 -0
- package/dist/chats.js.map +1 -0
- package/dist/client.d.ts +52 -6
- package/dist/client.js +88 -47
- package/dist/client.js.map +1 -1
- package/dist/config.d.ts +75 -8
- package/dist/config.js +103 -13
- package/dist/config.js.map +1 -1
- package/dist/constructors.d.ts +37 -1
- package/dist/constructors.js +6 -2
- package/dist/constructors.js.map +1 -1
- package/dist/database.d.ts +83 -0
- package/dist/database.js +92 -0
- package/dist/database.js.map +1 -0
- package/dist/db.d.ts +19 -1
- package/dist/db.js +51 -7
- package/dist/db.js.map +1 -1
- package/dist/deadlines.d.ts +91 -0
- package/dist/deadlines.js +165 -0
- package/dist/deadlines.js.map +1 -0
- package/dist/define.d.ts +25 -4
- package/dist/define.js +40 -0
- package/dist/define.js.map +1 -1
- package/dist/demo.d.ts +28 -0
- package/dist/demo.js +72 -0
- package/dist/demo.js.map +1 -0
- package/dist/describe.d.ts +5 -2
- package/dist/describe.js +10 -6
- package/dist/describe.js.map +1 -1
- package/dist/errors.d.ts +10 -1
- package/dist/errors.js +13 -0
- package/dist/errors.js.map +1 -1
- package/dist/fake.d.ts +34 -0
- package/dist/fake.js +134 -1
- package/dist/fake.js.map +1 -1
- package/dist/grid.d.ts +34 -0
- package/dist/grid.js +62 -0
- package/dist/grid.js.map +1 -0
- package/dist/host.d.ts +12 -2
- package/dist/host.js +2 -2
- package/dist/host.js.map +1 -1
- package/dist/index.d.ts +15 -8
- package/dist/index.js +10 -5
- package/dist/index.js.map +1 -1
- package/dist/ledger.d.ts +11 -2
- package/dist/ledger.js.map +1 -1
- package/dist/lint.js +2 -2
- package/dist/lint.js.map +1 -1
- package/dist/op.d.ts +21 -2
- package/dist/op.js.map +1 -1
- package/dist/person.d.ts +5 -0
- package/dist/person.js +3 -1
- package/dist/person.js.map +1 -1
- package/dist/policy.d.ts +7 -1
- package/dist/policy.js +2 -1
- package/dist/policy.js.map +1 -1
- package/dist/resource.d.ts +13 -1
- package/dist/resource.js +9 -1
- package/dist/resource.js.map +1 -1
- package/dist/resources.d.ts +2 -0
- package/dist/resources.js +15 -4
- package/dist/resources.js.map +1 -1
- package/dist/run.d.ts +5 -0
- package/dist/run.js.map +1 -1
- package/dist/sandbox.d.ts +38 -10
- package/dist/sandbox.js +66 -35
- package/dist/sandbox.js.map +1 -1
- package/dist/scenario.d.ts +18 -1
- package/dist/scenario.js +77 -27
- package/dist/scenario.js.map +1 -1
- package/dist/scenarios.d.ts +10 -1
- package/dist/scenarios.js +19 -4
- package/dist/scenarios.js.map +1 -1
- package/dist/schedules.d.ts +66 -0
- package/dist/schedules.js +158 -0
- package/dist/schedules.js.map +1 -0
- package/dist/schema.d.ts +6 -0
- package/dist/schema.js +13 -3
- package/dist/schema.js.map +1 -1
- package/dist/shared.d.ts +30 -2
- package/dist/shared.js +42 -4
- package/dist/shared.js.map +1 -1
- package/dist/source.d.ts +185 -2
- package/dist/source.js +9 -0
- package/dist/source.js.map +1 -1
- package/dist/supervisor.d.ts +39 -0
- package/dist/supervisor.js +68 -0
- package/dist/supervisor.js.map +1 -0
- package/dist/version.d.ts +3 -1
- package/dist/version.js +3 -1
- package/dist/version.js.map +1 -1
- package/dist/wakeup-driver.d.ts +128 -0
- package/dist/wakeup-driver.js +216 -0
- package/dist/wakeup-driver.js.map +1 -0
- package/dist/wakeup-service.d.ts +83 -0
- package/dist/wakeup-service.js +415 -0
- package/dist/wakeup-service.js.map +1 -0
- package/dist/wakeup-type.d.ts +43 -0
- package/dist/wakeup-type.js +80 -0
- package/dist/wakeup-type.js.map +1 -0
- package/dist/wakeup.d.ts +77 -0
- package/dist/wakeup.js +78 -0
- package/dist/wakeup.js.map +1 -0
- package/dist/worker.d.ts +39 -1
- package/dist/worker.js +125 -38
- package/dist/worker.js.map +1 -1
- package/oxlint.json +3 -1
- package/package.json +10 -2
- package/src/apply.ts +25 -6
- package/src/approvals.ts +89 -16
- package/src/call.ts +40 -29
- package/src/cedar.ts +24 -6
- package/src/change.ts +222 -0
- package/src/chats.ts +114 -0
- package/src/client.ts +145 -55
- package/src/config.ts +149 -21
- package/src/constructors.ts +8 -2
- package/src/database.ts +152 -0
- package/src/db.ts +58 -9
- package/src/deadlines.ts +228 -0
- package/src/define.ts +71 -4
- package/src/demo.ts +87 -0
- package/src/describe.ts +18 -6
- package/src/errors.ts +14 -0
- package/src/fake.ts +149 -0
- package/src/grid.ts +100 -0
- package/src/host.ts +12 -4
- package/src/index.ts +66 -3
- package/src/ledger.ts +15 -3
- package/src/lint.ts +2 -2
- package/src/op.ts +22 -2
- package/src/person.ts +4 -1
- package/src/policy.ts +7 -1
- package/src/resource.ts +22 -3
- package/src/resources.ts +17 -4
- package/src/run.ts +5 -0
- package/src/sandbox.ts +97 -37
- package/src/scenario.ts +97 -28
- package/src/scenarios.ts +21 -5
- package/src/schedules.ts +206 -0
- package/src/schema.ts +16 -3
- package/src/shared.ts +51 -4
- package/src/source.ts +176 -3
- package/src/supervisor.ts +102 -0
- package/src/version.ts +3 -1
- package/src/wakeup-driver.ts +270 -0
- package/src/wakeup-service.ts +504 -0
- package/src/wakeup-type.ts +90 -0
- package/src/wakeup.ts +139 -0
- package/src/worker.ts +176 -43
package/dist/change.d.ts
ADDED
|
@@ -0,0 +1,219 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import type { ApprovalState, Approver } from "./define.ts";
|
|
3
|
+
import { type Driver } from "./op.ts";
|
|
4
|
+
import { type Decision } from "./policy.ts";
|
|
5
|
+
import { type Resource } from "./resource.ts";
|
|
6
|
+
import { type PeopleResource } from "./shared.ts";
|
|
7
|
+
import type { CheckResult } from "./source.ts";
|
|
8
|
+
/**
|
|
9
|
+
* What the planner finds in a change, before the policy is asked: the attributes of the
|
|
10
|
+
* `Sanoma::Change` that `sanoma.change.merge` acts on, so a rule reads `resource.touches`.
|
|
11
|
+
*/
|
|
12
|
+
export declare const ChangeFacts: z.ZodObject<{
|
|
13
|
+
touches: z.ZodArray<z.ZodString>;
|
|
14
|
+
strandedRuns: z.ZodNumber;
|
|
15
|
+
stranded: z.ZodArray<z.ZodString>;
|
|
16
|
+
checksOk: z.ZodBoolean;
|
|
17
|
+
rules: z.ZodBoolean;
|
|
18
|
+
}, z.core.$strip>;
|
|
19
|
+
export type ChangeFacts = z.infer<typeof ChangeFacts>;
|
|
20
|
+
/** What opening a change takes: its draft's id, and the pull request's title, body and the change page's link. */
|
|
21
|
+
export declare const ChangeInput: z.ZodObject<{
|
|
22
|
+
id: z.ZodString;
|
|
23
|
+
title: z.ZodString;
|
|
24
|
+
body: z.ZodOptional<z.ZodString>;
|
|
25
|
+
page: z.ZodOptional<z.ZodString>;
|
|
26
|
+
}, z.core.$strip>;
|
|
27
|
+
export type ChangeInput = z.infer<typeof ChangeInput>;
|
|
28
|
+
/** The change a call acts on: its policy target. */
|
|
29
|
+
declare const target: ({ id }: {
|
|
30
|
+
id: string;
|
|
31
|
+
}) => string;
|
|
32
|
+
/** The operations of a change, on the built-in connector `sanoma`: only the `change` workflow calls them. */
|
|
33
|
+
export declare const changeOps: import("./op.ts").Connector<"sanoma", {
|
|
34
|
+
readonly change: {
|
|
35
|
+
readonly open: {
|
|
36
|
+
readonly effect: "write";
|
|
37
|
+
readonly idempotent: true;
|
|
38
|
+
readonly description: "Open a change: push its draft's branch and open a pull request for it";
|
|
39
|
+
readonly input: z.ZodObject<{
|
|
40
|
+
id: z.ZodString;
|
|
41
|
+
title: z.ZodString;
|
|
42
|
+
body: z.ZodOptional<z.ZodString>;
|
|
43
|
+
page: z.ZodOptional<z.ZodString>;
|
|
44
|
+
}, z.core.$strip>;
|
|
45
|
+
readonly output: z.ZodObject<{
|
|
46
|
+
number: z.ZodNumber;
|
|
47
|
+
url: z.ZodString;
|
|
48
|
+
head: z.ZodString;
|
|
49
|
+
branch: z.ZodString;
|
|
50
|
+
}, z.core.$strip>;
|
|
51
|
+
readonly target: typeof target;
|
|
52
|
+
readonly phrases: {
|
|
53
|
+
readonly expect: "change {id} is opened";
|
|
54
|
+
};
|
|
55
|
+
};
|
|
56
|
+
readonly review: {
|
|
57
|
+
readonly effect: "write";
|
|
58
|
+
readonly idempotent: true;
|
|
59
|
+
readonly description: "Report Sanoma's review of a change on its pull request";
|
|
60
|
+
readonly input: z.ZodObject<{
|
|
61
|
+
id: z.ZodString;
|
|
62
|
+
number: z.ZodNumber;
|
|
63
|
+
head: z.ZodString;
|
|
64
|
+
state: z.ZodEnum<{
|
|
65
|
+
failure: "failure";
|
|
66
|
+
pending: "pending";
|
|
67
|
+
}>;
|
|
68
|
+
description: z.ZodString;
|
|
69
|
+
page: z.ZodOptional<z.ZodString>;
|
|
70
|
+
}, z.core.$strip>;
|
|
71
|
+
readonly output: z.ZodObject<{}, z.core.$strip>;
|
|
72
|
+
readonly target: typeof target;
|
|
73
|
+
readonly phrases: {
|
|
74
|
+
readonly expect: "change {id} is reviewed";
|
|
75
|
+
};
|
|
76
|
+
};
|
|
77
|
+
readonly merge: {
|
|
78
|
+
readonly effect: "write";
|
|
79
|
+
readonly idempotent: true;
|
|
80
|
+
readonly description: "Merge a change's pull request";
|
|
81
|
+
readonly input: z.ZodObject<{
|
|
82
|
+
id: z.ZodString;
|
|
83
|
+
number: z.ZodNumber;
|
|
84
|
+
head: z.ZodString;
|
|
85
|
+
title: z.ZodString;
|
|
86
|
+
facts: z.ZodObject<{
|
|
87
|
+
touches: z.ZodArray<z.ZodString>;
|
|
88
|
+
strandedRuns: z.ZodNumber;
|
|
89
|
+
stranded: z.ZodArray<z.ZodString>;
|
|
90
|
+
checksOk: z.ZodBoolean;
|
|
91
|
+
rules: z.ZodBoolean;
|
|
92
|
+
}, z.core.$strip>;
|
|
93
|
+
}, z.core.$strip>;
|
|
94
|
+
readonly output: z.ZodObject<{
|
|
95
|
+
outcome: z.ZodEnum<{
|
|
96
|
+
blocked: "blocked";
|
|
97
|
+
closed: "closed";
|
|
98
|
+
merged: "merged";
|
|
99
|
+
moved: "moved";
|
|
100
|
+
}>;
|
|
101
|
+
sha: z.ZodOptional<z.ZodString>;
|
|
102
|
+
reason: z.ZodOptional<z.ZodString>;
|
|
103
|
+
}, z.core.$strip>;
|
|
104
|
+
readonly target: typeof target;
|
|
105
|
+
readonly phrases: {
|
|
106
|
+
readonly expect: "change {id} is merged";
|
|
107
|
+
};
|
|
108
|
+
};
|
|
109
|
+
readonly close: {
|
|
110
|
+
readonly effect: "write";
|
|
111
|
+
readonly idempotent: true;
|
|
112
|
+
readonly description: "Close a change's pull request without merging it";
|
|
113
|
+
readonly input: z.ZodObject<{
|
|
114
|
+
id: z.ZodString;
|
|
115
|
+
number: z.ZodNumber;
|
|
116
|
+
}, z.core.$strip>;
|
|
117
|
+
readonly output: z.ZodObject<{
|
|
118
|
+
closed: z.ZodLiteral<true>;
|
|
119
|
+
}, z.core.$strip>;
|
|
120
|
+
readonly target: typeof target;
|
|
121
|
+
readonly phrases: {
|
|
122
|
+
readonly expect: "change {id} is closed";
|
|
123
|
+
};
|
|
124
|
+
};
|
|
125
|
+
};
|
|
126
|
+
}>;
|
|
127
|
+
/**
|
|
128
|
+
* The built-in workflow that alone may call `op`, what the operation does and what to do instead:
|
|
129
|
+
* `apply` for a writable resource type's change operations (`isChangeOp`), `change` for
|
|
130
|
+
* `sanoma.change.*`; undefined for any other. `resolveConfig` refuses a workflow that uses one, and
|
|
131
|
+
* a run's call of one outside its workflow fails.
|
|
132
|
+
*/
|
|
133
|
+
export declare function reservedFor(op: {
|
|
134
|
+
readonly vendor: string;
|
|
135
|
+
readonly resource: string;
|
|
136
|
+
readonly name: string;
|
|
137
|
+
}, types: ReadonlyMap<string, Pick<Resource, "writable">>): {
|
|
138
|
+
workflow: string;
|
|
139
|
+
does: string;
|
|
140
|
+
instead: string;
|
|
141
|
+
} | undefined;
|
|
142
|
+
/** A placeholder: lane C5 replaces it with the driver over the repository's host. */
|
|
143
|
+
export declare function changeDriver(): Driver;
|
|
144
|
+
/**
|
|
145
|
+
* Each path, relative to the root with `/` between its parts, and each of its parent directories
|
|
146
|
+
* with a trailing `/`, sorted, each once: what a rule asks with `touches.contains("resources/finance/")`.
|
|
147
|
+
*/
|
|
148
|
+
export declare function touchesOf(files: readonly string[]): string[];
|
|
149
|
+
/**
|
|
150
|
+
* The runtime's own rule, asked before any company policy and under `allowAll` too: a merge of a
|
|
151
|
+
* change to the rules (`facts.rules`, or `touches` naming `policies/` or `resources/people.ts`) waits for `admin`, whoever made it, until an approval
|
|
152
|
+
* addressed to `admin` covering the merge is approved; denied while no data file declares the
|
|
153
|
+
* group. Undefined for anything else, which the company's policy alone decides. `people` are the
|
|
154
|
+
* running instance's, never the change's, so a change cannot add its author to `admin`.
|
|
155
|
+
*/
|
|
156
|
+
export declare function runtimeHold(opId: string, input: unknown, approvals: readonly ApprovalState[], people: readonly PeopleResource[]): Decision | undefined;
|
|
157
|
+
/** What a change run is told while it waits: new commits on its branch, a close asked for, or its pull request closed or merged on the host. */
|
|
158
|
+
export type ChangeEvent = {
|
|
159
|
+
kind: "commits";
|
|
160
|
+
} | {
|
|
161
|
+
kind: "close";
|
|
162
|
+
by: string;
|
|
163
|
+
} | {
|
|
164
|
+
kind: "closed";
|
|
165
|
+
} | {
|
|
166
|
+
kind: "merged";
|
|
167
|
+
sha: string;
|
|
168
|
+
};
|
|
169
|
+
/** Where a change is, as its run publishes it (`CHANGE_EVENT`) for the app. */
|
|
170
|
+
export interface ChangeState {
|
|
171
|
+
id: string;
|
|
172
|
+
branch: string;
|
|
173
|
+
title: string;
|
|
174
|
+
page?: string;
|
|
175
|
+
phase: "opening" | "planning" | "checking" | "reviewing" | "waiting" | "merging" | "deploying" | "merged" | "closed" | "blocked";
|
|
176
|
+
pullRequest?: {
|
|
177
|
+
number: number;
|
|
178
|
+
url: string;
|
|
179
|
+
};
|
|
180
|
+
head?: string;
|
|
181
|
+
facts?: ChangeFacts;
|
|
182
|
+
check?: CheckResult;
|
|
183
|
+
decision?: {
|
|
184
|
+
answer: "allow" | "hold" | "deny";
|
|
185
|
+
approver?: Approver;
|
|
186
|
+
title?: string;
|
|
187
|
+
reasons?: string[];
|
|
188
|
+
reason?: string;
|
|
189
|
+
};
|
|
190
|
+
/** The review card on the host: unavailable in this version. */
|
|
191
|
+
card: {
|
|
192
|
+
status: "unavailable";
|
|
193
|
+
reason: string;
|
|
194
|
+
};
|
|
195
|
+
merged?: {
|
|
196
|
+
sha: string;
|
|
197
|
+
at: number;
|
|
198
|
+
deploy?: {
|
|
199
|
+
runId?: string;
|
|
200
|
+
followed?: string;
|
|
201
|
+
skipped?: string;
|
|
202
|
+
};
|
|
203
|
+
};
|
|
204
|
+
blocked?: string;
|
|
205
|
+
}
|
|
206
|
+
/** How a change run ended. */
|
|
207
|
+
export interface ChangeReport {
|
|
208
|
+
outcome: "merged" | "closed";
|
|
209
|
+
head: string;
|
|
210
|
+
pullRequest: {
|
|
211
|
+
number: number;
|
|
212
|
+
url: string;
|
|
213
|
+
};
|
|
214
|
+
sha?: string;
|
|
215
|
+
deploy?: {
|
|
216
|
+
runId?: string;
|
|
217
|
+
};
|
|
218
|
+
}
|
|
219
|
+
export {};
|
package/dist/change.js
ADDED
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { defineConnector, defineDriver, DriverError } from "./op.js";
|
|
3
|
+
import { approve, approvedFor, deny } from "./policy.js";
|
|
4
|
+
import { isChangeOp } from "./resource.js";
|
|
5
|
+
import { APPLY_WORKFLOW, CHANGE_MERGE, CHANGE_WORKFLOW, groupNamesOf } from "./shared.js";
|
|
6
|
+
// A change: how a draft of the company's repository goes live, as the built-in `change` workflow
|
|
7
|
+
// runs it (lane C5): its four operations on the built-in connector `sanoma`, the facts a policy
|
|
8
|
+
// decides its merge on (the attributes of its `Sanoma::Change`), and the runtime's own rule that
|
|
9
|
+
// a change to the rules waits for `admin`, before any company policy is asked.
|
|
10
|
+
/**
|
|
11
|
+
* What the planner finds in a change, before the policy is asked: the attributes of the
|
|
12
|
+
* `Sanoma::Change` that `sanoma.change.merge` acts on, so a rule reads `resource.touches`.
|
|
13
|
+
*/
|
|
14
|
+
export const ChangeFacts = z.object({
|
|
15
|
+
/** Every path the change edits and each of its parent directories (`touchesOf`). */
|
|
16
|
+
touches: z.array(z.string()),
|
|
17
|
+
/** How many waiting runs are of a workflow the change edits, which the publish cannot move. */
|
|
18
|
+
strandedRuns: z.number().int(),
|
|
19
|
+
/** Those runs' ids. */
|
|
20
|
+
stranded: z.array(z.string()),
|
|
21
|
+
/** Whether `sanoma check` passed on the change. */
|
|
22
|
+
checksOk: z.boolean(),
|
|
23
|
+
/** Whether the change edits the rules: a policy or a people file, which wait for `admin` (`runtimeHold`). */
|
|
24
|
+
rules: z.boolean(),
|
|
25
|
+
});
|
|
26
|
+
/** What opening a change takes: its draft's id, and the pull request's title, body and the change page's link. */
|
|
27
|
+
export const ChangeInput = z.object({
|
|
28
|
+
id: z.string().regex(/^[\w-]{1,64}$/),
|
|
29
|
+
title: z.string().min(1),
|
|
30
|
+
body: z.string().optional(),
|
|
31
|
+
page: z.string().url().optional(),
|
|
32
|
+
});
|
|
33
|
+
/** The change a call acts on: its policy target. */
|
|
34
|
+
const target = ({ id }) => `change:${id}`;
|
|
35
|
+
/** A change once it has a pull request: its draft's id and the pull request's number. */
|
|
36
|
+
const opened = { id: ChangeInput.shape.id, number: z.number().int().positive() };
|
|
37
|
+
/** The operations of a change, on the built-in connector `sanoma`: only the `change` workflow calls them. */
|
|
38
|
+
export const changeOps = defineConnector("sanoma", {
|
|
39
|
+
change: {
|
|
40
|
+
open: {
|
|
41
|
+
effect: "write",
|
|
42
|
+
idempotent: true,
|
|
43
|
+
description: "Open a change: push its draft's branch and open a pull request for it",
|
|
44
|
+
input: ChangeInput,
|
|
45
|
+
output: z.object({ number: z.number().int(), url: z.string(), head: z.string(), branch: z.string() }),
|
|
46
|
+
target,
|
|
47
|
+
phrases: { expect: "change {id} is opened" },
|
|
48
|
+
},
|
|
49
|
+
review: {
|
|
50
|
+
effect: "write",
|
|
51
|
+
idempotent: true,
|
|
52
|
+
description: "Report Sanoma's review of a change on its pull request",
|
|
53
|
+
input: z.object({
|
|
54
|
+
...opened,
|
|
55
|
+
head: z.string(),
|
|
56
|
+
state: z.enum(["pending", "failure"]),
|
|
57
|
+
description: z.string(),
|
|
58
|
+
page: z.string().url().optional(),
|
|
59
|
+
}),
|
|
60
|
+
output: z.object({}),
|
|
61
|
+
target,
|
|
62
|
+
phrases: { expect: "change {id} is reviewed" },
|
|
63
|
+
},
|
|
64
|
+
merge: {
|
|
65
|
+
effect: "write",
|
|
66
|
+
idempotent: true,
|
|
67
|
+
description: "Merge a change's pull request",
|
|
68
|
+
input: z.object({ ...opened, head: z.string(), title: z.string(), facts: ChangeFacts }),
|
|
69
|
+
output: z.object({
|
|
70
|
+
outcome: z.enum(["merged", "closed", "moved", "blocked"]),
|
|
71
|
+
sha: z.string().optional(),
|
|
72
|
+
reason: z.string().optional(),
|
|
73
|
+
}),
|
|
74
|
+
target,
|
|
75
|
+
phrases: { expect: "change {id} is merged" },
|
|
76
|
+
},
|
|
77
|
+
close: {
|
|
78
|
+
effect: "write",
|
|
79
|
+
idempotent: true,
|
|
80
|
+
description: "Close a change's pull request without merging it",
|
|
81
|
+
input: z.object(opened),
|
|
82
|
+
output: z.object({ closed: z.literal(true) }),
|
|
83
|
+
target,
|
|
84
|
+
phrases: { expect: "change {id} is closed" },
|
|
85
|
+
},
|
|
86
|
+
},
|
|
87
|
+
});
|
|
88
|
+
/**
|
|
89
|
+
* The built-in workflow that alone may call `op`, what the operation does and what to do instead:
|
|
90
|
+
* `apply` for a writable resource type's change operations (`isChangeOp`), `change` for
|
|
91
|
+
* `sanoma.change.*`; undefined for any other. `resolveConfig` refuses a workflow that uses one, and
|
|
92
|
+
* a run's call of one outside its workflow fails.
|
|
93
|
+
*/
|
|
94
|
+
export function reservedFor(op, types) {
|
|
95
|
+
if (isChangeOp(op, types)) {
|
|
96
|
+
return { workflow: APPLY_WORKFLOW, does: "changes a declared resource", instead: "change the data file" };
|
|
97
|
+
}
|
|
98
|
+
if (op.vendor === "sanoma" && op.resource === "change") {
|
|
99
|
+
return { workflow: CHANGE_WORKFLOW, does: "changes the company's repository", instead: "send a draft for review" };
|
|
100
|
+
}
|
|
101
|
+
return undefined;
|
|
102
|
+
}
|
|
103
|
+
const notBuilt = async () => {
|
|
104
|
+
throw new DriverError("not built", { retryable: false });
|
|
105
|
+
};
|
|
106
|
+
/** A placeholder: lane C5 replaces it with the driver over the repository's host. */
|
|
107
|
+
export function changeDriver() {
|
|
108
|
+
return defineDriver(changeOps, { change: { open: notBuilt, review: notBuilt, merge: notBuilt, close: notBuilt } });
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* Each path, relative to the root with `/` between its parts, and each of its parent directories
|
|
112
|
+
* with a trailing `/`, sorted, each once: what a rule asks with `touches.contains("resources/finance/")`.
|
|
113
|
+
*/
|
|
114
|
+
export function touchesOf(files) {
|
|
115
|
+
const touches = new Set();
|
|
116
|
+
for (const file of files) {
|
|
117
|
+
touches.add(file);
|
|
118
|
+
for (let end = file.indexOf("/"); end > 0; end = file.indexOf("/", end + 1))
|
|
119
|
+
touches.add(file.slice(0, end + 1));
|
|
120
|
+
}
|
|
121
|
+
return [...touches].toSorted();
|
|
122
|
+
}
|
|
123
|
+
/** The group the runtime holds a change to the rules for. */
|
|
124
|
+
const ADMIN = "admin";
|
|
125
|
+
/** The paths in `touches` that are the rules whatever `rules` says: the policies, and the template's people file. */
|
|
126
|
+
const RULES = ["policies/", "resources/people.ts"];
|
|
127
|
+
/** The runtime rule's id, as a hold's `reasons` name it. */
|
|
128
|
+
const RULES_WAIT_FOR_ADMIN = "sanoma:rules-wait-for-admin";
|
|
129
|
+
/**
|
|
130
|
+
* The runtime's own rule, asked before any company policy and under `allowAll` too: a merge of a
|
|
131
|
+
* change to the rules (`facts.rules`, or `touches` naming `policies/` or `resources/people.ts`) waits for `admin`, whoever made it, until an approval
|
|
132
|
+
* addressed to `admin` covering the merge is approved; denied while no data file declares the
|
|
133
|
+
* group. Undefined for anything else, which the company's policy alone decides. `people` are the
|
|
134
|
+
* running instance's, never the change's, so a change cannot add its author to `admin`.
|
|
135
|
+
*/
|
|
136
|
+
export function runtimeHold(opId, input, approvals, people) {
|
|
137
|
+
const facts = opId === CHANGE_MERGE ? input.facts : undefined;
|
|
138
|
+
// The planner's `rules`, or what `touches` already says: a fact left false cannot skip the rule.
|
|
139
|
+
if (!facts || !(facts.rules || RULES.some((path) => facts.touches.includes(path))))
|
|
140
|
+
return undefined;
|
|
141
|
+
if (!groupNamesOf(people).includes(ADMIN)) {
|
|
142
|
+
return deny(`A change to the policies or the people waits for the group "${ADMIN}", which no data file declares: ` +
|
|
143
|
+
`declare it in resources/people.ts`, [RULES_WAIT_FOR_ADMIN]);
|
|
144
|
+
}
|
|
145
|
+
const approver = { group: ADMIN };
|
|
146
|
+
if (approvedFor(approvals, CHANGE_MERGE, approver))
|
|
147
|
+
return undefined;
|
|
148
|
+
return approve(approver, { title: "A change to the rules waits for admin", reasons: [RULES_WAIT_FOR_ADMIN] });
|
|
149
|
+
}
|
|
150
|
+
//# sourceMappingURL=change.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"change.js","sourceRoot":"","sources":["../src/change.ts"],"names":[],"mappings":"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"}
|
package/dist/chats.d.ts
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import type { UIMessage } from "ai";
|
|
2
|
+
import type { Pool } from "pg";
|
|
3
|
+
/** A chat as `SanomaClient.chats.list` reads it. */
|
|
4
|
+
export interface Chat {
|
|
5
|
+
id: string;
|
|
6
|
+
/** Whose chat it is: the principal's id. Nobody else reads or continues it. */
|
|
7
|
+
person: string;
|
|
8
|
+
/** What runs its turns: `"loop"`, the app's own loop, or another engine the app knows. */
|
|
9
|
+
engine: string;
|
|
10
|
+
/** The draft it edits (`Source.draft`), once its first edit opened one. */
|
|
11
|
+
draftId?: string;
|
|
12
|
+
title: string;
|
|
13
|
+
/** When it was opened, in milliseconds since the epoch. */
|
|
14
|
+
createdAt: number;
|
|
15
|
+
}
|
|
16
|
+
/** The chats' store, `SanomaClient.chats`. */
|
|
17
|
+
export interface Chats {
|
|
18
|
+
/**
|
|
19
|
+
* Opens the chat `id` (the browser's) for `person` on `engine`, titled `title`. An id another
|
|
20
|
+
* chat has is refused (`invalid_input`).
|
|
21
|
+
*/
|
|
22
|
+
open(chat: {
|
|
23
|
+
id: string;
|
|
24
|
+
person: string;
|
|
25
|
+
engine: string;
|
|
26
|
+
title: string;
|
|
27
|
+
}): Promise<void>;
|
|
28
|
+
/** Records the draft the chat edits. */
|
|
29
|
+
attach(id: string, draftId: string): Promise<void>;
|
|
30
|
+
/**
|
|
31
|
+
* Writes these messages of the chat, each by its id: a message already there is replaced in its
|
|
32
|
+
* place, a new one goes after the rest, in the order given.
|
|
33
|
+
*/
|
|
34
|
+
upsert(id: string, messages: readonly UIMessage[]): Promise<void>;
|
|
35
|
+
/** The chat's messages in order; none for a chat that has none. */
|
|
36
|
+
load(id: string): Promise<UIMessage[]>;
|
|
37
|
+
/** The chat `id`, or undefined when there is none. */
|
|
38
|
+
get(id: string): Promise<Chat | undefined>;
|
|
39
|
+
/** The person's chats, the newest first: the latest 50. */
|
|
40
|
+
list(person: string): Promise<Chat[]>;
|
|
41
|
+
}
|
|
42
|
+
/** The chats' store on the pool `db` gives, the config's database once it is prepared. */
|
|
43
|
+
export declare function chatStore(db: () => Promise<Pool>): Chats;
|
package/dist/chats.js
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { CHAT_MESSAGES_TABLE as MESSAGES, CHATS_TABLE as CHATS } from "./db.js";
|
|
2
|
+
import { SanomaError } from "./errors.js";
|
|
3
|
+
const COLUMNS = "id, person, engine, draft_id, title, created_at";
|
|
4
|
+
const chatOf = ({ draft_id, created_at, ...row }) => ({
|
|
5
|
+
...row,
|
|
6
|
+
...(draft_id === null ? {} : { draftId: draft_id }),
|
|
7
|
+
createdAt: created_at.getTime(),
|
|
8
|
+
});
|
|
9
|
+
/** The chats' store on the pool `db` gives, the config's database once it is prepared. */
|
|
10
|
+
export function chatStore(db) {
|
|
11
|
+
return {
|
|
12
|
+
async open({ id, person, engine, title }) {
|
|
13
|
+
const { rows } = await (await db()).query(`INSERT INTO ${CHATS} (id, person, engine, title) VALUES ($1, $2, $3, $4) ON CONFLICT (id) DO NOTHING RETURNING id`, [id, person, engine, title]);
|
|
14
|
+
if (!rows.length)
|
|
15
|
+
throw new SanomaError("invalid_input", `Chat ${id} exists already; open it with another id`);
|
|
16
|
+
},
|
|
17
|
+
async attach(id, draftId) {
|
|
18
|
+
await (await db()).query(`UPDATE ${CHATS} SET draft_id = $2 WHERE id = $1`, [id, draftId]);
|
|
19
|
+
},
|
|
20
|
+
async upsert(id, messages) {
|
|
21
|
+
if (!messages.length)
|
|
22
|
+
return;
|
|
23
|
+
if (messages.some((m) => !m.id))
|
|
24
|
+
throw new SanomaError("invalid_input", "A chat message needs an id");
|
|
25
|
+
// A new message's place is after the chat's last, in the order given.
|
|
26
|
+
await (await db()).query(`INSERT INTO ${MESSAGES} (chat_id, id, seq, message) ` +
|
|
27
|
+
`SELECT $1, m.value->>'id', last.seq + m.n, m.value ` +
|
|
28
|
+
`FROM jsonb_array_elements($2::jsonb) WITH ORDINALITY AS m (value, n), ` +
|
|
29
|
+
`(SELECT coalesce(max(seq), 0) AS seq FROM ${MESSAGES} WHERE chat_id = $1) AS last ` +
|
|
30
|
+
"ON CONFLICT (chat_id, id) DO UPDATE SET message = EXCLUDED.message", [id, JSON.stringify(messages)]);
|
|
31
|
+
},
|
|
32
|
+
async load(id) {
|
|
33
|
+
const { rows } = await (await db()).query(`SELECT message FROM ${MESSAGES} WHERE chat_id = $1 ORDER BY seq, id`, [id]);
|
|
34
|
+
return rows.map((row) => row.message);
|
|
35
|
+
},
|
|
36
|
+
async get(id) {
|
|
37
|
+
const { rows } = await (await db()).query(`SELECT ${COLUMNS} FROM ${CHATS} WHERE id = $1`, [id]);
|
|
38
|
+
return rows[0] && chatOf(rows[0]);
|
|
39
|
+
},
|
|
40
|
+
async list(person) {
|
|
41
|
+
const { rows } = await (await db()).query(`SELECT ${COLUMNS} FROM ${CHATS} WHERE person = $1 ORDER BY created_at DESC, id LIMIT 50`, [
|
|
42
|
+
person,
|
|
43
|
+
]);
|
|
44
|
+
return rows.map(chatOf);
|
|
45
|
+
},
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
//# sourceMappingURL=chats.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"chats.js","sourceRoot":"","sources":["../src/chats.ts"],"names":[],"mappings":"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"}
|
package/dist/client.d.ts
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { type WorkflowStatusString } from "@dbos-inc/dbos-sdk";
|
|
2
2
|
import { z } from "zod";
|
|
3
3
|
import { ApprovalMessage } from "./approvals.ts";
|
|
4
|
-
import { type
|
|
4
|
+
import { type Chats } from "./chats.ts";
|
|
5
|
+
import { type ResolvedConfig, type SanomaConfig } from "./config.ts";
|
|
5
6
|
import { type CredentialStatus } from "./env.ts";
|
|
6
7
|
import { type ApprovalState, Principal, type WorkflowDefinition } from "./define.ts";
|
|
7
8
|
import { type ApplyInput, type ApplyReport } from "./apply.ts";
|
|
@@ -77,6 +78,21 @@ export interface CallOptions {
|
|
|
77
78
|
*/
|
|
78
79
|
id?: string;
|
|
79
80
|
}
|
|
81
|
+
/** What `SanomaClient.connect` is given besides the config. */
|
|
82
|
+
export interface ClientOptions {
|
|
83
|
+
/**
|
|
84
|
+
* Called, never awaited, right before each change a worker must run: a run's start (drift,
|
|
85
|
+
* apply and a held call are starts) and an approval's decision or withdrawal; never for a read. A process that
|
|
86
|
+
* runs a worker that stops when idle starts it again with it (`Supervisor.resume`). Must not throw.
|
|
87
|
+
*/
|
|
88
|
+
onWrite?: () => void;
|
|
89
|
+
/**
|
|
90
|
+
* The config as the caller resolved it (`resolveConfig(config, options)`), for a client that
|
|
91
|
+
* shares its drivers with the caller, as `startWorker`'s `resolved` does. The caller closes its
|
|
92
|
+
* `dataStore`.
|
|
93
|
+
*/
|
|
94
|
+
resolved?: ResolvedConfig;
|
|
95
|
+
}
|
|
80
96
|
/** Talks to the runtime from another process (the app, a script), through the shared Postgres. */
|
|
81
97
|
export declare class SanomaClient {
|
|
82
98
|
private readonly dbos;
|
|
@@ -84,17 +100,20 @@ export declare class SanomaClient {
|
|
|
84
100
|
private readonly drivers;
|
|
85
101
|
/** The config's own ledger store, or a Postgres one made for this client, which `close` then closes. */
|
|
86
102
|
private readonly audit;
|
|
87
|
-
/** On the config's database, for the credentials
|
|
88
|
-
private readonly
|
|
103
|
+
/** On the config's database, for the runtime's tables (the credentials, the chats): opened on first use. */
|
|
104
|
+
private readonly pool;
|
|
89
105
|
/** What a direct call's driver reads secrets from, as a worker's live driver does. */
|
|
90
106
|
private readonly storedSecrets;
|
|
107
|
+
/** The operator agent's chats: their rows and their transcripts, in the config's database. */
|
|
108
|
+
readonly chats: Chats;
|
|
109
|
+
private readonly options;
|
|
91
110
|
private constructor();
|
|
92
111
|
/**
|
|
93
112
|
* Connects to the runtime's Postgres for the config's app. Checks the config first and throws
|
|
94
113
|
* what the worker would refuse. Reads ledgers from the config's ledger store, or from the
|
|
95
114
|
* Postgres store on its database when it has none.
|
|
96
115
|
*/
|
|
97
|
-
static connect(config: SanomaConfig): Promise<SanomaClient>;
|
|
116
|
+
static connect(config: SanomaConfig, options?: ClientOptions): Promise<SanomaClient>;
|
|
98
117
|
/**
|
|
99
118
|
* Checks the input against the workflow's schema, then queues a run for the worker. The run
|
|
100
119
|
* gets the input as sent, not as the schema parsed it: the worker parses it once, so a schema
|
|
@@ -177,6 +196,33 @@ export declare class SanomaClient {
|
|
|
177
196
|
decide(runId: string, message: ApprovalMessage, approvalId?: string, options?: {
|
|
178
197
|
timeoutSeconds?: number;
|
|
179
198
|
}): Promise<ApprovalState>;
|
|
199
|
+
/**
|
|
200
|
+
* Withdraws the run's pending approval `approvalId`, saying `reason`, as `options.by`: the run's
|
|
201
|
+
* starter, or someone who may decide it (`not_approver` otherwise, here and again in the run,
|
|
202
|
+
* which records who withdrew it). The run reads the
|
|
203
|
+
* withdrawal as a decision, and the step that waits on it throws `approval_withdrawn`. Returns
|
|
204
|
+
* the approval as withdrawn, and refuses as `decide` does: `already_decided` when it is not
|
|
205
|
+
* pending (or another decision reached the run first), `run_ended`, `no_pending_approval`,
|
|
206
|
+
* `run_not_found`; and returns it still `pending` when the run does not read the withdrawal
|
|
207
|
+
* within `timeoutSeconds` (30 by default).
|
|
208
|
+
*/
|
|
209
|
+
withdraw(runId: string, approvalId: string, reason: string, options: {
|
|
210
|
+
by: Principal | string;
|
|
211
|
+
timeoutSeconds?: number;
|
|
212
|
+
}): Promise<ApprovalState>;
|
|
213
|
+
/**
|
|
214
|
+
* The run's approval `approvalId` (else its first pending one) and the run's row, when the
|
|
215
|
+
* approval is pending on a run that has not ended: `already_decided`, `run_ended`,
|
|
216
|
+
* `no_pending_approval` or `run_not_found` otherwise.
|
|
217
|
+
*/
|
|
218
|
+
private pendingApproval;
|
|
219
|
+
/**
|
|
220
|
+
* Sends a message with an `id` to the approval and waits up to `timeoutSeconds` (30 by
|
|
221
|
+
* default) for the run to read it: the approval as the run then has it, still `pending` if it
|
|
222
|
+
* has not read it. `not_approver` when the run refused it, `already_decided` when another
|
|
223
|
+
* message decided it first.
|
|
224
|
+
*/
|
|
225
|
+
private sendToApproval;
|
|
180
226
|
/**
|
|
181
227
|
* The run's output once it ends, or its error. Throws `run_running` when it has not ended
|
|
182
228
|
* within `timeoutMs`; the run goes on.
|
|
@@ -253,8 +299,8 @@ export declare class SanomaClient {
|
|
|
253
299
|
* `invalid_input` when none does.
|
|
254
300
|
*/
|
|
255
301
|
private declared;
|
|
256
|
-
/** The pool the
|
|
257
|
-
private
|
|
302
|
+
/** The pool the runtime's tables are read and written with, on the database once it is prepared. */
|
|
303
|
+
private db;
|
|
258
304
|
/**
|
|
259
305
|
* The principal as the data files declare it (`admit`): its id alone is taken, never the groups
|
|
260
306
|
* a caller gives, and an id nobody declares is `not_admitted`.
|