stageflow 0.31.0 → 0.33.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 (96) hide show
  1. package/README.md +1 -0
  2. package/dist/agent/fakeAgent.js +0 -6
  3. package/dist/agent/piAdapter.js +21 -0
  4. package/dist/agent/port.d.ts +2 -0
  5. package/dist/agent/providerAuth.d.ts +6 -0
  6. package/dist/agent/providerAuth.js +50 -14
  7. package/dist/agent/resolveAgentPort.d.ts +2 -0
  8. package/dist/agent/resolveAgentPort.js +5 -1
  9. package/dist/config/listConfig.d.ts +0 -16
  10. package/dist/config/listConfig.js +0 -3
  11. package/dist/config/loadStage.js +10 -0
  12. package/dist/config/pipelineStageKeys.js +1 -0
  13. package/dist/email/accounts.d.ts +109 -0
  14. package/dist/email/accounts.js +285 -0
  15. package/dist/email/adapter.d.ts +69 -0
  16. package/dist/email/adapter.js +720 -0
  17. package/dist/email/attachments.d.ts +21 -0
  18. package/dist/email/attachments.js +146 -0
  19. package/dist/email/events.d.ts +95 -0
  20. package/dist/email/events.js +292 -0
  21. package/dist/email/host.d.ts +15 -0
  22. package/dist/email/host.js +119 -0
  23. package/dist/email/messages.d.ts +44 -0
  24. package/dist/email/messages.js +182 -0
  25. package/dist/email/port.d.ts +161 -0
  26. package/dist/email/port.js +12 -0
  27. package/dist/email/replies.d.ts +5 -0
  28. package/dist/email/replies.js +56 -0
  29. package/dist/email/submissions.d.ts +31 -0
  30. package/dist/email/submissions.js +123 -0
  31. package/dist/email/triggers.d.ts +140 -0
  32. package/dist/email/triggers.js +563 -0
  33. package/dist/hosted/containment.d.ts +3 -0
  34. package/dist/hosted/containment.js +36 -0
  35. package/dist/hosted/errors.d.ts +21 -0
  36. package/dist/hosted/errors.js +30 -0
  37. package/dist/hosted/packageSkills.d.ts +3 -0
  38. package/dist/hosted/packageSkills.js +80 -0
  39. package/dist/hosted/runtime.d.ts +12 -0
  40. package/dist/hosted/runtime.js +596 -0
  41. package/dist/hosted/sequencer.d.ts +28 -0
  42. package/dist/hosted/sequencer.js +129 -0
  43. package/dist/hosted/translate.d.ts +3 -0
  44. package/dist/hosted/translate.js +43 -0
  45. package/dist/hosted/types.d.ts +108 -0
  46. package/dist/hosted/types.js +10 -0
  47. package/dist/index.d.ts +8 -1
  48. package/dist/index.js +5 -0
  49. package/dist/package-meta.d.ts +1 -1
  50. package/dist/package-meta.js +1 -1
  51. package/dist/projection/projectRun.d.ts +0 -1
  52. package/dist/projection/projectRun.js +0 -1
  53. package/dist/runstore/port.d.ts +4 -0
  54. package/dist/runstore/sqlite/SqliteRunStore.d.ts +1 -0
  55. package/dist/runstore/sqlite/SqliteRunStore.js +24 -5
  56. package/dist/runstore/sqlite/migrations/011-email-dispatch-key.d.ts +7 -0
  57. package/dist/runstore/sqlite/migrations/011-email-dispatch-key.js +12 -0
  58. package/dist/runstore/sqlite/migrations/index.js +2 -0
  59. package/dist/runtime/containerLimits.d.ts +0 -3
  60. package/dist/runtime/containerLimits.js +0 -5
  61. package/dist/runtime/credentialBinding.d.ts +3 -0
  62. package/dist/runtime/credentialBinding.js +9 -0
  63. package/dist/runtime/pipelineRunner.d.ts +3 -0
  64. package/dist/runtime/pipelineRunner.js +11 -0
  65. package/dist/runtime/pipelineScheduler.js +3 -0
  66. package/dist/runtime/runManager.d.ts +1 -0
  67. package/dist/runtime/runManager.js +24 -3
  68. package/dist/runtime/runRetentionSweep.d.ts +0 -2
  69. package/dist/runtime/runRetentionSweep.js +0 -8
  70. package/dist/runtime/stageAttemptBootstrap.js +14 -0
  71. package/dist/runtime/stageProcessLauncher.d.ts +4 -0
  72. package/dist/runtime/stageProcessLauncher.js +45 -1
  73. package/dist/runtime/stageRoots.js +5 -1
  74. package/dist/server/bootstrap.d.ts +7 -0
  75. package/dist/server/bootstrap.js +17 -0
  76. package/dist/server/emailRoutes.d.ts +5 -0
  77. package/dist/server/emailRoutes.js +136 -0
  78. package/dist/server/http.d.ts +2 -0
  79. package/dist/server/http.js +16 -0
  80. package/dist/tools/readEmail.d.ts +77 -0
  81. package/dist/tools/readEmail.js +31 -0
  82. package/dist/tools/replyEmail.d.ts +31 -0
  83. package/dist/tools/replyEmail.js +25 -0
  84. package/dist/tools/sendEmail.d.ts +43 -0
  85. package/dist/tools/sendEmail.js +26 -0
  86. package/dist/types/stage.d.ts +4 -0
  87. package/dist/ui/assets/index-59cjF0OA.js +133 -0
  88. package/dist/ui/index.html +1 -1
  89. package/examples/hello-email/README.md +23 -0
  90. package/examples/hello-email/hello-email-reply.pipeline.yaml +6 -0
  91. package/examples/hello-email/hello-email.pipeline.yaml +6 -0
  92. package/examples/hello-email/hello-email.task.yaml +6 -0
  93. package/examples/hello-email/reply-hello-email.yaml +63 -0
  94. package/examples/hello-email/send-hello-email.yaml +37 -0
  95. package/package.json +14 -2
  96. package/dist/ui/assets/index-p8Iou3zk.js +0 -133
package/README.md CHANGED
@@ -254,6 +254,7 @@ Full docs: **[tejasghutukade.github.io/stageflow](https://tejasghutukade.github.
254
254
  |-----|-------------|
255
255
  | [docs/README.md](docs/README.md) | Documentation index |
256
256
  | [docs/architecture.md](docs/architecture.md) | Runtime components, execution flow, persistence, and design decisions |
257
+ | [docs/hosted.md](docs/hosted.md) | Embed Stageflow from another application and receive ordered run events |
257
258
  | [docs/quickstart.md](docs/quickstart.md) | Expanded quick start |
258
259
  | [docs/yaml-catalog.md](docs/yaml-catalog.md) | Pipelines, stages, tasks schema |
259
260
  | [docs/cli-reference.md](docs/cli-reference.md) | `sf init`, `sf run`, `sf run-stage`, `sf graph`, `sf validate`, `sf ui`, `sf mcp`, `sf envelope`, `sf export-run`, `sf artifact`, `sf skills`, `sf providers` |
@@ -113,12 +113,6 @@ export class FakeAgent {
113
113
  armWait();
114
114
  }
115
115
  }
116
- if (sessionMode === "feedback_resume" && behavior.type === "wait_then_emit") {
117
- behavior = {
118
- type: "emit",
119
- envelope: behavior.envelope,
120
- };
121
- }
122
116
  const emitStartActivity = () => {
123
117
  if (started)
124
118
  return;
@@ -44,6 +44,9 @@ import { attemptContext, noAttemptContext, } from "../runtime/stageAttemptContex
44
44
  import { createEmitStageEnvelopeTool, } from "../tools/emitStageEnvelope.js";
45
45
  import { createAskOperatorTool, } from "../tools/askOperator.js";
46
46
  import { createWriteStageArtifactTool } from "../tools/writeStageArtifact.js";
47
+ import { createSendEmailTool } from "../tools/sendEmail.js";
48
+ import { createReplyEmailTool } from "../tools/replyEmail.js";
49
+ import { createGetEmailTool, createSearchEmailTool, createDownloadEmailAttachmentTool } from "../tools/readEmail.js";
47
50
  import "./cursorProvider.js";
48
51
  import { findProviderSupport } from "./providerSupport.js";
49
52
  import { mapSessionEventToActivity, readActivityVerbose } from "./activity.js";
@@ -479,6 +482,9 @@ function buildUserPrompt(input, emitToolName, emitHintOverride, artifactToolName
479
482
  ].join("\n")
480
483
  : `Create factory stage artifacts under ${attemptArtifactsPath} relative to the run folder.`;
481
484
  return [
485
+ ...(input.stage.email?.length ? [
486
+ `Stageflow email permissions: ${JSON.stringify(input.stage.email)}. Use only declared accounts and operations. Use a stable operationKey for each intended message. Provider acceptance does not prove delivery. Never resend an unknown submission automatically.`,
487
+ ] : []),
482
488
  `Task id: ${input.task.id}`,
483
489
  `Stage id: ${runtimeStageId(input)}`,
484
490
  `Goal: ${input.task.goal}`,
@@ -908,6 +914,21 @@ async function prepareStageSessionWiring(input, sessionManager, existingAskWaitC
908
914
  if (attached.extensionFactories !== undefined) {
909
915
  tools.push(...collectMcpExtensionToolNames(loader));
910
916
  }
917
+ if (input.email) {
918
+ const permitted = new Set(input.stage.email?.flatMap(permission => permission.operations));
919
+ const definitions = [
920
+ permitted.has("send") ? createSendEmailTool(input.email) : undefined,
921
+ permitted.has("reply") ? createReplyEmailTool(input.email) : undefined,
922
+ permitted.has("search") ? createSearchEmailTool(input.email) : undefined,
923
+ permitted.has("getMessage") ? createGetEmailTool(input.email) : undefined,
924
+ permitted.has("downloadAttachment") ? createDownloadEmailAttachmentTool(input.email) : undefined,
925
+ ];
926
+ for (const definition of definitions)
927
+ if (definition) {
928
+ customTools.push(defineTool(definition));
929
+ tools.push(definition.name);
930
+ }
931
+ }
911
932
  return {
912
933
  sessionManager,
913
934
  modelRuntime,
@@ -7,6 +7,7 @@ import type { TaskFile } from "../types/task.js";
7
7
  import type { StageActivityEvent } from "./activity.js";
8
8
  import type { ResolvedMcpServers } from "../config/resolveStageMcpServers.js";
9
9
  import type { StageRoots } from "../runtime/stageRoots.js";
10
+ import type { StageEmail } from "../email/host.js";
10
11
  import type { QaExchange } from "../hitl/qaTrail.js";
11
12
  import type { StageUsage } from "../types/usage.js";
12
13
  /** Opaque to runtime; adapters interpret. */
@@ -63,6 +64,7 @@ export type StageRunInput = {
63
64
  /** Optional raw assistant-text-delta sink, fired alongside onActivity, not instead of it. */
64
65
  onAssistantTextDelta?: (delta: string) => void;
65
66
  skillFilePath?: string;
67
+ email?: StageEmail;
66
68
  /** Bundled browser skill; set by the runtime when the stage has `browser`. */
67
69
  browserSkillFilePath?: string;
68
70
  forkEmitContext?: ForkEmitContext;
@@ -82,6 +82,12 @@ export declare function statusForProvider(runtime: ProviderAuthRuntime, provider
82
82
  export declare function listProviders(cwd: string, ctx?: ProviderAuthContext): Promise<ProvidersListResult>;
83
83
  export declare function getAuthStatus(cwd: string, providerId?: string, ctx?: ProviderAuthContext): Promise<ProviderAuthStatus | ProviderAuthStatus[]>;
84
84
  export declare function loginWithApiKey(cwd: string, providerId: string, apiKey: string, ctx?: ProviderAuthContext): Promise<ProviderAuthStatus>;
85
+ /** Write a provider API key into an existing Pi auth file. Does not create the operator home. */
86
+ export declare function configurePiProviderApiKey(options: {
87
+ authPath: string;
88
+ providerId: string;
89
+ apiKey: string;
90
+ }, ctx?: ProviderAuthContext): Promise<void>;
85
91
  export type OauthLoginResult = {
86
92
  provider: ProviderAuthStatus;
87
93
  warning?: string;
@@ -1,3 +1,5 @@
1
+ import { mkdir, writeFile, chmod, access } from "node:fs/promises";
2
+ import path from "node:path";
1
3
  import { CredentialSynchronizationError, ModelRuntime, } from "@earendil-works/pi-coding-agent";
2
4
  import { parseCredentialSource, resolveCredentialBinding, writeCredentialSourceToContext, isUsableAuthFile, } from "../runtime/credentialBinding.js";
3
5
  import { getCursorHostStatus } from "./cursorProvider.js";
@@ -22,6 +24,23 @@ export class ProviderAuthError extends Error {
22
24
  }
23
25
  }
24
26
  const defaultCreateRuntime = async (authPath) => ModelRuntime.create({ authPath, refreshOnCreate: false });
27
+ async function ensurePiAuthFile(authPath) {
28
+ const resolved = path.resolve(authPath);
29
+ await mkdir(path.dirname(resolved), { recursive: true });
30
+ try {
31
+ await access(resolved);
32
+ }
33
+ catch {
34
+ await writeFile(resolved, "{}\n", { encoding: "utf8", mode: 0o600 });
35
+ }
36
+ try {
37
+ await chmod(resolved, 0o600);
38
+ }
39
+ catch {
40
+ // best-effort on non-POSIX
41
+ }
42
+ return resolved;
43
+ }
25
44
  export const defaultContext = {
26
45
  createRuntime: defaultCreateRuntime,
27
46
  lock: makeMutationLock(),
@@ -159,26 +178,43 @@ function mapLoginError(err, providerId) {
159
178
  }
160
179
  throw new ProviderAuthError("Provider login failed", 500);
161
180
  }
181
+ async function loginApiKeyOnRuntime(runtime, providerId, apiKey) {
182
+ if (typeof apiKey !== "string" || apiKey.trim().length === 0) {
183
+ throw new ProviderAuthError("apiKey is required", 400);
184
+ }
185
+ const provider = runtime.getProvider(providerId);
186
+ if (!provider) {
187
+ throw new ProviderAuthError("Provider not found", 404);
188
+ }
189
+ if (typeof provider.auth.apiKey?.login !== "function") {
190
+ throw new ProviderAuthError("Provider does not support api_key login", 400);
191
+ }
192
+ try {
193
+ await runtime.login(providerId, "api_key", apiKeyInteraction(apiKey));
194
+ }
195
+ catch (err) {
196
+ mapLoginError(err, providerId);
197
+ }
198
+ return statusForProvider(runtime, providerId);
199
+ }
162
200
  export async function loginWithApiKey(cwd, providerId, apiKey, ctx = defaultContext) {
163
201
  if (typeof apiKey !== "string" || apiKey.trim().length === 0) {
164
202
  throw new ProviderAuthError("apiKey is required", 400);
165
203
  }
166
204
  return ctx.lock.withMutationLock(async () => {
167
205
  const runtime = await openRuntime(cwd, ctx);
168
- const provider = runtime.getProvider(providerId);
169
- if (!provider) {
170
- throw new ProviderAuthError("Provider not found", 404);
171
- }
172
- if (typeof provider.auth.apiKey?.login !== "function") {
173
- throw new ProviderAuthError("Provider does not support api_key login", 400);
174
- }
175
- try {
176
- await runtime.login(providerId, "api_key", apiKeyInteraction(apiKey));
177
- }
178
- catch (err) {
179
- mapLoginError(err, providerId);
180
- }
181
- return statusForProvider(runtime, providerId);
206
+ return loginApiKeyOnRuntime(runtime, providerId, apiKey);
207
+ });
208
+ }
209
+ /** Write a provider API key into an existing Pi auth file. Does not create the operator home. */
210
+ export async function configurePiProviderApiKey(options, ctx = defaultContext) {
211
+ if (typeof options.authPath !== "string" || options.authPath.trim() === "") {
212
+ throw new ProviderAuthError("authPath is required", 400);
213
+ }
214
+ const authPath = await ensurePiAuthFile(options.authPath);
215
+ await ctx.lock.withMutationLock(async () => {
216
+ const runtime = await ctx.createRuntime(authPath);
217
+ await loginApiKeyOnRuntime(runtime, options.providerId, options.apiKey);
182
218
  });
183
219
  }
184
220
  export async function loginWithOauth(cwd, providerId, interaction, ctx = defaultContext) {
@@ -11,6 +11,8 @@ export type AgentSelection = {
11
11
  };
12
12
  /** stage > pipeline > global > "pi", with stage gated off for now. */
13
13
  export declare function resolveAgentBackend(selection?: AgentSelection): AgentBackendId;
14
+ /** Existing Pi AgentPort. Hosted runs pass this into createHostedRuntime. */
15
+ export declare function createPiAgentPort(): AgentPort;
14
16
  export declare function resolveAgentPort(selection?: AgentSelection): AgentPort;
15
17
  /** The global tier's backend id from an already-loaded manifest, or undefined for missing/invalid/unset. */
16
18
  export declare function globalAgentBackendFromManifest(manifest: LoadedManifest | null): AgentBackendId | undefined;
@@ -9,11 +9,15 @@ export function resolveAgentBackend(selection = {}) {
9
9
  }
10
10
  return selection.pipeline ?? selection.global ?? "pi";
11
11
  }
12
+ /** Existing Pi AgentPort. Hosted runs pass this into createHostedRuntime. */
13
+ export function createPiAgentPort() {
14
+ return new PiAgentAdapter();
15
+ }
12
16
  export function resolveAgentPort(selection = {}) {
13
17
  const backend = resolveAgentBackend(selection);
14
18
  switch (backend) {
15
19
  case "pi":
16
- return new PiAgentAdapter();
20
+ return createPiAgentPort();
17
21
  case "claude":
18
22
  return new ClaudeAgentAdapter();
19
23
  }
@@ -1,28 +1,12 @@
1
- import type { StageGateKind } from "../types/stage.js";
2
1
  import type { LoadedManifest } from "../types/stageflowManifest.js";
3
2
  import { type PipelineListing, type TaskListing } from "./browseCatalog.js";
4
3
  import { type StageflowContext } from "../project/resolveStageflowContext.js";
5
4
  import { type CatalogContext } from "./resolveCatalogContext.js";
6
5
  export type { PipelineListing, PipelineStageListing, TaskListing } from "./browseCatalog.js";
7
- export type ValidStageListing = {
8
- path: string;
9
- id: string;
10
- used_by_pipeline_ids: string[];
11
- gate_kinds?: StageGateKind[];
12
- };
13
- export type BrokenStageListing = {
14
- path: string;
15
- error: string;
16
- id?: string;
17
- model?: string;
18
- gate_kinds?: StageGateKind[];
19
- };
20
- export type StageListing = ValidStageListing | BrokenStageListing;
21
6
  export type CatalogListOptions = {
22
7
  projectRoot: string;
23
8
  manifest: LoadedManifest;
24
9
  };
25
10
  export declare function listTasks(options: CatalogListOptions): Promise<TaskListing[]>;
26
11
  export declare function listPipelines(options: CatalogListOptions): Promise<PipelineListing[]>;
27
- export declare function listStages(_options?: unknown): Promise<StageListing[]>;
28
12
  export declare function listModels(cwdOrContext: string | CatalogContext | StageflowContext): Promise<string[]>;
@@ -17,9 +17,6 @@ export async function listPipelines(options) {
17
17
  issues: [],
18
18
  });
19
19
  }
20
- export async function listStages(_options) {
21
- return [];
22
- }
23
20
  export async function listModels(cwdOrContext) {
24
21
  const ctx = typeof cwdOrContext === "string"
25
22
  ? catalogContextFromStageflow(await resolveStageflowContext(cwdOrContext))
@@ -7,6 +7,7 @@ import { parseModelField } from "./modelField.js";
7
7
  import { allowLegacyYamlAuthoring, dialectWarningForDocument, legacyAuthoringRejected, presentLegacyKeys, } from "./legacyYaml.js";
8
8
  import { parsePreEmitChecks } from "./parsePreEmitChecks.js";
9
9
  import { readYamlObject } from "./readYamlObject.js";
10
+ import { z } from "zod";
10
11
  import { parseStageSecrets } from "../runtime/stageSecretDecl.js";
11
12
  import { parseToolRequires } from "./toolRequires.js";
12
13
  import { parseStageBrowser } from "./stageBrowser.js";
@@ -140,6 +141,15 @@ function parseStageFields(raw, label, entryId, deferSchemaRefs, requireIo, compi
140
141
  id: entryId,
141
142
  system_prompt: raw.system_prompt,
142
143
  };
144
+ if (raw.email !== undefined) {
145
+ const permissions = z.array(z.object({ accountId: z.string().min(1).max(200),
146
+ operations: z.array(z.enum(["send", "reply", "getMessage", "search", "downloadAttachment"])).min(1).max(5),
147
+ }).strict()).max(20).safeParse(raw.email);
148
+ if (!permissions.success || new Set(permissions.data.map(permission => permission.accountId)).size !== permissions.data.length) {
149
+ return loadFailure([{ code: "stage.invalid_shape", message: `Invalid stage ${label}: invalid email permissions`, category: "stage", stageId: entryId }]);
150
+ }
151
+ stage.email = permissions.data;
152
+ }
143
153
  if (raw.clone_actions !== undefined) {
144
154
  return loadFailure([
145
155
  {
@@ -28,6 +28,7 @@ export const WIRING_KEYS = new Set([
28
28
  ]);
29
29
  /** Stage body keys. Target: `io` / `verify`. IR/legacy: `payload_schema`, `pre_emit_checks`, `clone_input_schema`. */
30
30
  export const BODY_KEYS = new Set([
31
+ "email",
31
32
  "system_prompt",
32
33
  "model",
33
34
  "payload_schema",
@@ -0,0 +1,109 @@
1
+ import { z } from "zod";
2
+ import { type EmailAccountStatus } from "./port.js";
3
+ declare const connectionSchema: z.ZodObject<{
4
+ host: z.ZodString;
5
+ port: z.ZodNumber;
6
+ username: z.ZodString;
7
+ tls: z.ZodDefault<z.ZodEnum<{
8
+ implicit: "implicit";
9
+ none: "none";
10
+ starttls: "starttls";
11
+ }>>;
12
+ auth: z.ZodObject<{
13
+ type: z.ZodEnum<{
14
+ oauth2: "oauth2";
15
+ password: "password";
16
+ }>;
17
+ secretRef: z.ZodString;
18
+ expiresAt: z.ZodOptional<z.ZodISODateTime>;
19
+ }, z.core.$strict>;
20
+ }, z.core.$strict>;
21
+ declare const accountSchema: z.ZodObject<{
22
+ displayName: z.ZodString;
23
+ address: z.ZodEmail;
24
+ enabled: z.ZodDefault<z.ZodBoolean>;
25
+ adapter: z.ZodDefault<z.ZodLiteral<"local">>;
26
+ folders: z.ZodDefault<z.ZodArray<z.ZodString>>;
27
+ senderAliases: z.ZodDefault<z.ZodArray<z.ZodEmail>>;
28
+ imap: z.ZodObject<{
29
+ host: z.ZodString;
30
+ port: z.ZodNumber;
31
+ username: z.ZodString;
32
+ tls: z.ZodDefault<z.ZodEnum<{
33
+ implicit: "implicit";
34
+ none: "none";
35
+ starttls: "starttls";
36
+ }>>;
37
+ auth: z.ZodObject<{
38
+ type: z.ZodEnum<{
39
+ oauth2: "oauth2";
40
+ password: "password";
41
+ }>;
42
+ secretRef: z.ZodString;
43
+ expiresAt: z.ZodOptional<z.ZodISODateTime>;
44
+ }, z.core.$strict>;
45
+ }, z.core.$strict>;
46
+ smtp: z.ZodObject<{
47
+ host: z.ZodString;
48
+ port: z.ZodNumber;
49
+ username: z.ZodString;
50
+ tls: z.ZodDefault<z.ZodEnum<{
51
+ implicit: "implicit";
52
+ none: "none";
53
+ starttls: "starttls";
54
+ }>>;
55
+ auth: z.ZodObject<{
56
+ type: z.ZodEnum<{
57
+ oauth2: "oauth2";
58
+ password: "password";
59
+ }>;
60
+ secretRef: z.ZodString;
61
+ expiresAt: z.ZodOptional<z.ZodISODateTime>;
62
+ }, z.core.$strict>;
63
+ }, z.core.$strict>;
64
+ allowInsecureLocalDevelopment: z.ZodDefault<z.ZodBoolean>;
65
+ connectionTimeoutMs: z.ZodDefault<z.ZodNumber>;
66
+ pollingIntervalMs: z.ZodDefault<z.ZodNumber>;
67
+ reconnectMaxDelayMs: z.ZodDefault<z.ZodNumber>;
68
+ searchWorkLimit: z.ZodDefault<z.ZodNumber>;
69
+ attachmentLimits: z.ZodDefault<z.ZodObject<{
70
+ count: z.ZodDefault<z.ZodNumber>;
71
+ perFileBytes: z.ZodDefault<z.ZodNumber>;
72
+ totalBytes: z.ZodDefault<z.ZodNumber>;
73
+ downloadBytes: z.ZodDefault<z.ZodNumber>;
74
+ }, z.core.$strict>>;
75
+ sentFolder: z.ZodOptional<z.ZodString>;
76
+ sentCopyPolicy: z.ZodDefault<z.ZodEnum<{
77
+ "imap-append": "imap-append";
78
+ "provider-managed": "provider-managed";
79
+ }>>;
80
+ sentCopyMaxBytes: z.ZodDefault<z.ZodNumber>;
81
+ }, z.core.$strict>;
82
+ export type EmailAccountInput = z.input<typeof accountSchema>;
83
+ export type EmailConnection = z.output<typeof connectionSchema>;
84
+ export type EmailAccount = z.output<typeof accountSchema> & {
85
+ accountId: string;
86
+ scope: string;
87
+ };
88
+ /** Host-owned configuration. Reads return copies; mutations replace the file atomically. */
89
+ export declare class EmailAccounts {
90
+ readonly scope: string;
91
+ private readonly file;
92
+ private state;
93
+ private readonly listeners;
94
+ constructor(cwd: string);
95
+ list(): EmailAccount[];
96
+ get(accountId: string, requireEnabled?: boolean): EmailAccount;
97
+ create(input: unknown): EmailAccount;
98
+ update(accountId: string, patch: unknown): EmailAccount;
99
+ remove(accountId: string): void;
100
+ health(accountId: string): EmailAccountStatus | undefined;
101
+ recordHealth(status: EmailAccountStatus): void;
102
+ onChange(listener: (accountId: string) => void): () => void;
103
+ private notify;
104
+ private requireHttpAccount;
105
+ private syncStartupAccounts;
106
+ private persist;
107
+ }
108
+ export declare function resolveEmailSecret(connection: EmailConnection, env?: NodeJS.ProcessEnv): string;
109
+ export {};