@eigenpal/cli 0.15.1 → 0.16.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/dist/cli.js CHANGED
@@ -7685,6 +7685,7 @@ var init_common = __esm(() => {
7685
7685
  AUTOMATION_TRIGGER: "atr",
7686
7686
  FILE_SOURCE_CONFIG: "fsc",
7687
7687
  FILE_UPLOAD: "fup",
7688
+ EMAIL_SERVER: "ems",
7688
7689
  WEBHOOK_ENDPOINT: "whep",
7689
7690
  WEBHOOK_EVENT: "whev",
7690
7691
  WEBHOOK_DELIVERY: "whdl",
@@ -7803,7 +7804,11 @@ var init_ai_client = __esm(() => {
7803
7804
  ];
7804
7805
  ReasoningEffortSchema = _enum(REASONING_EFFORTS);
7805
7806
  ModelReasoningConfigSchema = object({
7806
- supportedEfforts: array(ReasoningEffortSchema).min(1)
7807
+ supportedEfforts: array(ReasoningEffortSchema).min(1),
7808
+ defaultEffort: ReasoningEffortSchema.optional()
7809
+ }).refine((config) => config.defaultEffort === undefined || config.supportedEfforts.includes(config.defaultEffort), {
7810
+ message: "defaultEffort must be included in supportedEfforts",
7811
+ path: ["defaultEffort"]
7807
7812
  }).strict();
7808
7813
  });
7809
7814
 
@@ -15429,6 +15434,250 @@ var init_validation = __esm(() => {
15429
15434
  init_workspace_schema();
15430
15435
  });
15431
15436
 
15437
+ // ../types/src/email-servers.ts
15438
+ function defaultSmtpPort(security, port) {
15439
+ return port ?? SMTP_DEFAULT_PORT_BY_SECURITY[security];
15440
+ }
15441
+ function refineSmtpCredentialPair(data, ctx) {
15442
+ const hasUsername = data.username !== undefined;
15443
+ const hasPassword = data.password !== undefined;
15444
+ if (hasUsername !== hasPassword) {
15445
+ ctx.addIssue({
15446
+ code: "custom",
15447
+ path: hasUsername ? ["password"] : ["username"],
15448
+ message: "SMTP username and password must both be set or both omitted"
15449
+ });
15450
+ }
15451
+ }
15452
+ function refineSmtpNoneRejectsCredentials(data, ctx) {
15453
+ if (data.security !== "none")
15454
+ return;
15455
+ if (typeof data.username === "string") {
15456
+ ctx.addIssue({
15457
+ code: "custom",
15458
+ path: ["username"],
15459
+ message: SMTP_NONE_CREDENTIALS_MESSAGE
15460
+ });
15461
+ }
15462
+ if (data.password !== undefined) {
15463
+ ctx.addIssue({
15464
+ code: "custom",
15465
+ path: ["password"],
15466
+ message: SMTP_NONE_CREDENTIALS_MESSAGE
15467
+ });
15468
+ }
15469
+ }
15470
+ function hasTransport(patch) {
15471
+ return "transport" in patch;
15472
+ }
15473
+ function smtpDestinationChanged(existingTransport, patch, storedSmtp) {
15474
+ if (existingTransport !== "smtp")
15475
+ return false;
15476
+ const hostChanged = storedSmtp?.host != null && storedSmtp.host !== patch.host;
15477
+ const usernameChanged = typeof patch.username === "string" && patch.username !== (storedSmtp?.username ?? null);
15478
+ return hostChanged || usernameChanged;
15479
+ }
15480
+ function planEmailServerSecretUpdate(input) {
15481
+ if (!hasTransport(input.patch)) {
15482
+ return { resendApiKey: "retain", smtpPassword: "retain", caPem: "retain" };
15483
+ }
15484
+ if (input.patch.transport === "resend") {
15485
+ return {
15486
+ resendApiKey: input.patch.apiKey !== undefined ? "set" : "retain",
15487
+ smtpPassword: "clear",
15488
+ caPem: "clear"
15489
+ };
15490
+ }
15491
+ const password = input.patch.password !== undefined ? "set" : input.patch.username === null ? "clear" : input.existingTransport !== "smtp" ? "clear" : smtpDestinationChanged(input.existingTransport, input.patch, input.storedSmtp) ? "clear" : "retain";
15492
+ const caPem = input.patch.caPem === null ? "clear" : input.patch.caPem !== undefined ? "set" : input.existingTransport === "smtp" ? "retain" : "clear";
15493
+ return {
15494
+ resendApiKey: "clear",
15495
+ smtpPassword: password,
15496
+ caPem
15497
+ };
15498
+ }
15499
+ function planSmtpAuthActions(existingTransport, patch, storedSmtp) {
15500
+ const secrets = planEmailServerSecretUpdate({ existingTransport, storedSmtp, patch });
15501
+ const username = patch.username === null ? "clear" : typeof patch.username === "string" ? "set" : existingTransport === "smtp" ? "retain" : "clear";
15502
+ return { username, password: secrets.smtpPassword };
15503
+ }
15504
+ function actionLeavesPresent(action, storedPresent) {
15505
+ if (action === "set")
15506
+ return true;
15507
+ if (action === "clear")
15508
+ return false;
15509
+ return storedPresent;
15510
+ }
15511
+ function getEmailServerUpdateError(existingTransport, patch, storedSmtp) {
15512
+ if (hasTransport(patch) && patch.transport === "smtp") {
15513
+ const auth = planSmtpAuthActions(existingTransport, patch, storedSmtp);
15514
+ const hasUsername = actionLeavesPresent(auth.username, Boolean(storedSmtp?.username));
15515
+ const hasPassword = actionLeavesPresent(auth.password, storedSmtp?.passwordConfigured === true);
15516
+ if (patch.security === "none" && (hasUsername || hasPassword)) {
15517
+ return SMTP_NONE_CREDENTIALS_MESSAGE;
15518
+ }
15519
+ if (smtpDestinationChanged(existingTransport, patch, storedSmtp) && patch.password === undefined && hasUsername && storedSmtp?.passwordConfigured === true) {
15520
+ return SMTP_TARGET_PASSWORD_MESSAGE;
15521
+ }
15522
+ if (hasUsername !== hasPassword) {
15523
+ return SMTP_CREDENTIAL_PAIR_MESSAGE;
15524
+ }
15525
+ }
15526
+ if (!hasTransport(patch))
15527
+ return null;
15528
+ if (patch.transport === existingTransport)
15529
+ return null;
15530
+ if (patch.transport === "resend" && patch.apiKey === undefined) {
15531
+ return "Resend API key is required when changing transport to resend";
15532
+ }
15533
+ return null;
15534
+ }
15535
+ var EMAIL_SERVER_TRANSPORTS, SMTP_SECURITY_MODES, SMTP_DEFAULT_PORT_BY_SECURITY, EMAIL_SERVER_ID_PREFIX, EMAIL_SERVER_ID_PATTERN, EmailServerIdSchema, EmailServerNameSchema, EmailServerFromEmailSchema, FROM_NAME_UNSAFE, EmailServerFromNameSchema, SmtpHostSchema, SmtpPortSchema, SmtpSecuritySchema, SmtpUsernameSchema, SecretStringSchema, fromFields, SMTP_NONE_CREDENTIALS_MESSAGE = "SMTP credentials cannot be used with security 'none'", SMTP_CREDENTIAL_PAIR_MESSAGE = "SMTP username and password must both be present or both absent", SMTP_TARGET_PASSWORD_MESSAGE = "A new SMTP password is required when the host or username changes", CreateResendEmailServerRequestSchema, CreateSmtpEmailServerRequestSchema, CreateEmailServerRequestSchema, UpdateMetadataOnlySchema, UpdateResendEmailServerRequestSchema, UpdateSmtpEmailServerRequestSchema, UpdateEmailServerRequestSchema, PublicEmailServerTimestamps, PublicResendEmailServerSchema, PublicSmtpEmailServerSchema, EmailServerSchema, ListEmailServersResponseSchema, DeleteEmailServerResponseSchema, TestEmailServerRequestSchema, TestEmailServerResponseSchema;
15536
+ var init_email_servers = __esm(() => {
15537
+ init_zod();
15538
+ init_common();
15539
+ EMAIL_SERVER_TRANSPORTS = ["resend", "smtp"];
15540
+ SMTP_SECURITY_MODES = ["starttls", "tls", "none"];
15541
+ SMTP_DEFAULT_PORT_BY_SECURITY = {
15542
+ starttls: 587,
15543
+ tls: 465,
15544
+ none: 25
15545
+ };
15546
+ EMAIL_SERVER_ID_PREFIX = ID_PREFIXES.EMAIL_SERVER;
15547
+ EMAIL_SERVER_ID_PATTERN = /^ems_[A-Za-z0-9_-]+$/;
15548
+ EmailServerIdSchema = string2().regex(EMAIL_SERVER_ID_PATTERN, "Expected ems_… id").max(128);
15549
+ EmailServerNameSchema = string2().trim().min(1).max(128);
15550
+ EmailServerFromEmailSchema = string2().trim().email();
15551
+ FROM_NAME_UNSAFE = /[\p{Cc}<>]/u;
15552
+ EmailServerFromNameSchema = string2().trim().min(1).max(128).refine((value) => !FROM_NAME_UNSAFE.test(value), {
15553
+ message: "fromName cannot contain control characters or angle brackets"
15554
+ });
15555
+ SmtpHostSchema = string2().trim().min(1).max(253);
15556
+ SmtpPortSchema = number2().int().min(1).max(65535);
15557
+ SmtpSecuritySchema = _enum(SMTP_SECURITY_MODES);
15558
+ SmtpUsernameSchema = string2().min(1).max(256);
15559
+ SecretStringSchema = string2().min(1);
15560
+ fromFields = {
15561
+ fromEmail: EmailServerFromEmailSchema,
15562
+ fromName: EmailServerFromNameSchema
15563
+ };
15564
+ CreateResendEmailServerRequestSchema = object({
15565
+ name: EmailServerNameSchema,
15566
+ enabled: boolean2().optional().default(true),
15567
+ transport: literal("resend"),
15568
+ apiKey: SecretStringSchema,
15569
+ ...fromFields
15570
+ }).strict();
15571
+ CreateSmtpEmailServerRequestSchema = object({
15572
+ name: EmailServerNameSchema,
15573
+ enabled: boolean2().optional().default(true),
15574
+ transport: literal("smtp"),
15575
+ host: SmtpHostSchema,
15576
+ port: SmtpPortSchema.optional(),
15577
+ security: SmtpSecuritySchema.optional().default("starttls"),
15578
+ username: SmtpUsernameSchema.optional(),
15579
+ password: SecretStringSchema.optional(),
15580
+ caPem: SecretStringSchema.optional(),
15581
+ ...fromFields
15582
+ }).strict().superRefine((data, ctx) => {
15583
+ refineSmtpCredentialPair(data, ctx);
15584
+ refineSmtpNoneRejectsCredentials(data, ctx);
15585
+ }).transform((data) => ({
15586
+ ...data,
15587
+ port: defaultSmtpPort(data.security, data.port)
15588
+ }));
15589
+ CreateEmailServerRequestSchema = discriminatedUnion("transport", [
15590
+ CreateResendEmailServerRequestSchema,
15591
+ CreateSmtpEmailServerRequestSchema
15592
+ ]).meta({ id: "CreateEmailServerRequest" });
15593
+ UpdateMetadataOnlySchema = object({
15594
+ name: EmailServerNameSchema.optional(),
15595
+ enabled: boolean2().optional()
15596
+ }).strict().superRefine((value, ctx) => {
15597
+ if (value.name === undefined && value.enabled === undefined) {
15598
+ ctx.addIssue({
15599
+ code: "custom",
15600
+ message: "at least one field is required"
15601
+ });
15602
+ }
15603
+ });
15604
+ UpdateResendEmailServerRequestSchema = object({
15605
+ name: EmailServerNameSchema.optional(),
15606
+ enabled: boolean2().optional(),
15607
+ transport: literal("resend"),
15608
+ apiKey: SecretStringSchema.optional(),
15609
+ ...fromFields
15610
+ }).strict();
15611
+ UpdateSmtpEmailServerRequestSchema = object({
15612
+ name: EmailServerNameSchema.optional(),
15613
+ enabled: boolean2().optional(),
15614
+ transport: literal("smtp"),
15615
+ host: SmtpHostSchema,
15616
+ port: SmtpPortSchema,
15617
+ security: SmtpSecuritySchema,
15618
+ username: SmtpUsernameSchema.nullable().optional(),
15619
+ password: SecretStringSchema.optional(),
15620
+ caPem: SecretStringSchema.nullable().optional(),
15621
+ ...fromFields
15622
+ }).strict().superRefine(refineSmtpNoneRejectsCredentials);
15623
+ UpdateEmailServerRequestSchema = union([
15624
+ UpdateResendEmailServerRequestSchema,
15625
+ UpdateSmtpEmailServerRequestSchema,
15626
+ UpdateMetadataOnlySchema
15627
+ ]).meta({ id: "UpdateEmailServerRequest" });
15628
+ PublicEmailServerTimestamps = {
15629
+ id: EmailServerIdSchema,
15630
+ name: EmailServerNameSchema,
15631
+ enabled: boolean2(),
15632
+ createdAt: union([string2(), exports_coerce.date()]),
15633
+ updatedAt: union([string2(), exports_coerce.date()])
15634
+ };
15635
+ PublicResendEmailServerSchema = object({
15636
+ ...PublicEmailServerTimestamps,
15637
+ transport: literal("resend"),
15638
+ fromEmail: EmailServerFromEmailSchema,
15639
+ fromName: EmailServerFromNameSchema,
15640
+ apiKeyConfigured: literal(true)
15641
+ }).strict().meta({ id: "PublicResendEmailServer" });
15642
+ PublicSmtpEmailServerSchema = object({
15643
+ ...PublicEmailServerTimestamps,
15644
+ transport: literal("smtp"),
15645
+ fromEmail: EmailServerFromEmailSchema,
15646
+ fromName: EmailServerFromNameSchema,
15647
+ host: SmtpHostSchema,
15648
+ port: SmtpPortSchema,
15649
+ security: SmtpSecuritySchema,
15650
+ username: string2().nullable(),
15651
+ passwordConfigured: boolean2(),
15652
+ caPemConfigured: boolean2()
15653
+ }).strict().meta({ id: "PublicSmtpEmailServer" });
15654
+ EmailServerSchema = discriminatedUnion("transport", [PublicResendEmailServerSchema, PublicSmtpEmailServerSchema]).meta({ id: "EmailServer" });
15655
+ ListEmailServersResponseSchema = object({
15656
+ data: array(EmailServerSchema),
15657
+ total: number2().int(),
15658
+ limit: number2().int(),
15659
+ offset: number2().int()
15660
+ }).meta({ id: "ListEmailServersResponse" });
15661
+ DeleteEmailServerResponseSchema = object({
15662
+ deleted: literal(true),
15663
+ id: EmailServerIdSchema
15664
+ }).strict().meta({ id: "DeleteEmailServerResponse" });
15665
+ TestEmailServerRequestSchema = object({
15666
+ to: EmailServerFromEmailSchema
15667
+ }).strict().meta({ id: "TestEmailServerRequest" });
15668
+ TestEmailServerResponseSchema = discriminatedUnion("ok", [
15669
+ object({
15670
+ ok: literal(true),
15671
+ transport: _enum(EMAIL_SERVER_TRANSPORTS),
15672
+ messageId: string2().min(1)
15673
+ }).strict(),
15674
+ object({
15675
+ ok: literal(false),
15676
+ error: string2().min(1)
15677
+ }).strict()
15678
+ ]).meta({ id: "TestEmailServerResponse" });
15679
+ });
15680
+
15432
15681
  // ../../node_modules/@babel/parser/lib/index.js
15433
15682
  var require_lib = __commonJS(function(exports) {
15434
15683
  Object.defineProperty(exports, "__esModule", {
@@ -52892,6 +53141,61 @@ var init_typed_script = __esm(() => {
52892
53141
  init_compile();
52893
53142
  });
52894
53143
 
53144
+ // ../types/src/workflow/email-recipients.ts
53145
+ function splitRecipientTokens(value) {
53146
+ const tokens = [];
53147
+ let start = 0;
53148
+ let templateClose;
53149
+ for (let index = 0;index < value.length; index++) {
53150
+ if (templateClose) {
53151
+ if (value.startsWith(templateClose, index)) {
53152
+ index++;
53153
+ templateClose = undefined;
53154
+ }
53155
+ continue;
53156
+ }
53157
+ if (value.startsWith("{{", index)) {
53158
+ templateClose = "}}";
53159
+ index++;
53160
+ continue;
53161
+ }
53162
+ if (value.startsWith("{%", index)) {
53163
+ templateClose = "%}";
53164
+ index++;
53165
+ continue;
53166
+ }
53167
+ if (value[index] === ",") {
53168
+ tokens.push(value.slice(start, index));
53169
+ start = index + 1;
53170
+ }
53171
+ }
53172
+ tokens.push(value.slice(start));
53173
+ return tokens;
53174
+ }
53175
+ function countDeterministicEmailRecipients(value) {
53176
+ if (value === undefined || value === null)
53177
+ return 0;
53178
+ const parts = Array.isArray(value) ? value : [value];
53179
+ let count = 0;
53180
+ for (const part of parts) {
53181
+ if (typeof part !== "string")
53182
+ continue;
53183
+ const tokens = splitRecipientTokens(part).map((token) => token.trim()).filter((token) => token.length > 0);
53184
+ count += tokens.length;
53185
+ }
53186
+ return count;
53187
+ }
53188
+ function countActionEmailRecipients(fields) {
53189
+ return countDeterministicEmailRecipients(fields.to) + countDeterministicEmailRecipients(fields.cc) + countDeterministicEmailRecipients(fields.bcc);
53190
+ }
53191
+ function actionEmailRecipientCountExceedsLimit(fields) {
53192
+ return countActionEmailRecipients(fields) > ACTION_EMAIL_MAX_RECIPIENTS;
53193
+ }
53194
+ var ACTION_EMAIL_MAX_RECIPIENTS = 10, ACTION_EMAIL_RECIPIENT_LIMIT_MESSAGE;
53195
+ var init_email_recipients = __esm(() => {
53196
+ ACTION_EMAIL_RECIPIENT_LIMIT_MESSAGE = `At most ${ACTION_EMAIL_MAX_RECIPIENTS} recipients combined across to, cc, and bcc`;
53197
+ });
53198
+
52895
53199
  // ../types/src/workflow/script-function.ts
52896
53200
  var SCRIPT_FN_MAX_BYTES = 50000;
52897
53201
 
@@ -52998,7 +53302,8 @@ var init_steps = __esm(() => {
52998
53302
  ACTION_STEP_TYPES = [
52999
53303
  "action.http",
53000
53304
  "action.invoke-workflow",
53001
- "action.website-reader"
53305
+ "action.website-reader",
53306
+ "action.email"
53002
53307
  ];
53003
53308
  CONTROL_STEP_TYPES = [
53004
53309
  "control.if",
@@ -53128,17 +53433,19 @@ function getStepSchema(stepType) {
53128
53433
  function listStepTypes() {
53129
53434
  return [...STEP_TYPES];
53130
53435
  }
53131
- var OptionalReasoningEffortSchema, AiParseConfigSchema, AiParseOutputSchema, AiExtractConfigSchema, AiExtractOutputSchema, VisionPageRangeSchema, AiVisionConfigSchema, AiVisionOutputSchema, AiSplitConfigSchema, AiSplitSectionSchema, AiSplitOutputSchema, AiSegmentConfigSchema, AiSegmentOutputSchema, AiClassifyConfigSchema, AiClassifyOutputSchema, ClassifyPagesLabelSchema2, AiClassifyPagesConfigSchema, AiClassifyPagesOutputSchema, TransformSetConfigSchema, TransformSetOutputSchema, TransformRemoveConfigSchema, TransformRemoveOutputSchema, TransformCombineConfigSchema, TransformCombineOutputSchema, TransformSplitConfigSchema, TransformSplitOutputSchema, TransformMergeConfigSchema, TransformMergeOutputSchema, TransformTemplateConfigSchema, TransformTemplateOutputSchema, TransformPdfEmbedConfigSchema, TransformPdfEmbedOutputSchema, TransformXlsxToJsonConfigSchema, TransformXlsxToJsonOutputSchema, JsonToXlsxAuthoringRowsSchema, JsonToXlsxSheetConfigSchema, TransformJsonToXlsxConfigSchema, TransformJsonToXlsxOutputSchema, TransformScriptConfigSchema, TransformScriptOutputSchema, ParsedDocPageSchema, TransformTextChunkerConfigSchema, TransformTextChunkerOutputSchema, RegexNormalizerSchema, RegexFormatSchema, REGEX_FLAGS, RegexFieldSchema, TransformRegexExtractConfigSchema, TransformRegexExtractOutputSchema, ActionHttpConfigSchema, ActionHttpOutputSchema, ActionInvokeWorkflowConfigSchema, ActionInvokeWorkflowOutputSchema, ActionWebsiteReaderConfigSchema, ActionWebsiteReaderOutputSchema, ControlIfConfigSchema, ControlIfOutputSchema, ControlSwitchConfigSchema, ControlSwitchOutputSchema, ControlForeachConfigSchema, ControlForeachOutputSchema, ControlParallelMapConfigSchema, ControlParallelMapOutputSchema, ControlParallelConfigSchema, ControlParallelOutputSchema, ControlWaitConfigSchema, ControlWaitOutputSchema, ControlFailConfigSchema, ControlFailOutputSchema, STEP_SCHEMAS;
53436
+ var OptionalReasoningEffortSchema, AiParseConfigSchema, AiParseOutputSchema, AiExtractConfigSchema, AiExtractOutputSchema, VisionPageRangeSchema, AiVisionConfigSchema, AiVisionOutputSchema, AiSplitConfigSchema, AiSplitSectionSchema, AiSplitOutputSchema, AiSegmentConfigSchema, AiSegmentOutputSchema, AiClassifyConfigSchema, AiClassifyOutputSchema, ClassifyPagesLabelSchema2, AiClassifyPagesConfigSchema, AiClassifyPagesOutputSchema, TransformSetConfigSchema, TransformSetOutputSchema, TransformRemoveConfigSchema, TransformRemoveOutputSchema, TransformCombineConfigSchema, TransformCombineOutputSchema, TransformSplitConfigSchema, TransformSplitOutputSchema, TransformMergeConfigSchema, TransformMergeOutputSchema, TransformTemplateConfigSchema, TransformTemplateOutputSchema, TransformPdfEmbedConfigSchema, TransformPdfEmbedOutputSchema, TransformXlsxToJsonConfigSchema, TransformXlsxToJsonOutputSchema, JsonToXlsxAuthoringRowsSchema, JsonToXlsxSheetConfigSchema, TransformJsonToXlsxConfigSchema, TransformJsonToXlsxOutputSchema, TransformScriptConfigSchema, TransformScriptOutputSchema, ParsedDocPageSchema, TransformTextChunkerConfigSchema, TransformTextChunkerOutputSchema, RegexNormalizerSchema, RegexFormatSchema, REGEX_FLAGS, RegexFieldSchema, TransformRegexExtractConfigSchema, TransformRegexExtractOutputSchema, ActionHttpConfigSchema, ActionHttpOutputSchema, ActionInvokeWorkflowConfigSchema, ActionInvokeWorkflowOutputSchema, ActionWebsiteReaderConfigSchema, ActionWebsiteReaderOutputSchema, ACTION_EMAIL_MAX_ATTACHMENTS = 10, ACTION_EMAIL_MAX_ATTACHMENT_BYTES, ACTION_EMAIL_BODY_MAX_BYTES, emailBodyMaxBytes = (value) => new TextEncoder().encode(value).byteLength <= ACTION_EMAIL_BODY_MAX_BYTES, ActionEmailRecipientListSchema, ActionEmailToSchema, ActionEmailOptionalRecipientsSchema, ActionEmailAttachmentSchema, ActionEmailConfigSchema, ActionEmailOutputSchema, ControlIfConfigSchema, ControlIfOutputSchema, ControlSwitchConfigSchema, ControlSwitchOutputSchema, ControlForeachConfigSchema, ControlForeachOutputSchema, ControlParallelMapConfigSchema, ControlParallelMapOutputSchema, ControlParallelConfigSchema, ControlParallelOutputSchema, ControlWaitConfigSchema, ControlWaitOutputSchema, ControlFailConfigSchema, ControlFailOutputSchema, STEP_SCHEMAS;
53132
53437
  var init_step_configs = __esm(() => {
53133
53438
  init_zod();
53134
53439
  init_ai_client();
53135
53440
  init_common();
53441
+ init_email_servers();
53136
53442
  init_parser();
53137
53443
  init_json_to_xlsx();
53138
53444
  init_xlsx_to_json();
53139
53445
  init_typed_script();
53446
+ init_email_recipients();
53140
53447
  init_steps();
53141
- OptionalReasoningEffortSchema = ReasoningEffortSchema.optional().describe("Reasoning effort for models that support it. Omit to preserve the current provider default.");
53448
+ OptionalReasoningEffortSchema = ReasoningEffortSchema.optional().describe("Reasoning effort for models that support it. Omit to use the selected model's default.");
53142
53449
  AiParseConfigSchema = object({
53143
53450
  input: string2().describe("Storage reference or template expression for the document"),
53144
53451
  parseMode: ParseModeSchema.optional().describe('Base parser for PDF/image inputs. OCR is the default; vision uses the selected LLM. `native` extracts PDF embedded text only and never calls OCR or vision. `native-or-ocr` extracts native text, runs page-quality diagnostics, and requests OCR when pages have detectable anomalies (empty, U+FFFD, lone surrogates, forbidden controls, unassigned/noncharacter, heavy PUA). Page selection, subset egress, and billing are provider-dependent. Valid-looking wrong text and literal "?" are not flagged. Text and Office files always use local parsing.'),
@@ -53661,6 +53968,54 @@ var init_step_configs = __esm(() => {
53661
53968
  length: number2().describe("Content length in characters"),
53662
53969
  url: string2().describe("Final URL after redirects")
53663
53970
  });
53971
+ ACTION_EMAIL_MAX_ATTACHMENT_BYTES = 12 * 1024 * 1024;
53972
+ ACTION_EMAIL_BODY_MAX_BYTES = 50 * 1024;
53973
+ ActionEmailRecipientListSchema = array(string2().min(1));
53974
+ ActionEmailToSchema = union([
53975
+ string2().min(1, "To is required"),
53976
+ ActionEmailRecipientListSchema.min(1, "To requires at least one recipient")
53977
+ ]);
53978
+ ActionEmailOptionalRecipientsSchema = union([
53979
+ string2().min(1),
53980
+ ActionEmailRecipientListSchema
53981
+ ]);
53982
+ ActionEmailAttachmentSchema = union([
53983
+ string2().min(1).describe("File id or template expression that resolves to a file id"),
53984
+ object({
53985
+ fileId: string2().min(1).describe("File id or template expression that resolves to a file id"),
53986
+ filename: string2().min(1).optional().describe("Optional download filename override")
53987
+ })
53988
+ ]);
53989
+ ActionEmailConfigSchema = object({
53990
+ server: EmailServerIdSchema.describe("Outbound email server id (`ems_…`)"),
53991
+ to: ActionEmailToSchema.describe("Primary recipient(s). String, comma-separated list, or nonempty string array. Combined with cc and bcc, at most 10 recipients."),
53992
+ cc: ActionEmailOptionalRecipientsSchema.optional().describe("Carbon-copy recipient(s). String, comma-separated list, or string array. Combined with to and bcc, at most 10 recipients."),
53993
+ bcc: ActionEmailOptionalRecipientsSchema.optional().describe("Blind carbon-copy recipient(s). String, comma-separated list, or string array. Combined with to and cc, at most 10 recipients."),
53994
+ replyTo: string2().min(1).optional().describe("Reply-To address (supports template expressions)"),
53995
+ subject: string2().min(1, "Subject is required").describe("Email subject"),
53996
+ text: string2().min(1, "Body is required").refine(emailBodyMaxBytes, {
53997
+ message: `Email body must be at most ${ACTION_EMAIL_BODY_MAX_BYTES} bytes`
53998
+ }).describe("Plain-text email body (max 50KiB)"),
53999
+ attachments: array(ActionEmailAttachmentSchema).max(ACTION_EMAIL_MAX_ATTACHMENTS, `At most ${ACTION_EMAIL_MAX_ATTACHMENTS} attachments`).optional().describe("Optional same-run attachments as { fileId, filename? } or a bare fileId string (12MiB combined)")
54000
+ }).superRefine((config, ctx) => {
54001
+ if (actionEmailRecipientCountExceedsLimit(config)) {
54002
+ ctx.addIssue({
54003
+ code: "custom",
54004
+ message: ACTION_EMAIL_RECIPIENT_LIMIT_MESSAGE,
54005
+ path: ["to"]
54006
+ });
54007
+ }
54008
+ });
54009
+ ActionEmailOutputSchema = object({
54010
+ serverId: EmailServerIdSchema.describe("Email server that sent (or would have sent) the message"),
54011
+ messageId: string2().nullable().describe("Provider message id. Null when delivery was skipped (evaluation runs)."),
54012
+ provider: _enum(["resend", "smtp"]).nullable().describe("Email provider that sent the message. Null when delivery was skipped."),
54013
+ to: array(string2()).describe("Normalized To recipients"),
54014
+ cc: array(string2()).describe("Normalized Cc recipients"),
54015
+ bcc: array(string2()).describe("Normalized Bcc recipients"),
54016
+ attachmentCount: number2().int().nonnegative().describe("Number of attachments sent"),
54017
+ totalBytes: number2().int().nonnegative().describe("Total attachment size in bytes")
54018
+ });
53664
54019
  ControlIfConfigSchema = object({
53665
54020
  condition: string2().min(1, "Condition is required").describe("LiquidJS expression that evaluates to boolean")
53666
54021
  });
@@ -53914,6 +54269,15 @@ var init_step_configs = __esm(() => {
53914
54269
  outputSchema: ActionWebsiteReaderOutputSchema,
53915
54270
  configInWith: true
53916
54271
  },
54272
+ "action.email": {
54273
+ type: "action.email",
54274
+ category: "action",
54275
+ name: "Send Email",
54276
+ description: "Send an email with optional attachments via a selected email server. At most 10 recipients combined across to, cc, and bcc.",
54277
+ configSchema: ActionEmailConfigSchema,
54278
+ outputSchema: ActionEmailOutputSchema,
54279
+ configInWith: true
54280
+ },
53917
54281
  "control.if": {
53918
54282
  type: "control.if",
53919
54283
  category: "control",
@@ -54455,7 +54819,7 @@ var init_evaluator_config = __esm(() => {
54455
54819
  LabelsRecord = record(string2().min(1), ScoreInUnitInterval);
54456
54820
  LlmJudgeConfigSchema = object({
54457
54821
  model: string2().min(1).optional().describe("Which LLM grades the output. Falls back to the workspace's default LLM provider when unset."),
54458
- reasoningEffort: ReasoningEffortSchema.optional().describe("Reasoning effort for models that support it. Omit to preserve the current provider default."),
54822
+ reasoningEffort: ReasoningEffortSchema.optional().describe("Reasoning effort for models that support it. Omit to use the selected model's default."),
54459
54823
  mode: JudgeModeSchema.default("continuous").describe("Continuous = the LLM returns a free-form score in [0, 1]. Discrete = the LLM picks one of your labels and the score is looked up from the table."),
54460
54824
  labels: LabelsRecord.optional().describe("Allowed labels and the score each maps to. Required in discrete mode. The judge MUST return one of these labels; each score must be in [0, 1]."),
54461
54825
  passThreshold: ScoreInUnitInterval.optional().describe(LEGACY_EVALUATOR_THRESHOLD_DESCRIPTION),
@@ -55423,6 +55787,7 @@ var init_src = __esm(() => {
55423
55787
  init_eval();
55424
55788
  init_git_source();
55425
55789
  init_triggers();
55790
+ init_email_servers();
55426
55791
  init_webhooks();
55427
55792
  init_typed_script();
55428
55793
  });
@@ -205368,7 +205733,7 @@ import { fileURLToPath as fileURLToPath8 } from "url";
205368
205733
  // package.json
205369
205734
  var package_default = {
205370
205735
  name: "@eigenpal/cli",
205371
- version: "0.15.1",
205736
+ version: "0.16.1",
205372
205737
  description: "Eigenpal CLI — author and run document workflows from your terminal. Agent-ready.",
205373
205738
  keywords: [
205374
205739
  "eigenpal",
@@ -205425,7 +205790,7 @@ var package_default = {
205425
205790
  "@clack/prompts": "^1.3.0",
205426
205791
  ajv: "^8.17.1",
205427
205792
  commander: "^14.0.3",
205428
- fflate: "0.8.2",
205793
+ fflate: "0.8.3",
205429
205794
  picocolors: "^1.1.1",
205430
205795
  yaml: "^2.7.0",
205431
205796
  xlsx: "https://cdn.sheetjs.com/xlsx-0.20.3/xlsx-0.20.3.tgz",
@@ -208137,9 +208502,11 @@ function registerGitCommands(program) {
208137
208502
  // ../../node_modules/fflate/esm/index.mjs
208138
208503
  import { createRequire as createRequire2 } from "module";
208139
208504
  var require2 = createRequire2("/");
208505
+ var _a3;
208140
208506
  var Worker;
208507
+ var isMarkedAsUntransferable;
208141
208508
  try {
208142
- Worker = require2("worker_threads").Worker;
208509
+ _a3 = require2("worker_threads"), Worker = _a3.Worker, isMarkedAsUntransferable = _a3.isMarkedAsUntransferable;
208143
208510
  } catch (e) {}
208144
208511
  var u8 = Uint8Array;
208145
208512
  var u16 = Uint16Array;
@@ -208625,7 +208992,7 @@ var fltn = function(d, p, t, o) {
208625
208992
  var val2 = d[k], n = p + k, op = o;
208626
208993
  if (Array.isArray(val2))
208627
208994
  op = mrg(o, val2[1]), val2 = val2[0];
208628
- if (val2 instanceof u8)
208995
+ if (ArrayBuffer.isView(val2))
208629
208996
  t[n] = [val2, op];
208630
208997
  else {
208631
208998
  t[n += "/"] = [new u8(0), op];
@@ -240643,18 +241010,471 @@ function matchingSnippet(content, terms) {
240643
241010
  return line.replace(/^[#>*\s-]+/, "").replace(/[`[\]{}]/g, "").trim().slice(0, 140);
240644
241011
  }
240645
241012
 
241013
+ // src/lib/api-paths.ts
241014
+ var API_PREFIX = "/v1";
241015
+ function apiPath(suffix) {
241016
+ if (suffix === "/v1" || suffix.startsWith("/v1/"))
241017
+ return suffix;
241018
+ if (suffix === "/api/v1" || suffix.startsWith("/api/v1/")) {
241019
+ return `${API_PREFIX}${suffix.slice("/api/v1".length)}`;
241020
+ }
241021
+ const normalized = suffix.startsWith("/") ? suffix : `/${suffix}`;
241022
+ return `${API_PREFIX}${normalized}`;
241023
+ }
241024
+
241025
+ // src/lib/email-servers-cli.ts
241026
+ init_src();
241027
+ import { existsSync as existsSync14, readFileSync as readFileSync14 } from "node:fs";
241028
+ import { resolve as resolve4 } from "node:path";
241029
+ var SECRET_KEYS = new Set(["apiKey", "password", "caPem", "ciphertext"]);
241030
+ var SMTP_UPDATE_TARGET_FIELDS = ["host", "port", "security", "fromEmail", "fromName"];
241031
+ var SMTP_UPDATE_FLAG_BY_FIELD = {
241032
+ host: "--host",
241033
+ port: "--port",
241034
+ security: "--security",
241035
+ fromEmail: "--from-email",
241036
+ fromName: "--from-name"
241037
+ };
241038
+ function assertCompleteSmtpUpdateTarget(body) {
241039
+ if (body.transport !== "smtp")
241040
+ return;
241041
+ const missing = SMTP_UPDATE_TARGET_FIELDS.filter((field) => body[field] === undefined || body[field] === "");
241042
+ if (missing.length === 0)
241043
+ return;
241044
+ const flags = missing.map((field) => SMTP_UPDATE_FLAG_BY_FIELD[field]).join(", ");
241045
+ throw new Error(`SMTP updates that set --transport smtp require a complete target (host, port, security, from-email, from-name). Missing: ${flags}. Update does not default --security/--port (create still defaults to starttls and the matching port). Metadata-only updates omit --transport.`);
241046
+ }
241047
+ function countTruthy(values) {
241048
+ return values.filter(Boolean).length;
241049
+ }
241050
+ function assertExclusiveConfigSource(explicitFieldCount, opts, command) {
241051
+ const configSources = countTruthy([opts.configJson, opts.configFile]);
241052
+ if (configSources > 1) {
241053
+ throw new Error("Pass only one of --config-json or --config-file.");
241054
+ }
241055
+ if (configSources > 0 && explicitFieldCount > 0) {
241056
+ throw new Error(`${command} accepts either explicit flags or --config-json/--config-file, not both.`);
241057
+ }
241058
+ if (configSources === 0 && explicitFieldCount === 0 && command === "create") {
241059
+ throw new Error("create requires explicit fields or --config-json/--config-file (plus secret input for Resend or authenticated SMTP).");
241060
+ }
241061
+ }
241062
+ function readConfigObject(opts) {
241063
+ if (opts.configJson) {
241064
+ let parsed;
241065
+ try {
241066
+ parsed = JSON.parse(opts.configJson);
241067
+ } catch {
241068
+ throw new Error("--config-json must be valid JSON.");
241069
+ }
241070
+ if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
241071
+ throw new Error("--config-json must be a JSON object.");
241072
+ }
241073
+ return parsed;
241074
+ }
241075
+ if (opts.configFile) {
241076
+ const filePath = opts.configFile === "-" ? undefined : resolve4(opts.configFile);
241077
+ let raw;
241078
+ try {
241079
+ raw = opts.configFile === "-" ? readFileSync14(0, "utf8") : readFileSync14(filePath, "utf8");
241080
+ } catch (err) {
241081
+ const code = err && typeof err === "object" && "code" in err ? String(err.code) : "";
241082
+ if (code === "ENOENT") {
241083
+ throw new Error(`Config file not found: ${resolve4(opts.configFile)}`);
241084
+ }
241085
+ throw err;
241086
+ }
241087
+ let parsed;
241088
+ try {
241089
+ parsed = JSON.parse(raw);
241090
+ } catch {
241091
+ throw new Error("--config-file must contain a JSON object.");
241092
+ }
241093
+ if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
241094
+ throw new Error("--config-file must contain a JSON object.");
241095
+ }
241096
+ return parsed;
241097
+ }
241098
+ return {};
241099
+ }
241100
+ function rejectInlineSecrets(body) {
241101
+ for (const key of SECRET_KEYS) {
241102
+ if (key in body && body[key] != null) {
241103
+ throw new Error(`Secret field "${key}" cannot be set in --config-json/--config-file. Use the matching *-stdin or *-file flag, or answer the secure prompt.`);
241104
+ }
241105
+ }
241106
+ }
241107
+ async function readSecretInput2(label, opts, required) {
241108
+ const selected = countTruthy([opts.stdin, opts.file]);
241109
+ if (selected > 1) {
241110
+ throw new Error(`Pass only one of --${label}-stdin or --${label}-file.`);
241111
+ }
241112
+ if (opts.stdin) {
241113
+ return readFileSync14(0, "utf8").replace(/\n$/, "");
241114
+ }
241115
+ if (opts.file) {
241116
+ const filePath = opts.file === "-" ? undefined : resolve4(opts.file);
241117
+ try {
241118
+ return (opts.file === "-" ? readFileSync14(0, "utf8") : readFileSync14(filePath, "utf8")).replace(/\n$/, "");
241119
+ } catch (err) {
241120
+ const code = err && typeof err === "object" && "code" in err ? String(err.code) : "";
241121
+ if (code === "ENOENT") {
241122
+ throw new Error(`Secret file not found: ${resolve4(opts.file)}`);
241123
+ }
241124
+ throw err;
241125
+ }
241126
+ }
241127
+ if (!required)
241128
+ return;
241129
+ if (process.stdin.isTTY && process.stdout.isTTY) {
241130
+ await Promise.resolve().then(() => init_dist4());
241131
+ const answer = await Ce({ message: `${label} (input hidden)` });
241132
+ if (q(answer)) {
241133
+ me("Cancelled");
241134
+ process.exit(1);
241135
+ }
241136
+ return String(answer);
241137
+ }
241138
+ throw new Error(`${label} is required in noninteractive mode (use --${label}-stdin or --${label}-file).`);
241139
+ }
241140
+ function parseEnabled(opts) {
241141
+ if (opts.enabled && opts.disabled) {
241142
+ throw new Error("Pass only one of --enabled or --disabled.");
241143
+ }
241144
+ if (opts.disabled)
241145
+ return false;
241146
+ if (opts.enabled)
241147
+ return true;
241148
+ return;
241149
+ }
241150
+ async function buildCreateRequest(opts) {
241151
+ const explicitCount = countTruthy([
241152
+ opts.name,
241153
+ opts.transport,
241154
+ opts.fromEmail,
241155
+ opts.fromName,
241156
+ opts.enabled,
241157
+ opts.disabled,
241158
+ opts.host,
241159
+ opts.port,
241160
+ opts.security,
241161
+ opts.username
241162
+ ]);
241163
+ assertExclusiveConfigSource(explicitCount, opts, "create");
241164
+ const body = {};
241165
+ if (countTruthy([opts.configJson, opts.configFile]) > 0) {
241166
+ Object.assign(body, readConfigObject(opts));
241167
+ rejectInlineSecrets(body);
241168
+ }
241169
+ if (opts.name !== undefined)
241170
+ body.name = opts.name;
241171
+ if (opts.transport !== undefined)
241172
+ body.transport = opts.transport;
241173
+ if (opts.fromEmail !== undefined)
241174
+ body.fromEmail = opts.fromEmail;
241175
+ if (opts.fromName !== undefined)
241176
+ body.fromName = opts.fromName;
241177
+ const enabled = parseEnabled(opts);
241178
+ if (enabled !== undefined)
241179
+ body.enabled = enabled;
241180
+ if (opts.host !== undefined)
241181
+ body.host = opts.host;
241182
+ if (opts.port !== undefined)
241183
+ body.port = opts.port;
241184
+ if (opts.security !== undefined)
241185
+ body.security = opts.security;
241186
+ if (opts.username !== undefined)
241187
+ body.username = opts.username;
241188
+ const apiKey = await readSecretInput2("api-key", { stdin: opts.apiKeyStdin, file: opts.apiKeyFile }, false);
241189
+ if (apiKey !== undefined)
241190
+ body.apiKey = apiKey;
241191
+ const password = await readSecretInput2("password", { stdin: opts.passwordStdin, file: opts.passwordFile }, false);
241192
+ if (password !== undefined)
241193
+ body.password = password;
241194
+ const caPem = await readSecretInput2("ca-pem", { stdin: opts.caPemStdin, file: opts.caPemFile }, false);
241195
+ if (caPem !== undefined)
241196
+ body.caPem = caPem;
241197
+ const transport = body.transport;
241198
+ if (transport === "resend" && body.apiKey === undefined) {
241199
+ body.apiKey = await readSecretInput2("api-key", { stdin: opts.apiKeyStdin, file: opts.apiKeyFile }, true);
241200
+ }
241201
+ if (body.transport === "smtp" && typeof body.username === "string" && body.username.length > 0 && body.password === undefined) {
241202
+ body.password = await readSecretInput2("password", { stdin: opts.passwordStdin, file: opts.passwordFile }, true);
241203
+ }
241204
+ return CreateEmailServerRequestSchema.parse(body);
241205
+ }
241206
+ async function buildUpdateRequest(input) {
241207
+ const { existing, opts } = input;
241208
+ const explicitCount = countTruthy([
241209
+ opts.name,
241210
+ opts.transport,
241211
+ opts.fromEmail,
241212
+ opts.fromName,
241213
+ opts.enabled,
241214
+ opts.disabled,
241215
+ opts.host,
241216
+ opts.port,
241217
+ opts.security,
241218
+ opts.username,
241219
+ opts.clearCaPem,
241220
+ opts.clearUsername
241221
+ ]);
241222
+ assertExclusiveConfigSource(explicitCount, opts, "update");
241223
+ const body = {};
241224
+ if (countTruthy([opts.configJson, opts.configFile]) > 0) {
241225
+ Object.assign(body, readConfigObject(opts));
241226
+ rejectInlineSecrets(body);
241227
+ }
241228
+ if (opts.name !== undefined)
241229
+ body.name = opts.name;
241230
+ const enabled = parseEnabled(opts);
241231
+ if (enabled !== undefined)
241232
+ body.enabled = enabled;
241233
+ if (opts.transport !== undefined)
241234
+ body.transport = opts.transport;
241235
+ if (opts.fromEmail !== undefined)
241236
+ body.fromEmail = opts.fromEmail;
241237
+ if (opts.fromName !== undefined)
241238
+ body.fromName = opts.fromName;
241239
+ if (opts.host !== undefined)
241240
+ body.host = opts.host;
241241
+ if (opts.port !== undefined)
241242
+ body.port = opts.port;
241243
+ if (opts.security !== undefined)
241244
+ body.security = opts.security;
241245
+ if (opts.clearUsername)
241246
+ body.username = null;
241247
+ else if (opts.username !== undefined)
241248
+ body.username = opts.username;
241249
+ if (opts.clearCaPem)
241250
+ body.caPem = null;
241251
+ const apiKey = await readSecretInput2("api-key", { stdin: opts.apiKeyStdin, file: opts.apiKeyFile }, false);
241252
+ if (apiKey !== undefined)
241253
+ body.apiKey = apiKey;
241254
+ const password = await readSecretInput2("password", { stdin: opts.passwordStdin, file: opts.passwordFile }, false);
241255
+ if (password !== undefined)
241256
+ body.password = password;
241257
+ const caPem = await readSecretInput2("ca-pem", { stdin: opts.caPemStdin, file: opts.caPemFile }, false);
241258
+ if (caPem !== undefined)
241259
+ body.caPem = caPem;
241260
+ if (Object.keys(body).length === 0) {
241261
+ throw new Error("No changes requested. Pass fields to update or --config-json/--config-file.");
241262
+ }
241263
+ assertCompleteSmtpUpdateTarget(body);
241264
+ if (body.transport === "resend" && existing.transport !== "resend" && body.apiKey === undefined) {
241265
+ body.apiKey = await readSecretInput2("api-key", { stdin: opts.apiKeyStdin, file: opts.apiKeyFile }, true);
241266
+ }
241267
+ if (body.transport === "smtp" && body.password === undefined) {
241268
+ const targetUsername = body.username === null ? null : typeof body.username === "string" ? body.username : existing.username ?? null;
241269
+ const destinationChanged = existing.transport !== "smtp" || typeof body.host === "string" && existing.host !== undefined && body.host !== existing.host || targetUsername !== (existing.username ?? null);
241270
+ if (destinationChanged && targetUsername) {
241271
+ body.password = await readSecretInput2("password", { stdin: opts.passwordStdin, file: opts.passwordFile }, true);
241272
+ }
241273
+ }
241274
+ const patch = UpdateEmailServerRequestSchema.parse(body);
241275
+ const transportError = getEmailServerUpdateError(existing.transport, patch, {
241276
+ host: existing.host,
241277
+ username: existing.username,
241278
+ passwordConfigured: existing.passwordConfigured
241279
+ });
241280
+ if (transportError)
241281
+ throw new Error(transportError);
241282
+ return patch;
241283
+ }
241284
+ function redactValue(key, value) {
241285
+ if (SECRET_KEYS.has(key))
241286
+ return "[redacted]";
241287
+ if (value && typeof value === "object") {
241288
+ if (Array.isArray(value))
241289
+ return value.map((item) => redactUnknown(item));
241290
+ return redactUnknown(value);
241291
+ }
241292
+ return value;
241293
+ }
241294
+ function redactUnknown(value) {
241295
+ if (value == null || typeof value !== "object")
241296
+ return value;
241297
+ if (Array.isArray(value))
241298
+ return value.map((item) => redactUnknown(item));
241299
+ const out = {};
241300
+ for (const [key, nested] of Object.entries(value)) {
241301
+ out[key] = redactValue(key, nested);
241302
+ }
241303
+ return out;
241304
+ }
241305
+ function redactEmailServerPayload(value) {
241306
+ return redactUnknown(value);
241307
+ }
241308
+ function formatEmailServerHuman(server) {
241309
+ const lines = [];
241310
+ lines.push(`${server.id} ${server.name}${server.enabled ? "" : " (disabled)"}`);
241311
+ lines.push(` transport ${server.transport}`);
241312
+ lines.push(` from ${server.fromName} <${server.fromEmail}>`);
241313
+ if (server.transport === "resend") {
241314
+ lines.push(` api key configured`);
241315
+ } else {
241316
+ lines.push(` host ${server.host}:${server.port} (${server.security})`);
241317
+ lines.push(` username ${server.username ?? "-"}`);
241318
+ lines.push(` password ${server.passwordConfigured ? "configured" : "not configured"}`);
241319
+ lines.push(` ca pem ${server.caPemConfigured ? "configured" : "not configured"}`);
241320
+ }
241321
+ lines.push(` updated ${server.updatedAt instanceof Date ? server.updatedAt.toISOString() : server.updatedAt}`);
241322
+ return lines.join(`
241323
+ `);
241324
+ }
241325
+
241326
+ // src/commands/email-servers.ts
241327
+ var LIST_COLUMNS = [
241328
+ { key: "id", header: "id" },
241329
+ { key: "name", header: "name" },
241330
+ { key: "transport", header: "transport" },
241331
+ {
241332
+ key: "enabled",
241333
+ header: "enabled",
241334
+ format: (value) => value ? "yes" : "no"
241335
+ },
241336
+ { key: "fromEmail", header: "from" },
241337
+ {
241338
+ key: "host",
241339
+ header: "host",
241340
+ format: (_value, row) => row.transport === "smtp" ? String(row.host) : "-"
241341
+ },
241342
+ {
241343
+ key: "updatedAt",
241344
+ header: "updated",
241345
+ format: (value) => formatTimestamp(value)
241346
+ }
241347
+ ];
241348
+ function buildClient2(opts) {
241349
+ const config = resolveConfig(opts);
241350
+ requireApiKey(config);
241351
+ return new ApiClient(config);
241352
+ }
241353
+ function printJson2(value) {
241354
+ console.log(JSON.stringify(value, null, 2));
241355
+ }
241356
+ function sharedCreateOptions(cmd) {
241357
+ return cmd.option("--config-json <json>", "JSON object (non-secret fields only; use secret *-stdin/*-file flags)").option("--config-file <path>", "JSON file path (`-` reads stdin; non-secret fields only)").option("--name <name>", "Display name").option("--transport <kind>", "Transport: resend or smtp").option("--from-email <email>", "From address").option("--from-name <name>", "From display name (no control characters or <>)").option("--enabled", "Enable the server (default on create)").option("--disabled", "Disable the server").option("--host <host>", "SMTP host (required on update when --transport smtp)").option("--port <n>", "SMTP port. Required on update when --transport smtp; create defaults from --security", intArg).option("--security <mode>", "SMTP security: starttls, tls, or none (unauthenticated trusted relays; credentials are rejected). Required on update when --transport smtp; create defaults to starttls").option("--username <user>", "SMTP username (non-secret)").option("--api-key-stdin", "Read the Resend API key from stdin").option("--api-key-file <path>", "Read the Resend API key from a file (`-` for stdin)").option("--password-stdin", "Read the SMTP password from stdin").option("--password-file <path>", "Read the SMTP password from a file (`-` for stdin)").option("--ca-pem-stdin", "Read a custom SMTP CA PEM from stdin").option("--ca-pem-file <path>", "Read a custom SMTP CA PEM from a file (`-` for stdin)");
241358
+ }
241359
+ function sharedUpdateOptions(cmd) {
241360
+ return sharedCreateOptions(cmd).option("--clear-ca-pem", "Remove a stored custom SMTP CA certificate").option("--clear-username", "Clear stored SMTP username/password pair");
241361
+ }
241362
+ var EMAIL_SERVERS_EXAMPLES = `
241363
+ Examples:
241364
+ $ eigenpal email-servers list --json
241365
+ $ eigenpal email-servers get ems_... --json
241366
+ $ eigenpal email-servers create --transport resend --name Alerts \\
241367
+ --from-email alerts@example.com --from-name Alerts --api-key-stdin
241368
+ $ eigenpal email-servers create --transport smtp --name "Corp SMTP" --host smtp.example.com \\
241369
+ --from-email noreply@example.com --from-name Eigenpal
241370
+ $ eigenpal email-servers create --config-file ./resend.json --api-key-file ./re.key
241371
+ $ eigenpal email-servers update ems_... --name "Ops alerts"
241372
+ $ eigenpal email-servers update ems_... --transport smtp --host smtp.example.com \\
241373
+ --port 587 --security starttls --from-email noreply@example.com \\
241374
+ --from-name Eigenpal --password-stdin
241375
+ $ eigenpal email-servers delete ems_... --yes
241376
+ $ eigenpal email-servers test ems_... --to you@example.com
241377
+
241378
+ Secrets never belong on the command line. Provide Resend API keys, SMTP passwords,
241379
+ and CA PEM material via --*-stdin, --*-file, or the secure TTY prompt.
241380
+ `;
241381
+ function registerEmailServersCommands(program) {
241382
+ const emailServers = program.command("email-servers").alias("email-server").description("Manage outbound email servers (ems_…): list, inspect, create, update, delete, and send a real test message.").addHelpText("after", EMAIL_SERVERS_EXAMPLES);
241383
+ const listCmd = emailServers.command("list").description("List outbound email servers for the current workspace.");
241384
+ addJsonFlag(withBaseUrl(withPagination(listCmd))).action(action(async (opts) => {
241385
+ const client = buildClient2(opts);
241386
+ const raw = await client.get(apiPath("/email-servers"), {
241387
+ limit: String(opts.limit),
241388
+ offset: String(opts.offset)
241389
+ });
241390
+ renderListResult(raw, LIST_COLUMNS, {
241391
+ json: opts.json,
241392
+ entityLabel: "email server"
241393
+ });
241394
+ }));
241395
+ const getCmd = emailServers.command("get <id>").description("Inspect one email server. Human output is redacted even if the API regresses.");
241396
+ addJsonFlag(withBaseUrl(getCmd)).action(action(async (id, opts) => {
241397
+ const client = buildClient2(opts);
241398
+ const raw = await client.get(apiPath(`/email-servers/${encodeURIComponent(id)}`));
241399
+ const redacted = redactEmailServerPayload(raw);
241400
+ if (opts.json) {
241401
+ printJson2(redacted);
241402
+ return;
241403
+ }
241404
+ console.log(formatEmailServerHuman(redacted));
241405
+ }));
241406
+ const createCmd = emailServers.command("create").description("Create an outbound email server. Resend requires an API key; SMTP accepts optional username/password except with --security none, plus optional CA PEM, and defaults to starttls on port 587.");
241407
+ addJsonFlag(withBaseUrl(sharedCreateOptions(createCmd))).action(action(async (opts) => {
241408
+ const body = await buildCreateRequest(opts);
241409
+ const client = buildClient2(opts);
241410
+ const created = await client.post(apiPath("/email-servers"), body);
241411
+ const redacted = redactEmailServerPayload(created);
241412
+ if (opts.json) {
241413
+ printJson2(redacted);
241414
+ return;
241415
+ }
241416
+ success(`Created ${ui.bold(redacted.id)} (${redacted.transport})`);
241417
+ console.log(formatEmailServerHuman(redacted));
241418
+ }));
241419
+ const updateCmd = emailServers.command("update <id>").description("Update metadata or replace transport configuration. Omitted secrets are retained. Passing --transport smtp requires --host, --port, --security, --from-email, and --from-name (no security/port defaults). Metadata-only updates omit --transport.");
241420
+ addJsonFlag(withBaseUrl(sharedUpdateOptions(updateCmd))).action(action(async (id, opts) => {
241421
+ const client = buildClient2(opts);
241422
+ const existing = await client.get(apiPath(`/email-servers/${encodeURIComponent(id)}`));
241423
+ const body = await buildUpdateRequest({ existing, opts });
241424
+ const updated = await client.patch(apiPath(`/email-servers/${encodeURIComponent(id)}`), body);
241425
+ const redacted = redactEmailServerPayload(updated);
241426
+ if (opts.json) {
241427
+ printJson2(redacted);
241428
+ return;
241429
+ }
241430
+ success(`Updated ${ui.bold(redacted.id)}`);
241431
+ console.log(formatEmailServerHuman(redacted));
241432
+ }));
241433
+ const deleteCmd = emailServers.command("delete <id>").description("Soft-delete an outbound email server.").option("--yes", "Required for non-TTY shells", false);
241434
+ addJsonFlag(withBaseUrl(deleteCmd)).action(action(async (id, opts) => {
241435
+ if (!opts.yes && !process.stdout.isTTY) {
241436
+ throw new Error("email-servers delete is destructive and requires --yes when run non-interactively");
241437
+ }
241438
+ const client = buildClient2(opts);
241439
+ const result = await client.delete(apiPath(`/email-servers/${encodeURIComponent(id)}`));
241440
+ if (opts.json) {
241441
+ printJson2(result);
241442
+ return;
241443
+ }
241444
+ success(`Deleted ${ui.bold(id)}`);
241445
+ }));
241446
+ const testCmd = emailServers.command("test <id>").description("Send a real connectivity test email through the stored server to --to. Disabled servers fail with a conflict.").requiredOption("--to <email>", "Recipient for the live test message");
241447
+ addJsonFlag(withBaseUrl(testCmd)).action(action(async (id, opts) => {
241448
+ const client = buildClient2(opts);
241449
+ const result = await client.post(apiPath(`/email-servers/${encodeURIComponent(id)}/test`), {
241450
+ to: opts.to
241451
+ });
241452
+ if (opts.json) {
241453
+ printJson2(result);
241454
+ if (!result.ok)
241455
+ process.exit(1);
241456
+ return;
241457
+ }
241458
+ if (result.ok) {
241459
+ success(`Test email sent via ${ui.bold(result.transport)} (${ui.dim(result.messageId)})`);
241460
+ return;
241461
+ }
241462
+ throw new Error(result.error);
241463
+ }));
241464
+ }
241465
+
240646
241466
  // src/commands/init/index.ts
240647
241467
  init_dist4();
240648
241468
  import {
240649
241469
  copyFileSync,
240650
- existsSync as existsSync14,
241470
+ existsSync as existsSync15,
240651
241471
  mkdirSync as mkdirSync5,
240652
241472
  readdirSync as readdirSync4,
240653
- readFileSync as readFileSync14,
241473
+ readFileSync as readFileSync15,
240654
241474
  statSync as statSync4,
240655
241475
  writeFileSync as writeFileSync7
240656
241476
  } from "node:fs";
240657
- import { dirname as dirname4, join as join7, relative as relative2, resolve as resolve4 } from "node:path";
241477
+ import { dirname as dirname4, join as join7, relative as relative2, resolve as resolve5 } from "node:path";
240658
241478
  import { fileURLToPath as fileURLToPath6 } from "node:url";
240659
241479
  var TEMPLATE_NAMES = ["blank", "pdf-extraction", "text-classification"];
240660
241480
  var TEMPLATE_DESCRIPTIONS = {
@@ -240667,11 +241487,11 @@ function isValidProjectName(name) {
240667
241487
  }
240668
241488
  function resolveTemplatesRoot() {
240669
241489
  const here = dirname4(fileURLToPath6(import.meta.url));
240670
- const srcCandidate = resolve4(here, "..", "..", "templates");
240671
- if (existsSync14(srcCandidate))
241490
+ const srcCandidate = resolve5(here, "..", "..", "templates");
241491
+ if (existsSync15(srcCandidate))
240672
241492
  return srcCandidate;
240673
- const distCandidate = resolve4(here, "templates");
240674
- if (existsSync14(distCandidate))
241493
+ const distCandidate = resolve5(here, "templates");
241494
+ if (existsSync15(distCandidate))
240675
241495
  return distCandidate;
240676
241496
  throw new Error(`Cannot locate bundled templates. Looked in:
240677
241497
  ${srcCandidate}
@@ -240681,9 +241501,9 @@ async function init(name, opts) {
240681
241501
  if (!isValidProjectName(name)) {
240682
241502
  throw new Error(`Invalid project name "${name}". Use lowercase kebab/snake-case (e.g. parse-invoices), max 60 chars.`);
240683
241503
  }
240684
- const target = resolve4(process.cwd(), opts.dir ?? name);
241504
+ const target = resolve5(process.cwd(), opts.dir ?? name);
240685
241505
  assertSafeTargetDir(target, opts.dir);
240686
- if (existsSync14(target) && readdirSync4(target).length > 0) {
241506
+ if (existsSync15(target) && readdirSync4(target).length > 0) {
240687
241507
  throw new Error(`Target directory ${relative2(process.cwd(), target)} exists and is not empty.`);
240688
241508
  }
240689
241509
  let template;
@@ -240698,7 +241518,7 @@ async function init(name, opts) {
240698
241518
  template = await promptForTemplate();
240699
241519
  }
240700
241520
  const sourceRoot = join7(resolveTemplatesRoot(), template);
240701
- if (!existsSync14(sourceRoot)) {
241521
+ if (!existsSync15(sourceRoot)) {
240702
241522
  throw new Error(`Template directory missing on disk: ${sourceRoot}`);
240703
241523
  }
240704
241524
  const written = copyTemplate(sourceRoot, target, name);
@@ -240751,7 +241571,7 @@ function copyTemplate(src, dst, projectName) {
240751
241571
  }
240752
241572
  mkdirSync5(dirname4(targetPath), { recursive: true });
240753
241573
  if (isTextFile(sourcePath)) {
240754
- const text = readFileSync14(sourcePath, "utf-8").replaceAll(PLACEHOLDER, projectName);
241574
+ const text = readFileSync15(sourcePath, "utf-8").replaceAll(PLACEHOLDER, projectName);
240755
241575
  writeFileSync7(targetPath, text);
240756
241576
  } else {
240757
241577
  copyFileSync(sourcePath, targetPath);
@@ -240878,20 +241698,6 @@ function multipartMaxBytesFromEnv(raw = env.EIGENPAL_MULTIPART_MAX_BYTES) {
240878
241698
 
240879
241699
  // src/lib/upload-reusable-file.ts
240880
241700
  import { randomUUID } from "node:crypto";
240881
-
240882
- // src/lib/api-paths.ts
240883
- var API_PREFIX = "/v1";
240884
- function apiPath(suffix) {
240885
- if (suffix === "/v1" || suffix.startsWith("/v1/"))
240886
- return suffix;
240887
- if (suffix === "/api/v1" || suffix.startsWith("/api/v1/")) {
240888
- return `${API_PREFIX}${suffix.slice("/api/v1".length)}`;
240889
- }
240890
- const normalized = suffix.startsWith("/") ? suffix : `/${suffix}`;
240891
- return `${API_PREFIX}${normalized}`;
240892
- }
240893
-
240894
- // src/lib/upload-reusable-file.ts
240895
241701
  function newIdempotencyKey() {
240896
241702
  return randomUUID();
240897
241703
  }
@@ -241046,8 +241852,8 @@ function parseInputFileSpecs(inputFile) {
241046
241852
 
241047
241853
  // src/lib/format-eigenpal.ts
241048
241854
  import { spawnSync as spawnSync5 } from "child_process";
241049
- import { existsSync as existsSync15, readFileSync as readFileSync15 } from "fs";
241050
- import { join as join8, resolve as resolve5 } from "path";
241855
+ import { existsSync as existsSync16, readFileSync as readFileSync16 } from "fs";
241856
+ import { join as join8, resolve as resolve6 } from "path";
241051
241857
  var PRETTRC_NAMES = [
241052
241858
  ".prettierrc",
241053
241859
  ".prettierrc.json",
@@ -241060,14 +241866,14 @@ var PRETTRC_NAMES = [
241060
241866
  ];
241061
241867
  function hasPrettierConfig(cwd) {
241062
241868
  for (const name of PRETTRC_NAMES) {
241063
- if (existsSync15(join8(cwd, name)))
241869
+ if (existsSync16(join8(cwd, name)))
241064
241870
  return true;
241065
241871
  }
241066
241872
  try {
241067
241873
  const pkgPath = join8(cwd, "package.json");
241068
- if (!existsSync15(pkgPath))
241874
+ if (!existsSync16(pkgPath))
241069
241875
  return false;
241070
- const raw = readFileSync15(pkgPath, "utf-8");
241876
+ const raw = readFileSync16(pkgPath, "utf-8");
241071
241877
  const pkg = JSON.parse(raw);
241072
241878
  return pkg != null && typeof pkg === "object" && "prettier" in pkg;
241073
241879
  } catch {
@@ -241076,8 +241882,8 @@ function hasPrettierConfig(cwd) {
241076
241882
  }
241077
241883
  function formatEigenpalDirIfAvailable(dir) {
241078
241884
  const cwd = process.cwd();
241079
- const absDir = resolve5(cwd, dir);
241080
- if (!existsSync15(absDir))
241885
+ const absDir = resolve6(cwd, dir);
241886
+ if (!existsSync16(absDir))
241081
241887
  return;
241082
241888
  if (!hasPrettierConfig(cwd))
241083
241889
  return;
@@ -241204,17 +242010,17 @@ async function rerunTarget(runId, opts) {
241204
242010
  init_dist4();
241205
242011
  import { createHash as createHash5 } from "node:crypto";
241206
242012
  import {
241207
- existsSync as existsSync16,
242013
+ existsSync as existsSync17,
241208
242014
  lstatSync,
241209
242015
  mkdirSync as mkdirSync6,
241210
- readFileSync as readFileSync16,
242016
+ readFileSync as readFileSync17,
241211
242017
  readdirSync as readdirSync5,
241212
242018
  rmSync as rmSync2,
241213
242019
  rmdirSync,
241214
242020
  unlinkSync as unlinkSync2,
241215
242021
  writeFileSync as writeFileSync8
241216
242022
  } from "node:fs";
241217
- import { sep as PATH_SEP, dirname as dirname5, join as join10, relative as relative3, resolve as resolve6 } from "node:path";
242023
+ import { sep as PATH_SEP, dirname as dirname5, join as join10, relative as relative3, resolve as resolve7 } from "node:path";
241218
242024
  import { fileURLToPath as fileURLToPath7 } from "node:url";
241219
242025
 
241220
242026
  // src/commands/skill/tools.ts
@@ -241289,11 +242095,11 @@ var TOOLS = [
241289
242095
  var MANIFEST_NAME = ".eigenpal-manifest.json";
241290
242096
  function resolveSkillSource() {
241291
242097
  const here = dirname5(fileURLToPath7(import.meta.url));
241292
- const srcCandidate = resolve6(here, "..", "..", "skill");
241293
- if (existsSync16(srcCandidate))
242098
+ const srcCandidate = resolve7(here, "..", "..", "skill");
242099
+ if (existsSync17(srcCandidate))
241294
242100
  return srcCandidate;
241295
- const distCandidate = resolve6(here, "skill");
241296
- if (existsSync16(distCandidate))
242101
+ const distCandidate = resolve7(here, "skill");
242102
+ if (existsSync17(distCandidate))
241297
242103
  return distCandidate;
241298
242104
  throw new Error(`Cannot locate bundled skill content. Looked in:
241299
242105
  ${srcCandidate}
@@ -241330,15 +242136,15 @@ async function installSkill(opts) {
241330
242136
  for (const relativePath of sourceFiles) {
241331
242137
  const sourcePath = join10(source, relativePath);
241332
242138
  const targetPath = join10(target, relativePath);
241333
- const sourceBytes = templateSourceFile(relativePath, readFileSync16(sourcePath), cliVersion);
242139
+ const sourceBytes = templateSourceFile(relativePath, readFileSync17(sourcePath), cliVersion);
241334
242140
  const sourceHash = sha256(sourceBytes);
241335
- if (!existsSync16(targetPath)) {
242141
+ if (!existsSync17(targetPath)) {
241336
242142
  mkdirSync6(dirname5(targetPath), { recursive: true });
241337
242143
  writeFileSync8(targetPath, sourceBytes);
241338
242144
  written += 1;
241339
242145
  continue;
241340
242146
  }
241341
- const targetBytes = readFileSync16(targetPath);
242147
+ const targetBytes = readFileSync17(targetPath);
241342
242148
  const targetHash = sha256(targetBytes);
241343
242149
  if (targetHash === sourceHash) {
241344
242150
  skipped += 1;
@@ -241370,9 +242176,9 @@ async function installSkill(opts) {
241370
242176
  const manifestEntries = [];
241371
242177
  for (const relativePath of sourceFiles) {
241372
242178
  const targetPath = join10(target, relativePath);
241373
- if (!existsSync16(targetPath))
242179
+ if (!existsSync17(targetPath))
241374
242180
  continue;
241375
- manifestEntries.push({ path: relativePath, sha256: sha256(readFileSync16(targetPath)) });
242181
+ manifestEntries.push({ path: relativePath, sha256: sha256(readFileSync17(targetPath)) });
241376
242182
  }
241377
242183
  const manifest = {
241378
242184
  cliVersion,
@@ -241403,19 +242209,19 @@ async function uninstallSkill(opts) {
241403
242209
  } else if (!opts.yes) {
241404
242210
  throw new Error(nonInteractiveYesRequired("Uninstall skill from custom --target path"));
241405
242211
  }
241406
- const targetReal = resolve6(target);
242212
+ const targetReal = resolve7(target);
241407
242213
  const safeBase = targetReal + PATH_SEP;
241408
242214
  let removed = 0;
241409
242215
  let kept = 0;
241410
242216
  for (const entry of manifest.files) {
241411
- const path = resolve6(targetReal, entry.path);
242217
+ const path = resolve7(targetReal, entry.path);
241412
242218
  if (path !== targetReal && !path.startsWith(safeBase)) {
241413
242219
  console.error(`Refusing to touch ${path}: manifest path escapes ${targetReal}`);
241414
242220
  continue;
241415
242221
  }
241416
- if (!existsSync16(path))
242222
+ if (!existsSync17(path))
241417
242223
  continue;
241418
- const currentHash = sha256(readFileSync16(path));
242224
+ const currentHash = sha256(readFileSync17(path));
241419
242225
  if (currentHash !== entry.sha256 && !opts.yes) {
241420
242226
  kept += 1;
241421
242227
  continue;
@@ -241616,10 +242422,10 @@ function hintFor(tool, installed, detected) {
241616
242422
  return tool.relativePath;
241617
242423
  }
241618
242424
  function isInstalled(cwd, tool) {
241619
- return existsSync16(join10(cwd, tool.relativePath, MANIFEST_NAME));
242425
+ return existsSync17(join10(cwd, tool.relativePath, MANIFEST_NAME));
241620
242426
  }
241621
242427
  function isProjectUsing(cwd, tool) {
241622
- return tool.detectPaths.some((p) => existsSync16(join10(cwd, p)));
242428
+ return tool.detectPaths.some((p) => existsSync17(join10(cwd, p)));
241623
242429
  }
241624
242430
  function listFiles(root) {
241625
242431
  const out = [];
@@ -241643,10 +242449,10 @@ function listFiles(root) {
241643
242449
  }
241644
242450
  function readManifest(target) {
241645
242451
  const path = join10(target, MANIFEST_NAME);
241646
- if (!existsSync16(path))
242452
+ if (!existsSync17(path))
241647
242453
  return null;
241648
242454
  try {
241649
- return JSON.parse(readFileSync16(path, "utf-8"));
242455
+ return JSON.parse(readFileSync17(path, "utf-8"));
241650
242456
  } catch {
241651
242457
  return null;
241652
242458
  }
@@ -241655,13 +242461,13 @@ function readCliVersion() {
241655
242461
  try {
241656
242462
  const here = dirname5(fileURLToPath7(import.meta.url));
241657
242463
  const candidates = [
241658
- resolve6(here, "..", "..", "..", "package.json"),
241659
- resolve6(here, "..", "..", "package.json"),
241660
- resolve6(here, "..", "package.json")
242464
+ resolve7(here, "..", "..", "..", "package.json"),
242465
+ resolve7(here, "..", "..", "package.json"),
242466
+ resolve7(here, "..", "package.json")
241661
242467
  ];
241662
242468
  for (const candidate of candidates) {
241663
- if (existsSync16(candidate)) {
241664
- const pkg = JSON.parse(readFileSync16(candidate, "utf-8"));
242469
+ if (existsSync17(candidate)) {
242470
+ const pkg = JSON.parse(readFileSync17(candidate, "utf-8"));
241665
242471
  if (pkg.name && pkg.name !== "@eigenpal/cli")
241666
242472
  continue;
241667
242473
  if (pkg.version)
@@ -241672,7 +242478,7 @@ function readCliVersion() {
241672
242478
  return "unknown";
241673
242479
  }
241674
242480
  function pruneEmptyDirs(root) {
241675
- if (!existsSync16(root))
242481
+ if (!existsSync17(root))
241676
242482
  return;
241677
242483
  const stack = [];
241678
242484
  const collect = (dir) => {
@@ -242462,13 +243268,13 @@ function looksLikeFreeform(prop) {
242462
243268
  return prop.pattern !== undefined || prop.format !== undefined;
242463
243269
  }
242464
243270
  // src/commands/workflow/index.ts
242465
- import { existsSync as existsSync22, promises as fs20 } from "node:fs";
243271
+ import { existsSync as existsSync23, promises as fs20 } from "node:fs";
242466
243272
  import path18 from "node:path";
242467
243273
 
242468
243274
  // src/lib/local-templates.ts
242469
243275
  init_src();
242470
- import { existsSync as existsSync17, promises as fs17, realpathSync as realpathSync3, statSync as statSync5 } from "node:fs";
242471
- import { basename, dirname as dirname6, isAbsolute, relative as relative4, resolve as resolve7, sep } from "node:path";
243276
+ import { existsSync as existsSync18, promises as fs17, realpathSync as realpathSync3, statSync as statSync5 } from "node:fs";
243277
+ import { basename, dirname as dirname6, isAbsolute, relative as relative4, resolve as resolve8, sep } from "node:path";
242472
243278
 
242473
243279
  // src/lib/office-template.ts
242474
243280
  import { createHash as createHash6 } from "node:crypto";
@@ -242709,8 +243515,8 @@ function walkTemplateSteps(steps, visit) {
242709
243515
  }
242710
243516
  }
242711
243517
  function resolveWorkflowProjectRoot(workflowFile) {
242712
- const abs = resolve7(workflowFile);
242713
- if (!existsSync17(abs)) {
243518
+ const abs = resolve8(workflowFile);
243519
+ if (!existsSync18(abs)) {
242714
243520
  throw new Error(`Workflow file not found: ${abs}`);
242715
243521
  }
242716
243522
  return dirname6(realpathSync3(abs));
@@ -242729,11 +243535,11 @@ function resolveWorkflowTemplatePath(workflowFile, templatePath, opts = {}) {
242729
243535
  throw new Error(`Invalid local template path "${templatePath}". Use a relative .docx or .xlsx path such as ./templates/foo.xlsx.`);
242730
243536
  }
242731
243537
  const projectRoot = resolveWorkflowProjectRoot(workflowFile);
242732
- const candidate = resolve7(projectRoot, templatePath);
243538
+ const candidate = resolve8(projectRoot, templatePath);
242733
243539
  if (!opts.allowExternal) {
242734
243540
  assertInsideProject(projectRoot, templatePath, candidate);
242735
243541
  }
242736
- if (!existsSync17(candidate)) {
243542
+ if (!existsSync18(candidate)) {
242737
243543
  throw new Error(`Local template not found: ${candidate}`);
242738
243544
  }
242739
243545
  const real = realpathSync3(candidate);
@@ -242915,11 +243721,11 @@ function rewriteLocalTemplateYaml(yamlText, resolved) {
242915
243721
  }
242916
243722
 
242917
243723
  // src/commands/workflow/clear.ts
242918
- import { existsSync as existsSync18, readdirSync as readdirSync6, rmSync as rmSync3, statSync as statSync6 } from "fs";
243724
+ import { existsSync as existsSync19, readdirSync as readdirSync6, rmSync as rmSync3, statSync as statSync6 } from "fs";
242919
243725
  import { basename as basename2, join as join11 } from "path";
242920
243726
  var EMPTY_REPORT = { removed: 0, kept: 0, touched: 0 };
242921
243727
  function getDirectoryEntries(path) {
242922
- if (!existsSync18(path))
243728
+ if (!existsSync19(path))
242923
243729
  return [];
242924
243730
  return readdirSync6(path).filter((entry) => statSync6(join11(path, entry)).isDirectory()).sort();
242925
243731
  }
@@ -242940,7 +243746,7 @@ function removeDirEntriesWithRetention(path, removeAll) {
242940
243746
  return { removed, kept: keepSet.size, touched: entries.length };
242941
243747
  }
242942
243748
  function removeJudgeSummaryFilesWithRetention(exampleDir, removeAll) {
242943
- if (!existsSync18(exampleDir))
243749
+ if (!existsSync19(exampleDir))
242944
243750
  return EMPTY_REPORT;
242945
243751
  const stampByFile = new Map;
242946
243752
  for (const fileName of readdirSync6(exampleDir).sort()) {
@@ -243012,7 +243818,7 @@ async function clearEvalOutputs(dir, exampleNames = [], options = {}) {
243012
243818
  runSection({
243013
243819
  exampleDirs,
243014
243820
  clean: (exampleDir) => removeDirEntriesWithRetention(join11(exampleDir, "executions"), removeAll),
243015
- shouldCount: (exampleDir) => existsSync18(join11(exampleDir, "executions")),
243821
+ shouldCount: (exampleDir) => existsSync19(join11(exampleDir, "executions")),
243016
243822
  successLabel: "Execution cleanup complete",
243017
243823
  scannedLabel: "examples scanned:",
243018
243824
  seenLabel: "runs seen: ",
@@ -243024,7 +243830,7 @@ async function clearEvalOutputs(dir, exampleNames = [], options = {}) {
243024
243830
  runSection({
243025
243831
  exampleDirs,
243026
243832
  clean: (exampleDir) => removeJudgeSummaryFilesWithRetention(exampleDir, removeAll),
243027
- shouldCount: (exampleDir) => existsSync18(exampleDir),
243833
+ shouldCount: (exampleDir) => existsSync19(exampleDir),
243028
243834
  successLabel: "Judge summary cleanup complete",
243029
243835
  scannedLabel: "examples scanned: ",
243030
243836
  seenLabel: "summary files seen: ",
@@ -243137,24 +243943,24 @@ function registerStepExecCommands(workflow) {
243137
243943
 
243138
243944
  // src/commands/workflow/templates.ts
243139
243945
  init_src();
243140
- import { existsSync as existsSync19, promises as fs19 } from "node:fs";
243141
- import { basename as basename3, resolve as resolve8 } from "node:path";
243142
- function buildClient2(opts) {
243946
+ import { existsSync as existsSync20, promises as fs19 } from "node:fs";
243947
+ import { basename as basename3, resolve as resolve9 } from "node:path";
243948
+ function buildClient3(opts) {
243143
243949
  const config = resolveConfig(opts);
243144
243950
  requireApiKey(config);
243145
243951
  return new ApiClient(config);
243146
243952
  }
243147
- function printJson2(value) {
243953
+ function printJson3(value) {
243148
243954
  console.log(JSON.stringify(value, null, 2));
243149
243955
  }
243150
243956
  async function readJsonFixtureFile(fixturePath) {
243151
243957
  let raw;
243152
243958
  try {
243153
- raw = await fs19.readFile(resolve8(fixturePath), "utf8");
243959
+ raw = await fs19.readFile(resolve9(fixturePath), "utf8");
243154
243960
  } catch (err) {
243155
243961
  const code = err && typeof err === "object" && "code" in err ? String(err.code) : "";
243156
243962
  if (code === "ENOENT") {
243157
- throw new Error(`JSON fixture file not found: ${resolve8(fixturePath)}`);
243963
+ throw new Error(`JSON fixture file not found: ${resolve9(fixturePath)}`);
243158
243964
  }
243159
243965
  throw err;
243160
243966
  }
@@ -243201,9 +244007,9 @@ function registerTemplateCommands(parent) {
243201
244007
  const templates = parent.command("templates").description("Manage workspace DOCX/XLSX templates (tmpl_…): upload, list, inspect, download, replace, delete, and smoke-fill.").addHelpText("after", TEMPLATES_EXAMPLES);
243202
244008
  const uploadCmd = templates.command("upload <file>").description("Upload a DOCX or XLSX file as a new tmpl_… resource with an immutable tmpr_… revision.").option("--name <name>", "Display name (defaults to the filename without extension)").option("--description <text>", "Optional description");
243203
244009
  addJsonFlag(withBaseUrl(uploadCmd)).action(action(async (file, opts) => {
243204
- const filePath = resolve8(file);
244010
+ const filePath = resolve9(file);
243205
244011
  const bytes = await fs19.readFile(filePath);
243206
- const client = buildClient2(opts);
244012
+ const client = buildClient3(opts);
243207
244013
  const template = await uploadWorkspaceTemplate(client, {
243208
244014
  bytes,
243209
244015
  filename: basename3(filePath),
@@ -243211,7 +244017,7 @@ function registerTemplateCommands(parent) {
243211
244017
  description: opts.description
243212
244018
  });
243213
244019
  if (opts.json) {
243214
- printJson2(template);
244020
+ printJson3(template);
243215
244021
  return;
243216
244022
  }
243217
244023
  success(`Uploaded ${ui.bold(template.id)} revision ${ui.bold(template.currentRevision?.id ?? "-")} (${template.format})`);
@@ -243219,10 +244025,10 @@ function registerTemplateCommands(parent) {
243219
244025
  }));
243220
244026
  const listCmd = templates.command("list").description("List workspace templates.");
243221
244027
  addJsonFlag(withBaseUrl(withPagination(listCmd))).action(action(async (opts) => {
243222
- const client = buildClient2(opts);
244028
+ const client = buildClient3(opts);
243223
244029
  const result = await listPublicTemplates(client, { limit: opts.limit, offset: opts.offset });
243224
244030
  if (opts.json) {
243225
- printJson2(result);
244031
+ printJson3(result);
243226
244032
  return;
243227
244033
  }
243228
244034
  console.log(table(result.items.map((row) => ({
@@ -243247,10 +244053,10 @@ function registerTemplateCommands(parent) {
243247
244053
  }));
243248
244054
  const getCmd = templates.command("get <template-id>").alias("inspect").description("Inspect a tmpl_… resource: current tmpr_…, format, checksum, tokens, grammar.");
243249
244055
  addJsonFlag(withBaseUrl(getCmd)).action(action(async (templateId, opts) => {
243250
- const client = buildClient2(opts);
244056
+ const client = buildClient3(opts);
243251
244057
  const template = await getPublicTemplate(client, templateId);
243252
244058
  if (opts.json) {
243253
- printJson2(template);
244059
+ printJson3(template);
243254
244060
  return;
243255
244061
  }
243256
244062
  printTemplateHuman(template);
@@ -243259,21 +244065,21 @@ function registerTemplateCommands(parent) {
243259
244065
  withBaseUrl(downloadCmd).action(action(async (templateId, opts) => {
243260
244066
  if (!opts.out)
243261
244067
  throw new Error("Missing --out <path>.");
243262
- const client = buildClient2(opts);
244068
+ const client = buildClient3(opts);
243263
244069
  const downloaded = await downloadTemplateBytes(client, templateId, opts.revisionId);
243264
244070
  await fs19.writeFile(opts.out, downloaded.bytes);
243265
244071
  success(`Wrote ${ui.bold(opts.out)} ${ui.dim(`(${downloaded.bytes.byteLength} bytes)`)}`);
243266
244072
  }));
243267
244073
  const replaceCmd = templates.command("replace <template-id> <file>").description("Append an immutable revision and advance the tmpl_… pointer.");
243268
244074
  addJsonFlag(withBaseUrl(replaceCmd)).action(action(async (templateId, file, opts) => {
243269
- const filePath = resolve8(file);
244075
+ const filePath = resolve9(file);
243270
244076
  const bytes = await fs19.readFile(filePath);
243271
- const client = buildClient2(opts);
244077
+ const client = buildClient3(opts);
243272
244078
  const current = await getPublicTemplate(client, templateId);
243273
244079
  const nextInspection = inspectOfficeTemplateBytes(bytes, basename3(filePath));
243274
244080
  if (current.currentRevision?.sha256 === nextInspection.sha256 || current.sha256 === nextInspection.sha256) {
243275
244081
  if (opts.json) {
243276
- printJson2({ ...current, reused: true });
244082
+ printJson3({ ...current, reused: true });
243277
244083
  return;
243278
244084
  }
243279
244085
  success(`Checksum matches current revision ${ui.bold(current.currentRevision?.id ?? "-")} — skipped upload`);
@@ -243285,7 +244091,7 @@ function registerTemplateCommands(parent) {
243285
244091
  filename: basename3(filePath)
243286
244092
  });
243287
244093
  if (opts.json) {
243288
- printJson2(template);
244094
+ printJson3(template);
243289
244095
  return;
243290
244096
  }
243291
244097
  success(`Replaced ${ui.bold(template.id)} → revision ${ui.bold(template.currentRevision?.id ?? "-")}`);
@@ -243296,10 +244102,10 @@ function registerTemplateCommands(parent) {
243296
244102
  if (!opts.yes && !process.stdout.isTTY) {
243297
244103
  throw new Error("templates delete is destructive and requires --yes when run non-interactively");
243298
244104
  }
243299
- const client = buildClient2(opts);
244105
+ const client = buildClient3(opts);
243300
244106
  const result = await deleteWorkspaceTemplate(client, templateId);
243301
244107
  if (opts.json) {
243302
- printJson2(result);
244108
+ printJson3(result);
243303
244109
  return;
243304
244110
  }
243305
244111
  success(`Deleted ${ui.bold(templateId)}`);
@@ -243312,13 +244118,13 @@ function registerTemplateCommands(parent) {
243312
244118
  let filename;
243313
244119
  const isTmpl = TemplateIdSchema.safeParse(templateArg).success;
243314
244120
  if (isTmpl) {
243315
- const client = buildClient2(opts);
244121
+ const client = buildClient3(opts);
243316
244122
  const downloaded = await downloadTemplateBytes(client, templateArg, opts.revisionId);
243317
244123
  bytes = downloaded.bytes;
243318
244124
  filename = downloaded.filename;
243319
244125
  } else {
243320
- const filePath = resolve8(templateArg);
243321
- if (!existsSync19(filePath)) {
244126
+ const filePath = resolve9(templateArg);
244127
+ if (!existsSync20(filePath)) {
243322
244128
  throw new Error(`Template file not found: ${filePath}. Pass a local .docx/.xlsx path or a tmpl_… id.`);
243323
244129
  }
243324
244130
  bytes = await fs19.readFile(filePath);
@@ -243340,7 +244146,7 @@ function registerTemplateCommands(parent) {
243340
244146
  bytes: rendered.output.byteLength
243341
244147
  };
243342
244148
  if (opts.json) {
243343
- printJson2(payload);
244149
+ printJson3(payload);
243344
244150
  return;
243345
244151
  }
243346
244152
  success(`Wrote ${ui.bold(opts.out)} (${rendered.inspection.format}, ${rendered.output.byteLength} bytes)`);
@@ -243360,12 +244166,12 @@ function registerTemplateCommands(parent) {
243360
244166
 
243361
244167
  // src/commands/workflow/validation.ts
243362
244168
  init_src();
243363
- import { existsSync as existsSync21, readdirSync as readdirSync7, readFileSync as readFileSync18, statSync as statSync7 } from "fs";
243364
- import { join as join12, resolve as resolve9 } from "path";
244169
+ import { existsSync as existsSync22, readdirSync as readdirSync7, readFileSync as readFileSync19, statSync as statSync7 } from "fs";
244170
+ import { join as join12, resolve as resolve10 } from "path";
243365
244171
 
243366
244172
  // src/lib/template-diagnostics.ts
243367
244173
  init_src();
243368
- import { existsSync as existsSync20, readFileSync as readFileSync17 } from "node:fs";
244174
+ import { existsSync as existsSync21, readFileSync as readFileSync18 } from "node:fs";
243369
244175
  function walkSteps(steps, pathPrefix, visit) {
243370
244176
  if (!Array.isArray(steps))
243371
244177
  return;
@@ -243490,7 +244296,7 @@ async function diagnoseTemplateSteps(args) {
243490
244296
  });
243491
244297
  continue;
243492
244298
  }
243493
- if (!existsSync20(absolute)) {
244299
+ if (!existsSync21(absolute)) {
243494
244300
  diagnostics.push({
243495
244301
  field: `${info.fieldPath}.template`,
243496
244302
  message: `File not found: ${absolute}`,
@@ -243499,7 +244305,7 @@ async function diagnoseTemplateSteps(args) {
243499
244305
  continue;
243500
244306
  }
243501
244307
  try {
243502
- const bytes = readFileSync17(absolute);
244308
+ const bytes = readFileSync18(absolute);
243503
244309
  const inspection = inspectOfficeTemplateBytes(bytes, absolute);
243504
244310
  diagnostics.push(...formatDiagnostics(info, inspection));
243505
244311
  } catch (err) {
@@ -243635,7 +244441,7 @@ function countInvokeWorkflowSteps(steps) {
243635
244441
  return count;
243636
244442
  }
243637
244443
  function validateWorkflowYaml(path) {
243638
- if (!existsSync21(path)) {
244444
+ if (!existsSync22(path)) {
243639
244445
  return {
243640
244446
  issues: [{ field: path, message: "File not found." }],
243641
244447
  warnings: [],
@@ -243644,7 +244450,7 @@ function validateWorkflowYaml(path) {
243644
244450
  steps: []
243645
244451
  };
243646
244452
  }
243647
- const text = readFileSync18(path, "utf-8");
244453
+ const text = readFileSync19(path, "utf-8");
243648
244454
  try {
243649
244455
  const definition = parseWorkflow(text);
243650
244456
  let warnings = [];
@@ -243745,10 +244551,10 @@ function printSchemaQualityWarnings(path, warnings) {
243745
244551
  }
243746
244552
  }
243747
244553
  function validateEvaluatorsYaml(path) {
243748
- if (!existsSync21(path)) {
244554
+ if (!existsSync22(path)) {
243749
244555
  return [{ field: path, message: "File not found." }];
243750
244556
  }
243751
- const text = readFileSync18(path, "utf-8");
244557
+ const text = readFileSync19(path, "utf-8");
243752
244558
  let parsed;
243753
244559
  try {
243754
244560
  parsed = $parse(text);
@@ -243765,17 +244571,17 @@ function validateEvaluatorsYaml(path) {
243765
244571
  }
243766
244572
  function validateDatasetFolder(root) {
243767
244573
  const issues = [];
243768
- if (!existsSync21(root)) {
244574
+ if (!existsSync22(root)) {
243769
244575
  return [{ field: root, message: "Folder not found." }];
243770
244576
  }
243771
- if (existsSync21(join12(root, "manifest.json"))) {
244577
+ if (existsSync22(join12(root, "manifest.json"))) {
243772
244578
  issues.push({
243773
244579
  field: "manifest.json",
243774
244580
  message: "Top-level manifest.json is the legacy format. Re-export the dataset using the folder convention."
243775
244581
  });
243776
244582
  }
243777
244583
  const examplesDir = join12(root, "examples");
243778
- if (!existsSync21(examplesDir)) {
244584
+ if (!existsSync22(examplesDir)) {
243779
244585
  issues.push({ field: "examples/", message: "No examples/ directory found at dataset root." });
243780
244586
  return issues;
243781
244587
  }
@@ -243791,7 +244597,7 @@ function validateDatasetFolder(root) {
243791
244597
  continue;
243792
244598
  }
243793
244599
  const inputJsonPath = join12(exampleFolder, "input.json");
243794
- const hasInputJson = existsSync21(inputJsonPath);
244600
+ const hasInputJson = existsSync22(inputJsonPath);
243795
244601
  if (!hasInputJson) {
243796
244602
  issues.push({
243797
244603
  field: `examples/${exampleName}/input.json`,
@@ -243801,7 +244607,7 @@ function validateDatasetFolder(root) {
243801
244607
  }
243802
244608
  let args;
243803
244609
  try {
243804
- const parsed = JSON.parse(readFileSync18(inputJsonPath, "utf-8"));
244610
+ const parsed = JSON.parse(readFileSync19(inputJsonPath, "utf-8"));
243805
244611
  if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
243806
244612
  issues.push({
243807
244613
  field: `examples/${exampleName}/input.json`,
@@ -243818,7 +244624,7 @@ function validateDatasetFolder(root) {
243818
244624
  continue;
243819
244625
  }
243820
244626
  const inputDir = join12(exampleFolder, "input");
243821
- if (existsSync21(join12(inputDir, "arguments.json"))) {
244627
+ if (existsSync22(join12(inputDir, "arguments.json"))) {
243822
244628
  issues.push({
243823
244629
  field: `examples/${exampleName}/input/arguments.json`,
243824
244630
  message: "Legacy input/arguments.json is no longer accepted. Use input.json instead."
@@ -243835,7 +244641,7 @@ function validateDatasetFolder(root) {
243835
244641
  }
243836
244642
  const expectedDir = join12(exampleFolder, "expected");
243837
244643
  const expectedJsonPath = join12(exampleFolder, "expected.json");
243838
- if (existsSync21(expectedDir)) {
244644
+ if (existsSync22(expectedDir)) {
243839
244645
  for (const entry of readdirSync7(expectedDir)) {
243840
244646
  if (entry === "output.json" || entry === "error.json") {
243841
244647
  issues.push({
@@ -243871,10 +244677,10 @@ function validateDatasetFolder(root) {
243871
244677
  }
243872
244678
  }
243873
244679
  }
243874
- if (existsSync21(expectedJsonPath)) {
244680
+ if (existsSync22(expectedJsonPath)) {
243875
244681
  let parsed;
243876
244682
  try {
243877
- parsed = JSON.parse(readFileSync18(expectedJsonPath, "utf-8"));
244683
+ parsed = JSON.parse(readFileSync19(expectedJsonPath, "utf-8"));
243878
244684
  } catch {
243879
244685
  issues.push({
243880
244686
  field: `examples/${exampleName}/expected.json`,
@@ -243953,7 +244759,7 @@ function validateFileRefs2(args) {
243953
244759
  });
243954
244760
  continue;
243955
244761
  }
243956
- if (!existsSync21(join12(args.filesRoot, relative))) {
244762
+ if (!existsSync22(join12(args.filesRoot, relative))) {
243957
244763
  issues.push({
243958
244764
  field: `${args.fieldPrefix}:${ref.jsonPath}`,
243959
244765
  message: `Referenced file does not exist: ${ref.path}.`
@@ -243974,7 +244780,7 @@ function parseDatasetFileRef(path, root) {
243974
244780
  return parts.join("/");
243975
244781
  }
243976
244782
  function rootDir(opts) {
243977
- return resolve9(opts.dir ?? process.cwd());
244783
+ return resolve10(opts.dir ?? process.cwd());
243978
244784
  }
243979
244785
  async function onlineInvokeIssues(yamlText, opts) {
243980
244786
  const config = resolveConfig(opts);
@@ -243984,8 +244790,8 @@ async function onlineInvokeIssues(yamlText, opts) {
243984
244790
  return res.issues ?? [];
243985
244791
  }
243986
244792
  function discoverWorkflowProjectRoots(rootPath) {
243987
- const root = resolve9(rootPath);
243988
- if (existsSync21(join12(root, "workflow.yaml")))
244793
+ const root = resolve10(rootPath);
244794
+ if (existsSync22(join12(root, "workflow.yaml")))
243989
244795
  return [root];
243990
244796
  const candidates = [
243991
244797
  join12(root, "eigenpal", "workflows"),
@@ -243993,9 +244799,9 @@ function discoverWorkflowProjectRoots(rootPath) {
243993
244799
  root.endsWith(join12("eigenpal", "workflows")) ? root : ""
243994
244800
  ].filter(Boolean);
243995
244801
  for (const parent of candidates) {
243996
- if (!existsSync21(parent) || !statSync7(parent).isDirectory())
244802
+ if (!existsSync22(parent) || !statSync7(parent).isDirectory())
243997
244803
  continue;
243998
- const projects = readdirSync7(parent, { withFileTypes: true }).filter((entry) => entry.isDirectory() && !entry.isSymbolicLink() && existsSync21(join12(parent, entry.name, "workflow.yaml"))).map((entry) => join12(parent, entry.name)).sort();
244804
+ const projects = readdirSync7(parent, { withFileTypes: true }).filter((entry) => entry.isDirectory() && !entry.isSymbolicLink() && existsSync22(join12(parent, entry.name, "workflow.yaml"))).map((entry) => join12(parent, entry.name)).sort();
243999
244805
  if (projects.length > 0)
244000
244806
  return projects;
244001
244807
  }
@@ -244012,10 +244818,10 @@ async function validateProjectRoot(root, opts) {
244012
244818
  }
244013
244819
  const evOk = printIssues("evaluators.yaml", relPath(root, join12(root, "evaluators.yaml")), validateEvaluatorsYaml(join12(root, "evaluators.yaml")));
244014
244820
  const dsOk = printIssues("dataset/", relPath(root, join12(root, "dataset")), validateDatasetFolder(join12(root, "dataset")));
244015
- const templateOk = wfOk && existsSync21(wfFile) ? await runTemplateDiagnostics(wfFile, wfResult.steps, opts) : true;
244821
+ const templateOk = wfOk && existsSync22(wfFile) ? await runTemplateDiagnostics(wfFile, wfResult.steps, opts) : true;
244016
244822
  let onlineOk = true;
244017
- if (wfOk && opts.online && existsSync21(wfFile)) {
244018
- onlineOk = printIssues("invoke refs (server)", wfPath, await onlineInvokeIssues(readFileSync18(wfFile, "utf-8"), opts));
244823
+ if (wfOk && opts.online && existsSync22(wfFile)) {
244824
+ onlineOk = printIssues("invoke refs (server)", wfPath, await onlineInvokeIssues(readFileSync19(wfFile, "utf-8"), opts));
244019
244825
  }
244020
244826
  return wfOk && evOk && dsOk && templateOk && onlineOk;
244021
244827
  }
@@ -244031,8 +244837,8 @@ Note
244031
244837
  ` + ` project unless you pass --allow-external-templates.
244032
244838
  `);
244033
244839
  withBaseUrl(cmd).action(action(async (path, opts) => {
244034
- if (path && (!existsSync21(resolve9(path)) || !statSync7(resolve9(path)).isDirectory())) {
244035
- const target = resolve9(path);
244840
+ if (path && (!existsSync22(resolve10(path)) || !statSync7(resolve10(path)).isDirectory())) {
244841
+ const target = resolve10(path);
244036
244842
  const wfResult = validateWorkflowYaml(target);
244037
244843
  const wfOk = printIssues("workflow.yaml", target, wfResult.issues);
244038
244844
  if (wfOk) {
@@ -244042,13 +244848,13 @@ Note
244042
244848
  const templateOk = wfOk ? await runTemplateDiagnostics(target, wfResult.steps, opts) : true;
244043
244849
  let onlineOk = true;
244044
244850
  if (wfOk && opts.online) {
244045
- onlineOk = printIssues("invoke refs (server)", target, await onlineInvokeIssues(readFileSync18(target, "utf-8"), opts));
244851
+ onlineOk = printIssues("invoke refs (server)", target, await onlineInvokeIssues(readFileSync19(target, "utf-8"), opts));
244046
244852
  }
244047
244853
  if (!wfOk || !templateOk || !onlineOk)
244048
244854
  process.exit(1);
244049
244855
  return;
244050
244856
  }
244051
- const requestedRoot = path ? resolve9(path) : rootDir(opts);
244857
+ const requestedRoot = path ? resolve10(path) : rootDir(opts);
244052
244858
  const projects = discoverWorkflowProjectRoots(requestedRoot);
244053
244859
  if (projects.length === 0) {
244054
244860
  if (!await validateProjectRoot(requestedRoot, opts))
@@ -244070,14 +244876,14 @@ Note
244070
244876
  }
244071
244877
  function registerEvaluatorsValidateCommand(parent) {
244072
244878
  parent.command("validate [path]").description("Validate an evaluators YAML file against the EvalConfig schema. Defaults to ./evaluators.yaml.").action((path) => {
244073
- const target = resolve9(path ?? "evaluators.yaml");
244879
+ const target = resolve10(path ?? "evaluators.yaml");
244074
244880
  if (!printIssues("evaluators", target, validateEvaluatorsYaml(target)))
244075
244881
  process.exit(1);
244076
244882
  });
244077
244883
  }
244078
244884
  function registerDatasetValidateCommand(parent) {
244079
244885
  parent.command("validate [path]").description("Validate a dataset folder against the examples/<name>/{input,expected,meta} convention. Defaults to ./dataset/.").action((path) => {
244080
- const target = resolve9(path ?? "dataset");
244886
+ const target = resolve10(path ?? "dataset");
244081
244887
  if (!printIssues("dataset", target, validateDatasetFolder(target)))
244082
244888
  process.exit(1);
244083
244889
  });
@@ -244091,20 +244897,20 @@ function relPath(root, target) {
244091
244897
  }
244092
244898
 
244093
244899
  // src/commands/workflow/index.ts
244094
- function buildClient3(opts) {
244900
+ function buildClient4(opts) {
244095
244901
  const config = resolveConfig(opts);
244096
244902
  requireApiKey(config);
244097
244903
  return new ApiClient(config);
244098
244904
  }
244099
244905
  async function buildClientForWorkflow(workflowIdOrSlug, opts) {
244100
- const client = buildClient3(opts);
244906
+ const client = buildClient4(opts);
244101
244907
  const workflowId = await resolveWorkflowId(client, workflowIdOrSlug);
244102
244908
  return { client, workflowId };
244103
244909
  }
244104
244910
  function descriptionFor(tool) {
244105
244911
  return WORKFLOW_TOOL_METADATA[tool].description;
244106
244912
  }
244107
- function printJson3(value) {
244913
+ function printJson4(value) {
244108
244914
  console.log(JSON.stringify(value, null, 2));
244109
244915
  }
244110
244916
  function extractWorkflowVersion(yaml) {
@@ -244205,7 +245011,7 @@ YAML's \`name:\` field). Both:
244205
245011
  function registerWorkflowCoreCommands(parent) {
244206
245012
  const listCmd = parent.command("list").description(descriptionFor("workflow_list")).option("--search <q>", "Filter by name");
244207
245013
  addJsonFlag(withBaseUrl(withPagination(listCmd))).action(action(async (opts) => {
244208
- const client = buildClient3(opts);
245014
+ const client = buildClient4(opts);
244209
245015
  const params = {
244210
245016
  limit: String(opts.limit),
244211
245017
  offset: String(opts.offset)
@@ -244293,7 +245099,7 @@ new uploads are deleted. The file on disk is not rewritten.
244293
245099
  defaultValue: "workflow.yaml",
244294
245100
  validate: (value) => {
244295
245101
  const p = value || "workflow.yaml";
244296
- if (!existsSync22(p))
245102
+ if (!existsSync23(p))
244297
245103
  return `Not found: ${p}`;
244298
245104
  return;
244299
245105
  }
@@ -244308,7 +245114,7 @@ new uploads are deleted. The file on disk is not rewritten.
244308
245114
  }
244309
245115
  }
244310
245116
  const yamlOnDisk = await fs20.readFile(filePath, "utf8");
244311
- const client = buildClient3(opts);
245117
+ const client = buildClient4(opts);
244312
245118
  const definition = parseWorkflowOrThrow(yamlOnDisk);
244313
245119
  const loadedTemplates = await loadLocalTemplatesForPush(filePath, definition.steps, {
244314
245120
  allowExternal: Boolean(opts.allowExternalTemplates)
@@ -244366,7 +245172,7 @@ new uploads are deleted. The file on disk is not rewritten.
244366
245172
  });
244367
245173
  await finalizeCreatedWorkspaceTemplates(client, created);
244368
245174
  if (opts.json) {
244369
- printJson3(withLocalTemplates(result, resolvedTemplates));
245175
+ printJson4(withLocalTemplates(result, resolvedTemplates));
244370
245176
  return;
244371
245177
  }
244372
245178
  success(`Pushed ${ui.bold(workflowId)} (v${result.version ?? nextVersion})`);
@@ -244380,7 +245186,7 @@ new uploads are deleted. The file on disk is not rewritten.
244380
245186
  });
244381
245187
  await finalizeCreatedWorkspaceTemplates(client, created);
244382
245188
  if (opts.json) {
244383
- printJson3(withLocalTemplates(result, resolvedTemplates));
245189
+ printJson4(withLocalTemplates(result, resolvedTemplates));
244384
245190
  return;
244385
245191
  }
244386
245192
  const id = result.workflow?.id ?? result.id ?? "?";
@@ -244399,7 +245205,7 @@ new uploads are deleted. The file on disk is not rewritten.
244399
245205
  folderPath: opts.folder
244400
245206
  });
244401
245207
  if (opts.json) {
244402
- printJson3(result);
245208
+ printJson4(result);
244403
245209
  return;
244404
245210
  }
244405
245211
  const target = opts.folder.trim() === "/" ? "root" : opts.folder;
@@ -244572,7 +245378,7 @@ function registerEvaluatorsCommands(parent) {
244572
245378
  yaml
244573
245379
  });
244574
245380
  if (opts.json) {
244575
- printJson3(result);
245381
+ printJson4(result);
244576
245382
  return;
244577
245383
  }
244578
245384
  let count = null;
@@ -244680,7 +245486,7 @@ skip in CI). Folder layout reference: \`packages/cli/src/skill/reference/dataset
244680
245486
  }));
244681
245487
  if (issues.length === 0) {
244682
245488
  error2("Import aborted with no structured issues — server-side bug.");
244683
- printJson3(terminal);
245489
+ printJson4(terminal);
244684
245490
  } else {
244685
245491
  printIssues("dataset", opts.file, issues);
244686
245492
  if (errPayload.limitMb != null && errPayload.actualMb != null) {
@@ -244701,7 +245507,7 @@ skip in CI). Folder layout reference: \`packages/cli/src/skill/reference/dataset
244701
245507
  if (terminal.phase === "done") {
244702
245508
  const done = terminal;
244703
245509
  if (opts.json) {
244704
- printJson3(done);
245510
+ printJson4(done);
244705
245511
  return;
244706
245512
  }
244707
245513
  const created = done.created ?? 0;
@@ -244719,7 +245525,7 @@ skip in CI). Folder layout reference: \`packages/cli/src/skill/reference/dataset
244719
245525
  }
244720
245526
  } else {
244721
245527
  error2(`Import response had unexpected terminal phase: ${terminal.phase}`);
244722
- printJson3(terminal);
245528
+ printJson4(terminal);
244723
245529
  process.exit(1);
244724
245530
  }
244725
245531
  }));
@@ -244779,7 +245585,7 @@ exclusive. To attach files without a dataset folder, pass ingress refs in JSON:
244779
245585
  const { client, workflowId } = await buildClientForWorkflow(workflow, opts);
244780
245586
  const result = await client.post(`/v1/automations/${workflowId}/examples`, body);
244781
245587
  if (opts.json) {
244782
- printJson3(result);
245588
+ printJson4(result);
244783
245589
  return;
244784
245590
  }
244785
245591
  success(`Created example ${ui.bold(opts.name)} (${result.id}) in ${ui.bold(workflowId)}`);
@@ -244805,7 +245611,7 @@ exclusive. To attach files without a dataset folder, pass ingress refs in JSON:
244805
245611
  const { client, workflowId } = await buildClientForWorkflow(workflow, opts);
244806
245612
  const result = await client.patch(`/v1/automations/${workflowId}/examples/${encodeURIComponent(exampleId)}`, body);
244807
245613
  if (opts.json) {
244808
- printJson3(result);
245614
+ printJson4(result);
244809
245615
  return;
244810
245616
  }
244811
245617
  const fields = Object.keys(body).join(", ");
@@ -244819,7 +245625,7 @@ exclusive. To attach files without a dataset folder, pass ingress refs in JSON:
244819
245625
  const { client, workflowId } = await buildClientForWorkflow(workflow, opts);
244820
245626
  const deleted = await client.delete(`/v1/automations/${workflowId}/examples/${encodeURIComponent(exampleId)}`);
244821
245627
  if (opts.json) {
244822
- printJson3(deleted);
245628
+ printJson4(deleted);
244823
245629
  return;
244824
245630
  }
244825
245631
  success(`Deleted example ${ui.bold(deleted.name ?? exampleId)} ${ui.dim(`(${exampleId})`)} from ${ui.bold(workflowId)}`);
@@ -244829,7 +245635,7 @@ exclusive. To attach files without a dataset folder, pass ingress refs in JSON:
244829
245635
  const { client, workflowId } = await buildClientForWorkflow(workflow, opts);
244830
245636
  const row = await client.get(`/v1/automations/${workflowId}/examples/${encodeURIComponent(exampleId)}`);
244831
245637
  if (opts.json) {
244832
- printJson3(row);
245638
+ printJson4(row);
244833
245639
  return;
244834
245640
  }
244835
245641
  renderExampleHuman(row);
@@ -244956,7 +245762,7 @@ returns immediately with \`{ batchId, total }\`; poll
244956
245762
  const total = start.runCount ?? start.total ?? 0;
244957
245763
  if (!opts.wait) {
244958
245764
  if (opts.json) {
244959
- printJson3({ ...start, batchId: experimentId, total });
245765
+ printJson4({ ...start, batchId: experimentId, total });
244960
245766
  return;
244961
245767
  }
244962
245768
  success(`Started experiment ${ui.bold(experimentId)} ${ui.dim(`(${total} run${total === 1 ? "" : "s"} queued)`)}`);
@@ -244970,7 +245776,7 @@ returns immediately with \`{ batchId, total }\`; poll
244970
245776
  const status = await client.get(`/v1/automations/${workflowId}/experiments/${experimentId}`);
244971
245777
  if (status.status === "completed") {
244972
245778
  if (opts.json) {
244973
- printJson3({
245779
+ printJson4({
244974
245780
  ...status,
244975
245781
  batchId: experimentId,
244976
245782
  total: status.runCount ?? status.total
@@ -244990,7 +245796,7 @@ returns immediately with \`{ batchId, total }\`; poll
244990
245796
  }
244991
245797
  if (Date.now() >= deadline) {
244992
245798
  if (opts.json) {
244993
- printJson3({
245799
+ printJson4({
244994
245800
  ...status,
244995
245801
  batchId: experimentId,
244996
245802
  total: status.runCount ?? status.total
@@ -245030,12 +245836,12 @@ returns immediately with \`{ batchId, total }\`; poll
245030
245836
  const summary = summarizeExperimentExecutions(execs);
245031
245837
  if (execs.length === 0) {
245032
245838
  if (opts.json)
245033
- printJson3({ ...result, summary: rollupForJson(summary) });
245839
+ printJson4({ ...result, summary: rollupForJson(summary) });
245034
245840
  error2(`Experiment ${batchId} still has no executions after retrying — check the batch id.`);
245035
245841
  process.exit(1);
245036
245842
  }
245037
245843
  if (opts.json) {
245038
- printJson3({ ...result, summary: rollupForJson(summary) });
245844
+ printJson4({ ...result, summary: rollupForJson(summary) });
245039
245845
  return;
245040
245846
  }
245041
245847
  if (opts.short) {
@@ -245067,7 +245873,7 @@ returns immediately with \`{ batchId, total }\`; poll
245067
245873
  maxWait: opts.maxWait,
245068
245874
  onTerminal: (result, summary) => {
245069
245875
  if (wantPayload) {
245070
- printJson3({ ...result, summary: rollupForJson(summary) });
245876
+ printJson4({ ...result, summary: rollupForJson(summary) });
245071
245877
  } else {
245072
245878
  process.stderr.write(`${ui.dim(`use --include payload (or --json) for the full per-execution snapshot`)}
245073
245879
  `);
@@ -245075,7 +245881,7 @@ returns immediately with \`{ batchId, total }\`; poll
245075
245881
  },
245076
245882
  onDeadline: (result, summary) => {
245077
245883
  if (wantPayload)
245078
- printJson3({ ...result, summary: rollupForJson(summary) });
245884
+ printJson4({ ...result, summary: rollupForJson(summary) });
245079
245885
  }
245080
245886
  });
245081
245887
  }));
@@ -245099,7 +245905,7 @@ Behavior:
245099
245905
  const { client, workflowId } = await buildClientForWorkflow(workflow, opts);
245100
245906
  const result = await client.post(`/v1/automations/${workflowId}/experiments/${batchId}/cancel`);
245101
245907
  if (opts.json) {
245102
- printJson3(result);
245908
+ printJson4(result);
245103
245909
  return;
245104
245910
  }
245105
245911
  const c = result.counts;
@@ -245173,7 +245979,7 @@ batches must belong to the same workflow within the caller's tenant.
245173
245979
  if (!Number.isFinite(threshold) || threshold < 0) {
245174
245980
  throw new Error("--regression-threshold must be a non-negative number");
245175
245981
  }
245176
- const client = buildClient3(opts);
245982
+ const client = buildClient4(opts);
245177
245983
  if (opts.outputs) {
245178
245984
  const [outputsA, outputsB] = await Promise.all([
245179
245985
  fetchExperimentOutputs(client, batchIdA),
@@ -245189,7 +245995,7 @@ batches must belong to the same workflow within the caller's tenant.
245189
245995
  rowsB: outputsB.rows
245190
245996
  });
245191
245997
  if (opts.json)
245192
- printJson3(outputDiff);
245998
+ printJson4(outputDiff);
245193
245999
  else
245194
246000
  renderExperimentOutputDiffHuman(outputDiff);
245195
246001
  return;
@@ -245207,7 +246013,7 @@ batches must belong to the same workflow within the caller's tenant.
245207
246013
  regressionThreshold: threshold
245208
246014
  });
245209
246015
  if (opts.json) {
245210
- printJson3(diff);
246016
+ printJson4(diff);
245211
246017
  return;
245212
246018
  }
245213
246019
  renderBatchDiffHuman(diff);
@@ -245245,7 +246051,7 @@ Behavior:
245245
246051
  const dest = opts.pull ? opts.pullOnComplete ?? `./results-${batchId}.${opts.format}` : null;
245246
246052
  if (dest) {
245247
246053
  const dir = path18.dirname(dest);
245248
- if (!existsSync22(dir)) {
246054
+ if (!existsSync23(dir)) {
245249
246055
  error2(`Destination directory does not exist: ${dir}. Create it first or pass a path under an existing directory.`);
245250
246056
  process.exit(2);
245251
246057
  }
@@ -245492,7 +246298,7 @@ sent to the server is replaced with \`templateId\` + \`templateRevisionId\`.
245492
246298
  const result = await client.post(automationVersionsPath(workflowId), body).catch((err) => rethrowAfterTemplateCleanup(client, created, err));
245493
246299
  await finalizeCreatedWorkspaceTemplates(client, created);
245494
246300
  if (opts.json) {
245495
- printJson3(withLocalTemplates(result, resolvedTemplates));
246301
+ printJson4(withLocalTemplates(result, resolvedTemplates));
245496
246302
  return;
245497
246303
  }
245498
246304
  const id = typeof result.id === "string" ? result.id : "?";
@@ -245515,7 +246321,7 @@ restore HEAD) return 404 — create a tagged copy first.
245515
246321
  const { client, workflowId } = await buildClientForWorkflow(workflow, opts);
245516
246322
  const result = await client.post(automationVersionsPath(workflowId, `/${encodeURIComponent(versionId)}/promote`));
245517
246323
  if (opts.json) {
245518
- printJson3(result);
246324
+ printJson4(result);
245519
246325
  return;
245520
246326
  }
245521
246327
  const label = formatWorkflowVersionLabel(result.version);
@@ -245538,7 +246344,7 @@ promoted until you create a tagged copy.
245538
246344
  const body = opts.message ? { message: opts.message } : {};
245539
246345
  const result = await client.post(automationVersionsPath(workflowId, `/${encodeURIComponent(versionId)}/restore`), body);
245540
246346
  if (opts.json) {
245541
- printJson3(result);
246347
+ printJson4(result);
245542
246348
  return;
245543
246349
  }
245544
246350
  const id = typeof result.id === "string" ? result.id : "?";
@@ -245787,7 +246593,7 @@ var HELP_GROUPS = [
245787
246593
  {
245788
246594
  title: "Authenticate",
245789
246595
  description: "Profiles in ~/.config/eigenpal/credentials.json",
245790
- commands: ["auth", "status", "models"]
246596
+ commands: ["auth", "status", "models", "email-servers"]
245791
246597
  },
245792
246598
  {
245793
246599
  title: "Workflows",
@@ -246015,6 +246821,7 @@ authCmd.command("use [profile]").description("Switch the active profile (persist
246015
246821
  registerWorkflowCommands(program2);
246016
246822
  registerAgentCommands(program2);
246017
246823
  registerModelsCommands(program2);
246824
+ registerEmailServersCommands(program2);
246018
246825
  registerRunCommands(program2);
246019
246826
  registerRunsCommands(program2);
246020
246827
  registerGitCommands(program2);