@sanoma-ai/workflows 0.11.15 → 0.11.17

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 (117) hide show
  1. package/README.md +14 -3
  2. package/dist/app-steps.d.ts +17 -0
  3. package/dist/app-steps.js +43 -0
  4. package/dist/app-steps.js.map +1 -0
  5. package/dist/app-workflows.d.ts +170 -0
  6. package/dist/app-workflows.js +107 -0
  7. package/dist/app-workflows.js.map +1 -0
  8. package/dist/apply-steps.js +3 -9
  9. package/dist/apply-steps.js.map +1 -1
  10. package/dist/approvals.d.ts +1 -1
  11. package/dist/approvals.js +3 -0
  12. package/dist/approvals.js.map +1 -1
  13. package/dist/call.d.ts +2 -1
  14. package/dist/call.js +2 -1
  15. package/dist/call.js.map +1 -1
  16. package/dist/change-steps.js +11 -17
  17. package/dist/change-steps.js.map +1 -1
  18. package/dist/chat-steps.d.ts +5 -0
  19. package/dist/chat-steps.js +107 -0
  20. package/dist/chat-steps.js.map +1 -0
  21. package/dist/chat-workflow.d.ts +43 -0
  22. package/dist/chat-workflow.js +47 -0
  23. package/dist/chat-workflow.js.map +1 -0
  24. package/dist/chats.d.ts +23 -4
  25. package/dist/chats.js +54 -7
  26. package/dist/chats.js.map +1 -1
  27. package/dist/client.d.ts +42 -31
  28. package/dist/client.js +118 -105
  29. package/dist/client.js.map +1 -1
  30. package/dist/config.d.ts +20 -0
  31. package/dist/config.js +55 -4
  32. package/dist/config.js.map +1 -1
  33. package/dist/db/company.d.ts +259 -2
  34. package/dist/db/company.js +32 -1
  35. package/dist/db/company.js.map +1 -1
  36. package/dist/db.d.ts +15 -0
  37. package/dist/db.js +42 -2
  38. package/dist/db.js.map +1 -1
  39. package/dist/description.d.ts +6 -3
  40. package/dist/description.js +4 -3
  41. package/dist/description.js.map +1 -1
  42. package/dist/follow-steps.d.ts +8 -0
  43. package/dist/follow-steps.js +113 -0
  44. package/dist/follow-steps.js.map +1 -0
  45. package/dist/follow-workflow.d.ts +56 -0
  46. package/dist/follow-workflow.js +50 -0
  47. package/dist/follow-workflow.js.map +1 -0
  48. package/dist/index.d.ts +10 -5
  49. package/dist/index.js +9 -4
  50. package/dist/index.js.map +1 -1
  51. package/dist/local-sandbox.d.ts +10 -0
  52. package/dist/local-sandbox.js +130 -0
  53. package/dist/local-sandbox.js.map +1 -0
  54. package/dist/op.d.ts +9 -2
  55. package/dist/op.js.map +1 -1
  56. package/dist/paths.d.ts +9 -0
  57. package/dist/paths.js +20 -4
  58. package/dist/paths.js.map +1 -1
  59. package/dist/resource.d.ts +7 -1
  60. package/dist/resource.js +5 -1
  61. package/dist/resource.js.map +1 -1
  62. package/dist/run.d.ts +39 -0
  63. package/dist/run.js +15 -0
  64. package/dist/run.js.map +1 -1
  65. package/dist/sandbox-contract.d.ts +100 -0
  66. package/dist/sandbox-contract.js +26 -0
  67. package/dist/sandbox-contract.js.map +1 -0
  68. package/dist/sandbox.d.ts +10 -0
  69. package/dist/sandbox.js +42 -4
  70. package/dist/sandbox.js.map +1 -1
  71. package/dist/scenario.d.ts +19 -0
  72. package/dist/scenario.js.map +1 -1
  73. package/dist/schedules.d.ts +11 -3
  74. package/dist/schedules.js +15 -3
  75. package/dist/schedules.js.map +1 -1
  76. package/dist/seal.d.ts +7 -0
  77. package/dist/seal.js +14 -2
  78. package/dist/seal.js.map +1 -1
  79. package/dist/shared.d.ts +34 -2
  80. package/dist/shared.js +39 -2
  81. package/dist/shared.js.map +1 -1
  82. package/dist/worker.d.ts +8 -0
  83. package/dist/worker.js +116 -10
  84. package/dist/worker.js.map +1 -1
  85. package/drizzle/company/0002_runs_tell_the_app.sql +27 -0
  86. package/drizzle/company/meta/0002_snapshot.json +819 -0
  87. package/drizzle/company/meta/_journal.json +7 -0
  88. package/package.json +1 -1
  89. package/src/app-steps.ts +67 -0
  90. package/src/app-workflows.ts +251 -0
  91. package/src/apply-steps.ts +3 -9
  92. package/src/approvals.ts +3 -1
  93. package/src/call.ts +2 -1
  94. package/src/change-steps.ts +10 -17
  95. package/src/chat-steps.ts +117 -0
  96. package/src/chat-workflow.ts +69 -0
  97. package/src/chats.ts +80 -14
  98. package/src/client.ts +154 -109
  99. package/src/config.ts +66 -3
  100. package/src/db/company.ts +49 -2
  101. package/src/db.ts +51 -3
  102. package/src/description.ts +4 -3
  103. package/src/follow-steps.ts +129 -0
  104. package/src/follow-workflow.ts +88 -0
  105. package/src/index.ts +32 -3
  106. package/src/local-sandbox.ts +132 -0
  107. package/src/op.ts +9 -2
  108. package/src/paths.ts +22 -4
  109. package/src/resource.ts +16 -2
  110. package/src/run.ts +41 -0
  111. package/src/sandbox-contract.ts +114 -0
  112. package/src/sandbox.ts +41 -4
  113. package/src/scenario.ts +17 -0
  114. package/src/schedules.ts +19 -4
  115. package/src/seal.ts +16 -2
  116. package/src/shared.ts +47 -2
  117. package/src/worker.ts +149 -10
package/dist/chats.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"chats.js","sourceRoot":"","sources":["../src/chats.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"chats.js","sourceRoot":"","sources":["../src/chats.ts"],"names":[],"mappings":"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"}
package/dist/client.d.ts CHANGED
@@ -6,6 +6,7 @@ import { ApprovalMessage } from "./approvals.ts";
6
6
  import { type Chats } from "./chats.ts";
7
7
  import { type Tokens } from "./tokens.ts";
8
8
  import { type SanomaConfig } from "./config.ts";
9
+ import { type AppBehind } from "./db.ts";
9
10
  import { type CredentialStatus } from "./env.ts";
10
11
  import { type ApprovalState, Principal, type WorkflowDefinition } from "./define.ts";
11
12
  import { type ApplyInput, type ApplyReport } from "./apply.ts";
@@ -15,7 +16,9 @@ import { type LedgerRecord } from "./ledger.ts";
15
16
  import type { SignInMethod } from "./op.ts";
16
17
  import { type SecretLocation } from "./secret-store.ts";
17
18
  import { type RunStatus } from "./shared.ts";
18
- import { type RemoteEvent, type Source } from "./source.ts";
19
+ import type { ChatTurnInput } from "./chat-workflow.ts";
20
+ import type { RunChecks } from "./scenario.ts";
21
+ import type { RemoteEvent } from "./source.ts";
19
22
  /** A run's status from DBOS's, and whether it has an approval pending. */
20
23
  export declare function runStatus(dbosStatus: string, approvals: readonly ApprovalState[]): RunStatus;
21
24
  /** The DBOS statuses the run statuses come from; `running` and `waiting` both come from PENDING. */
@@ -122,11 +125,6 @@ export interface ClientOptions {
122
125
  * runs a worker that stops when idle starts it again with it (`Supervisor.resume`). Must not throw.
123
126
  */
124
127
  onWrite?: () => void;
125
- /**
126
- * The company's repository, as the worker is given it: what `remoteEvent` acts for (its
127
- * `origin`) and fetches a draft's new commits into. Without one, `remoteEvent` does nothing.
128
- */
129
- source?: Source;
130
128
  /**
131
129
  * The version each run it starts is queued for, so only a worker of that code runs it: the app
132
130
  * bundle's (its snapshot's), which is live beside a worker of another version while a deploy
@@ -169,7 +167,9 @@ export declare class SanomaClient {
169
167
  * The policy's answer to starting a run of `workflow` as `startedBy` (`decideStart`), for a
170
168
  * workflow of the config's own: a deny throws `policy_denied`; a hold is what the run waits on
171
169
  * before its body. A run `runId` names already is returned as it is, whatever the policy says now, but to a visitor.
172
- * A visitor (`isVisitor`) starts no built-in but `call`, whose calls the policy decides as direct ones.
170
+ * A visitor (`isVisitor`, an api token's principal too) starts no built-in but `call`, whose calls
171
+ * the policy decides as direct ones: the app's own actions on the repository (`app-workflows.ts`)
172
+ * are staff's, as their server functions were, which no site's host answered.
173
173
  */
174
174
  private startHold;
175
175
  /**
@@ -330,6 +330,11 @@ export declare class SanomaClient {
330
330
  * or the others, else all; at most `limit` (20).
331
331
  */
332
332
  changes({ open, limit }?: ChangesFilter): Promise<ChangeView[]>;
333
+ /**
334
+ * Whether a change is merging or deploying `main` now (`ChangeState.phase`, as its run last
335
+ * published it), which follows `main` and applies the hosts itself.
336
+ */
337
+ changeDeploying(): Promise<boolean>;
333
338
  /** The change of the draft `id`: its latest run's (`openChange`), or undefined when it has none. */
334
339
  change(id: string): Promise<ChangeView | undefined>;
335
340
  /**
@@ -347,34 +352,40 @@ export declare class SanomaClient {
347
352
  key?: string;
348
353
  }): Promise<void>;
349
354
  /**
350
- * Does what a host's webhook says happened (`RemoteEvent`, from a remote half's `webhook`) to the
351
- * company's repository, the `origin` of `ClientOptions.source` (`repositoryOf`); an event of
352
- * another repository, or with no source, is ignored. A delivery told again does nothing more.
353
- *
354
- * - `pushed` to `main`: the checkout follows `main`, then apply on the declared hosts
355
- * (`ResolvedConfig.hosts`) as `host-check`, as the run `deploy:<head>`, once per head; nothing
356
- * with no host, nor while a change is merging or deploying, which does both itself.
357
- * - `pushed` to a draft's branch (`draftOf`) with its change open: the host's commits fetched into
358
- * the draft (`Source.follow` on its branch), then the change told `commits`, as `by`; nothing
359
- * when the change or the draft is at that head already (the run's own push), or when the draft
360
- * cannot fast-forward to it (warned).
361
- * - `closed` for the open change's pull request: the change told `merged` (with its merge commit)
362
- * or `closed`, as `by`. The run checks either on the host before it believes it.
363
- */
364
- remoteEvent(event: RemoteEvent, options: {
355
+ * Starts the built-in follow workflow on what a host's webhook says happened (`RemoteEvent`,
356
+ * from a remote half's `webhook`, verified), as the runtime's agent `host-check`: the worker,
357
+ * which has the checkout, follows it there (`follow-workflow.ts`). Its run id is
358
+ * `follow:<sha256 of the event>`, so a delivery told again is the one run. Its id.
359
+ */
360
+ follow(event: RemoteEvent): Promise<string>;
361
+ /**
362
+ * Starts a turn of the chat `input.chat` on the person's new message `input.message`, already in
363
+ * its transcript (`chats.upsert`), as `startedBy`, the chat's person: the built-in chat workflow,
364
+ * as the run `chat:<chat>:<message>` (`chatRunId`), after the chat's turn before it, which it
365
+ * waits for; that turn, when it has not ended, is told to stop. The worker runs the turn and
366
+ * writes its reply (`chats.chunks`, then the transcript). Its run id.
367
+ */
368
+ startTurn(input: Omit<ChatTurnInput, "after">, options: StartOptions): Promise<string>;
369
+ /** The chat's latest turn (`startTurn`), or undefined when it has had none. */
370
+ turn(chat: string): Promise<RunSummary | undefined>;
371
+ /**
372
+ * Hands `code`, which the person pasted on their own agent's sign-in card, to the sign-in waiting
373
+ * in the turn under way of their chat `chat`, sealed (`sealChatCode`), so the run's messages never
374
+ * show it. `run_not_found` when the chat has no turn under way of `by`'s.
375
+ */
376
+ turnCode(chat: string, code: string, options: {
365
377
  by: Principal | string;
366
378
  }): Promise<void>;
367
- /** After a push of `head` to `main` (`remoteEvent`): the checkout follows it, then apply on the declared hosts. */
368
- private deployPush;
369
- /** Where each open change is (`ChangeState.phase`), read from what its run last published. */
370
- private openChangePhases;
371
379
  /**
372
- * Brings `head`, pushed to the draft's `branch` on the host, into the draft: false when it holds
373
- * it already, or cannot take it (no `follow`, a commit of its own, or one uncommitted: warned).
380
+ * How far the app `folder` (taken from a source) is behind its source, or why that cannot be
381
+ * told, as the worker last checked (at its start and after the checkout follows `main`);
382
+ * undefined when it has not told it.
374
383
  */
375
- private fetched;
376
- /** The repository of `ClientOptions.source` on its host (`repositoryOf`); undefined with no source, remote or half for it. */
377
- private repository;
384
+ appBehind(folder: string): Promise<AppBehind | undefined>;
385
+ /** A sandbox run's checks against its scenario as the worker last ran them (when the run last waited or ended); undefined for none yet. */
386
+ runChecks(runId: string): Promise<RunChecks | undefined>;
387
+ /** The latest `limit` turns of the chat `chat`, newest first: its runs `chat:<chat>:<message>` (`chatRunPrefix`). */
388
+ private turns;
378
389
  /** The runs of the draft `id`'s change, newest first: `change:<id>` and `change:<id>~<n>`. */
379
390
  private changeRuns;
380
391
  /** A change run's row as the app shows it: its summary, its last `ChangeState` and, once finished, its report. */
package/dist/client.js CHANGED
@@ -13,23 +13,21 @@ import { tokenStore } from "./tokens.js";
13
13
  import { collectionsDriver } from "./collection.js";
14
14
  import { resolveConfig } from "./config.js";
15
15
  import { configuredSecrets } from "./credentials.js";
16
- import { dbosClient, lazyDb, spendInviteRequest } from "./db.js";
16
+ import { dbosClient, lazyDb, readAppBehind, readRunChecks, spendInviteRequest, } from "./db.js";
17
17
  import { credentialsOf } from "./env.js";
18
18
  import { Principal } from "./define.js";
19
19
  import { APPLY_WORKFLOW } from "./apply.js";
20
- import { ADMIN, BASE, ChangeEventSchema, ChangeInput, followBase, initialChangeState, repositoryOf, } from "./change.js";
20
+ import { ADMIN, ChangeEventSchema, ChangeInput, initialChangeState, } from "./change.js";
21
21
  import { DRIFT_WORKFLOW } from "./drift.js";
22
22
  import { isDirect } from "./direct.js";
23
- import { ApprovalPendingError, errorCode, errorInfo, NotAdmittedError, parseOrThrow, PolicyDeniedError, SanomaError, vendorCodeOf, } from "./errors.js";
23
+ import { ApprovalPendingError, errorCode, errorInfo, NotAdmittedError, parseOrThrow, PolicyDeniedError, SanomaError, } from "./errors.js";
24
24
  import { insertRecord, lastInvite, lastSignIns, loginRecord, ownedLedger, } from "./ledger.js";
25
- import { warn } from "./log.js";
26
25
  import { allowAll } from "./policy.js";
27
26
  import { admit, readPeople } from "./resources.js";
28
27
  import { SecretStoreError } from "./secret-store.js";
29
- import { BUILT_IN_WORKFLOWS, CALL_WORKFLOW, CHANGE_EVENT, CHANGE_MERGE, CHANGE_TOPIC, CHANGE_WORKFLOW, changeIdOf, DATA_VENDOR, ENDED_STATUSES, errorMessage, HOST_CHECK_AGENT, isEnded, isToken, isVisitor, refusalOf, SCHEDULE_AGENT, WORKFLOW_ACTION, } from "./shared.js";
30
- import { draftOf } from "./source.js";
31
- /** Whether two references name one repository: a host's names are compared without case. */
32
- const sameRepo = (a, b) => a.owner.toLowerCase() === b.owner.toLowerCase() && a.name.toLowerCase() === b.name.toLowerCase();
28
+ import { BUILT_IN_WORKFLOWS, CALL_WORKFLOW, CHANGE_EVENT, CHANGE_MERGE, CHANGE_TOPIC, CHANGE_WORKFLOW, CHAT_TOPIC, CHAT_WORKFLOW, changeIdOf, chatRunId, chatRunPrefix, DATA_VENDOR, DRAFT_ID, ENDED_STATUSES, errorMessage, FOLLOW_WORKFLOW, HOST_CHECK_AGENT, isEnded, isToken, isVisitor, refusalOf, SCHEDULE_AGENT, WORKFLOW_ACTION, } from "./shared.js";
29
+ import { RemoteEventSchema } from "./follow-workflow.js";
30
+ import { sealChatCode } from "./seal.js";
33
31
  /** A principal, or its id alone. */
34
32
  const PrincipalOrId = z.union([
35
33
  z
@@ -142,10 +140,12 @@ export class SanomaClient {
142
140
  const parsed = parseOrThrow(workflow.input, input, `The input does not match ${workflow.name}'s schema`);
143
141
  const { runId } = options;
144
142
  const sandbox = parseOrThrow(z.string().min(1).optional(), options.sandbox, "`sandbox` must be the name of a scenario in the config's `scenarios/`");
145
- if (workflow.name === CHANGE_WORKFLOW && !isChangeRunOf(parsed.id, runId)) {
146
- throw new SanomaError("invalid_input", "A change is started with openChange, which names its run", { runId });
147
- }
148
143
  const hold = await this.startHold(workflow.name, parsed, startedBy, runId);
144
+ const own = OWN_STARTS[workflow.name];
145
+ if (own && !(await own.admits(parsed, startedBy, runId, this))) {
146
+ const refused = `A run of ${workflow.name} is started with ${own.by}, which names its run`;
147
+ throw new SanomaError("invalid_input", refused, { runId });
148
+ }
149
149
  const args = { input, startedBy, ...(sandbox === undefined ? {} : { sandbox }), ...(hold && { hold }) };
150
150
  // Kept on the run's status row too, so a listing tells sandbox runs apart without its input,
151
151
  // and says whom an agent's run is for (DBOS keeps the principal's id and groups itself); a
@@ -183,7 +183,9 @@ export class SanomaClient {
183
183
  * The policy's answer to starting a run of `workflow` as `startedBy` (`decideStart`), for a
184
184
  * workflow of the config's own: a deny throws `policy_denied`; a hold is what the run waits on
185
185
  * before its body. A run `runId` names already is returned as it is, whatever the policy says now, but to a visitor.
186
- * A visitor (`isVisitor`) starts no built-in but `call`, whose calls the policy decides as direct ones.
186
+ * A visitor (`isVisitor`, an api token's principal too) starts no built-in but `call`, whose calls
187
+ * the policy decides as direct ones: the app's own actions on the repository (`app-workflows.ts`)
188
+ * are staff's, as their server functions were, which no site's host answered.
187
189
  */
188
190
  async startHold(workflow, input, startedBy, runId) {
189
191
  const { policy } = this.config;
@@ -660,6 +662,21 @@ export class SanomaClient {
660
662
  const rows = await this.dbos.listWorkflows({ workflowIDs: ids, sortDesc: true, loadInput: true, loadOutput: true });
661
663
  return Promise.all(rows.map((row) => this.changeView(row)));
662
664
  }
665
+ /**
666
+ * Whether a change is merging or deploying `main` now (`ChangeState.phase`, as its run last
667
+ * published it), which follows `main` and applies the hosts itself.
668
+ */
669
+ async changeDeploying() {
670
+ const rows = await this.dbos.listWorkflows({
671
+ workflowName: CHANGE_WORKFLOW,
672
+ applicationName: this.config.appName,
673
+ status: dbosStatusesOf("queued", "running"),
674
+ loadInput: false,
675
+ loadOutput: false,
676
+ });
677
+ const phases = await Promise.all(rows.map(async (row) => (await this.dbos.getEvent(row.workflowID, CHANGE_EVENT, 0))?.phase));
678
+ return phases.some((phase) => phase === "merging" || phase === "deploying");
679
+ }
663
680
  /** The change of the draft `id`: its latest run's (`openChange`), or undefined when it has none. */
664
681
  async change(id) {
665
682
  const [row] = await this.changeRuns(id, { load: true });
@@ -708,108 +725,78 @@ export class SanomaClient {
708
725
  }
709
726
  }
710
727
  /**
711
- * Does what a host's webhook says happened (`RemoteEvent`, from a remote half's `webhook`) to the
712
- * company's repository, the `origin` of `ClientOptions.source` (`repositoryOf`); an event of
713
- * another repository, or with no source, is ignored. A delivery told again does nothing more.
714
- *
715
- * - `pushed` to `main`: the checkout follows `main`, then apply on the declared hosts
716
- * (`ResolvedConfig.hosts`) as `host-check`, as the run `deploy:<head>`, once per head; nothing
717
- * with no host, nor while a change is merging or deploying, which does both itself.
718
- * - `pushed` to a draft's branch (`draftOf`) with its change open: the host's commits fetched into
719
- * the draft (`Source.follow` on its branch), then the change told `commits`, as `by`; nothing
720
- * when the change or the draft is at that head already (the run's own push), or when the draft
721
- * cannot fast-forward to it (warned).
722
- * - `closed` for the open change's pull request: the change told `merged` (with its merge commit)
723
- * or `closed`, as `by`. The run checks either on the host before it believes it.
728
+ * Starts the built-in follow workflow on what a host's webhook says happened (`RemoteEvent`,
729
+ * from a remote half's `webhook`, verified), as the runtime's agent `host-check`: the worker,
730
+ * which has the checkout, follows it there (`follow-workflow.ts`). Its run id is
731
+ * `follow:<sha256 of the event>`, so a delivery told again is the one run. Its id.
724
732
  */
725
- async remoteEvent(event, options) {
726
- const main = event.kind === "pushed" && event.branch === BASE;
727
- const id = draftOf(event.branch);
728
- if (!main && id === undefined)
729
- return;
730
- const repository = await this.repository();
731
- if (!repository || !sameRepo(repository.repo, event.repo))
732
- return;
733
- if (main)
734
- return this.deployPush(repository, event.head);
735
- const change = await this.change(id);
736
- if (!change || isEnded(change.status))
737
- return;
738
- let told;
739
- let key;
740
- if (event.kind === "closed") {
741
- // A pull request of an earlier change of the draft is not this one's.
742
- if (event.number !== change.state.pullRequest?.number)
743
- return;
744
- told = event.merged && event.sha !== undefined ? { kind: "merged", sha: event.sha } : { kind: "closed" };
745
- key = `${event.number}:${event.sha ?? "closed"}`;
746
- }
747
- else {
748
- if (change.state.head === event.head || !(await this.fetched(repository, event.branch, event.head)))
749
- return;
750
- told = { kind: "commits" };
751
- key = event.head;
752
- }
753
- await this.changeEvent(id, told, { by: options.by, key: `${event.kind}:${event.branch}:${key}` }).catch((err) => {
754
- // Ended, or gone, since it was read: nothing to tell.
755
- if (!["run_ended", "run_not_found"].includes(errorCode(err) ?? ""))
756
- throw err;
757
- });
733
+ async follow(event) {
734
+ const parsed = parseOrThrow(RemoteEventSchema, event, "Not an event of a host's webhook");
735
+ return this.start(FOLLOW_WORKFLOW, parsed, { startedBy: HOST_CHECK_AGENT, runId: followRunId(parsed) });
758
736
  }
759
- /** After a push of `head` to `main` (`remoteEvent`): the checkout follows it, then apply on the declared hosts. */
760
- async deployPush({ source }, head) {
761
- const runId = `deploy:${head}`;
762
- const [deployed, phases] = await Promise.all([this.run(runId), this.openChangePhases()]);
763
- if (deployed || phases.some((phase) => phase === "merging" || phase === "deploying"))
764
- return;
765
- // First, as a change's deploy does: the hosts, and what apply reads, are then main's.
766
- const moved = await followBase(this.config.remotes, this.storedSecrets, source);
767
- if (!("revision" in moved)) {
768
- // Not on stale files, and nothing recorded as `deploy:<head>`: a redelivery may deploy it.
769
- warn(`${BASE} was not deployed: the checkout did not follow it: ${"skipped" in moved ? moved.skipped : moved.error}`);
770
- return;
737
+ /**
738
+ * Starts a turn of the chat `input.chat` on the person's new message `input.message`, already in
739
+ * its transcript (`chats.upsert`), as `startedBy`, the chat's person: the built-in chat workflow,
740
+ * as the run `chat:<chat>:<message>` (`chatRunId`), after the chat's turn before it, which it
741
+ * waits for; that turn, when it has not ended, is told to stop. The worker runs the turn and
742
+ * writes its reply (`chats.chunks`, then the transcript). Its run id.
743
+ */
744
+ async startTurn(input, options) {
745
+ const runId = chatRunId(input.chat, input.message);
746
+ // The latest other than this one, which a start told again finds first.
747
+ const before = (await this.turns(input.chat, 2)).find((row) => row.workflowID !== runId);
748
+ await this.start(CHAT_WORKFLOW, { ...input, ...(before && { after: before.workflowID }) }, {
749
+ ...options,
750
+ runId,
751
+ });
752
+ // Once the new turn stands, which refused anyone but the chat's person.
753
+ if (before && !isEnded(runStatus(before.status, []))) {
754
+ await this.dbos.send(before.workflowID, { kind: "stop" }, CHAT_TOPIC);
771
755
  }
772
- const hosts = await this.config.hosts();
773
- if (hosts.length)
774
- await this.apply({ only: hosts }, { startedBy: HOST_CHECK_AGENT, runId });
756
+ return runId;
775
757
  }
776
- /** Where each open change is (`ChangeState.phase`), read from what its run last published. */
777
- async openChangePhases() {
778
- const rows = await this.dbos.listWorkflows({
779
- workflowName: CHANGE_WORKFLOW,
780
- applicationName: this.config.appName,
781
- status: dbosStatusesOf("queued", "running"),
782
- loadInput: false,
783
- loadOutput: false,
784
- });
785
- return Promise.all(rows.map(async (r) => (await this.dbos.getEvent(r.workflowID, CHANGE_EVENT, 0))?.phase));
758
+ /** The chat's latest turn (`startTurn`), or undefined when it has had none. */
759
+ async turn(chat) {
760
+ const [row] = await this.turns(chat, 1);
761
+ return row && this.summarize(row);
786
762
  }
787
763
  /**
788
- * Brings `head`, pushed to the draft's `branch` on the host, into the draft: false when it holds
789
- * it already, or cannot take it (no `follow`, a commit of its own, or one uncommitted: warned).
764
+ * Hands `code`, which the person pasted on their own agent's sign-in card, to the sign-in waiting
765
+ * in the turn under way of their chat `chat`, sealed (`sealChatCode`), so the run's messages never
766
+ * show it. `run_not_found` when the chat has no turn under way of `by`'s.
790
767
  */
791
- async fetched({ source, url, host }, branch, head) {
792
- const local = await Promise.resolve(source.head(branch)).catch(() => undefined);
793
- if (local === head)
794
- return false;
795
- const moved = source.follow
796
- ? await source.follow({ url, token: await host.token(), ref: branch })
797
- : { skipped: "this repository cannot follow its remote" };
798
- if ("skipped" in moved) {
799
- warn(`${branch} did not take the host's commits: ${moved.skipped}`);
800
- return false;
768
+ async turnCode(chat, code, options) {
769
+ const by = await this.admitted(parseOrThrow(PrincipalOrId, options?.by, '`by` must be a principal, such as "alice" or { id: "alice" }'));
770
+ const [row] = await this.turns(chat, 1);
771
+ if (!row || isEnded(runStatus(row.status, [])) || row.authenticatedUser !== by.id) {
772
+ throw new SanomaError("run_not_found", `No turn of chat ${chat} is under way`, { chat });
801
773
  }
802
- return true;
774
+ const told = { kind: "code", sealed: sealChatCode(row.workflowID, code) };
775
+ await this.dbos.send(row.workflowID, told, CHAT_TOPIC);
803
776
  }
804
- /** The repository of `ClientOptions.source` on its host (`repositoryOf`); undefined with no source, remote or half for it. */
805
- async repository() {
806
- const { source } = this.options;
807
- if (!source)
808
- return undefined;
809
- return repositoryOf(this.config.remotes, this.storedSecrets, source).catch((err) => {
810
- if (["no_remote", "no_remote_half"].includes(vendorCodeOf(err) ?? ""))
811
- return undefined;
812
- throw err;
777
+ /**
778
+ * How far the app `folder` (taken from a source) is behind its source, or why that cannot be
779
+ * told, as the worker last checked (at its start and after the checkout follows `main`);
780
+ * undefined when it has not told it.
781
+ */
782
+ async appBehind(folder) {
783
+ return readAppBehind(await this.database.db(), folder);
784
+ }
785
+ /** A sandbox run's checks against its scenario as the worker last ran them (when the run last waited or ended); undefined for none yet. */
786
+ async runChecks(runId) {
787
+ return readRunChecks(await this.database.db(), runId);
788
+ }
789
+ /** The latest `limit` turns of the chat `chat`, newest first: its runs `chat:<chat>:<message>` (`chatRunPrefix`). */
790
+ async turns(chat, limit) {
791
+ return this.dbos.listWorkflows({
792
+ // DBOS matches the prefix with LIKE as given, where a chat id's `_` is any character: escaped.
793
+ workflow_id_prefix: chatRunPrefix(chat).replaceAll(/[\\%_]/g, "\\$&"),
794
+ workflowName: CHAT_WORKFLOW,
795
+ applicationName: this.config.appName,
796
+ sortDesc: true,
797
+ limit,
798
+ loadInput: false,
799
+ loadOutput: false,
813
800
  });
814
801
  }
815
802
  /** The runs of the draft `id`'s change, newest first: `change:<id>` and `change:<id>~<n>`. */
@@ -1273,6 +1260,32 @@ const alreadyDecided = (runId, a) => new SanomaError("already_decided", a.status
1273
1260
  ...(a.decidedBy === undefined ? {} : { decidedBy: a.decidedBy }),
1274
1261
  ...(a.withdrawnReason === undefined ? {} : { withdrawnReason: a.withdrawnReason }),
1275
1262
  });
1263
+ /**
1264
+ * The built-ins only one of the client's methods starts, by name: that method (`by`), and whether
1265
+ * a start is its own (`admits`), which `start` asks once the policy has (a visitor is denied
1266
+ * first), refusing any other: a change under the id `openChange` names; a follow as `host-check`
1267
+ * under its event's id; a chat turn under its chat's and message's id, after a turn of the same
1268
+ * chat, as the chat's person.
1269
+ */
1270
+ const OWN_STARTS = {
1271
+ [CHANGE_WORKFLOW]: { by: "openChange", admits: (input, _by, runId) => isChangeRunOf(input.id, runId) },
1272
+ [FOLLOW_WORKFLOW]: {
1273
+ by: "follow",
1274
+ admits: (event, by, runId) => runId === followRunId(event) && by.id === HOST_CHECK_AGENT,
1275
+ },
1276
+ [CHAT_WORKFLOW]: {
1277
+ by: "startTurn",
1278
+ admits: async ({ chat, message, after }, by, runId, client) => runId === chatRunId(chat, message) &&
1279
+ (after === undefined ||
1280
+ (after.startsWith(chatRunPrefix(chat)) && DRAFT_ID.test(after.slice(chatRunPrefix(chat).length)))) &&
1281
+ (await client.chats.get(chat))?.person === by.id,
1282
+ },
1283
+ };
1284
+ /**
1285
+ * A follow's run id (`SanomaClient.follow`): `follow:` and the SHA-256 of the event as its schema
1286
+ * parsed it, its keys then in the schema's order, so one event is one id however its JSON was laid out.
1287
+ */
1288
+ const followRunId = (parsed) => `follow:${createHash("sha256").update(JSON.stringify(parsed)).digest("hex")}`;
1276
1289
  /** A change's first run's id: `change:<draft id>`. */
1277
1290
  const changeRunId = (id) => `change:${id}`;
1278
1291
  /** True when `runId` is a run of the draft `id`'s change: `change:<id>` or `change:<id>~<n>`. */