@eigenpal/cli 0.5.9 → 0.5.11

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/CHANGELOG.md CHANGED
@@ -1,5 +1,17 @@
1
1
  # @eigenpal/cli
2
2
 
3
+ ## 0.5.11
4
+
5
+ ### Patch Changes
6
+
7
+ - 2958f4d: Fix Git-backed source smoke-test polish: hidden `git show` and `git sync` now accept bare agent slugs, and workflow scaffolds use the current `triggerMethods` YAML shape.
8
+
9
+ ## 0.5.10
10
+
11
+ ### Patch Changes
12
+
13
+ - aee7e0c: Add hidden Git source commands for editing trigger policy and encrypted secrets.
14
+
3
15
  ## 0.5.9
4
16
 
5
17
  ### Major Changes
package/dist/cli.js CHANGED
@@ -68021,7 +68021,63 @@ var init_eval = __esm(() => {
68021
68021
  init_workflow_tool_metadata();
68022
68022
  });
68023
68023
 
68024
+ // ../types/src/git-source/cutover.ts
68025
+ function resolveAgentSourceCutover(settings) {
68026
+ const parsed = AgentSourceCutoverSettingsSchema.safeParse(settings ?? {});
68027
+ if (!parsed.success)
68028
+ return { mode: "legacy", reason: "invalid_settings" };
68029
+ const agents = parsed.data.gitBackedSource?.agents;
68030
+ if (!agents)
68031
+ return { mode: "legacy", reason: "settings_missing" };
68032
+ if (agents.migrationState === "rolled_back")
68033
+ return { mode: "legacy", reason: "rolled_back" };
68034
+ if (agents.runtime !== "git")
68035
+ return { mode: "legacy", reason: "runtime_legacy" };
68036
+ if (agents.migrationState !== "cutover") {
68037
+ return { mode: "legacy", reason: "migration_not_cutover" };
68038
+ }
68039
+ return { mode: "git", reason: "cutover_enabled" };
68040
+ }
68041
+ function isGitBackedAgentSourceEnabled(settings) {
68042
+ return resolveAgentSourceCutover(settings).mode === "git";
68043
+ }
68044
+ var AgentSourceRuntimeModeSchema, AgentSourceMigrationStateSchema, AgentSourceCutoverSettingsSchema;
68045
+ var init_cutover = __esm(() => {
68046
+ init_zod();
68047
+ AgentSourceRuntimeModeSchema = exports_external.enum(["legacy", "git"]);
68048
+ AgentSourceMigrationStateSchema = exports_external.enum([
68049
+ "disabled",
68050
+ "shadow",
68051
+ "validated",
68052
+ "cutover",
68053
+ "rolled_back"
68054
+ ]);
68055
+ AgentSourceCutoverSettingsSchema = exports_external.object({
68056
+ gitBackedSource: exports_external.object({
68057
+ agents: exports_external.object({
68058
+ runtime: AgentSourceRuntimeModeSchema.optional(),
68059
+ migrationState: AgentSourceMigrationStateSchema.optional(),
68060
+ legacySourceRetained: exports_external.boolean().optional(),
68061
+ rollbackReason: exports_external.string().optional()
68062
+ }).passthrough().optional()
68063
+ }).passthrough().optional()
68064
+ }).passthrough();
68065
+ });
68066
+
68024
68067
  // ../types/src/git-source/grammar.ts
68068
+ function parseAutomationTarget(target) {
68069
+ const parsed = AutomationTargetSchema.parse(target);
68070
+ const [rawPackageName, rawRef] = parsed.split("@");
68071
+ const packagePath = dottedPackageNameToPath(rawPackageName);
68072
+ const [type, ...slugParts] = packagePath.split("/");
68073
+ return {
68074
+ packageName: DottedPackageNameSchema.parse(rawPackageName),
68075
+ packagePath,
68076
+ type,
68077
+ slug: slugParts.join("/"),
68078
+ ref: SourceVersionRefSchema.parse(rawRef ?? "latest")
68079
+ };
68080
+ }
68025
68081
  function pathToDottedPackageName(path2) {
68026
68082
  const parsed = SourcePackagePathSchema.parse(path2);
68027
68083
  return DottedPackageNameSchema.parse(parsed.split("/").join("."));
@@ -68353,7 +68409,16 @@ var init_manifests = __esm(() => {
68353
68409
  api: exports_external.boolean().optional(),
68354
68410
  email: exports_external.object({
68355
68411
  enabled: exports_external.boolean().default(true),
68356
- aliases: exports_external.array(exports_external.string().email()).default([])
68412
+ aliases: exports_external.array(exports_external.union([
68413
+ exports_external.string().includes("@"),
68414
+ exports_external.object({
68415
+ address: exports_external.string().includes("@"),
68416
+ allowlist: exports_external.array(exports_external.string()).default([]),
68417
+ replyConfig: exports_external.record(exports_external.string(), exports_external.unknown()).default({}),
68418
+ requireSenderAuth: exports_external.boolean().default(true),
68419
+ enabled: exports_external.boolean().optional()
68420
+ }).strict()
68421
+ ])).default([])
68357
68422
  }).strict().optional()
68358
68423
  }).strict();
68359
68424
  CommonPackageManifestFields = {
@@ -68422,10 +68487,63 @@ var init_manifests = __esm(() => {
68422
68487
  SOURCE_TEMPLATE_FILE_PATTERN = /\.(?:docx|xlsx)$/i;
68423
68488
  });
68424
68489
 
68490
+ // ../types/src/git-source/secrets.ts
68491
+ var SOURCE_SECRETS_FILENAME = "secrets.enc.yaml", SecretNameSchema, Base64LikeSchema, EncryptedSecretValueSchema, SourceSecretEntrySchema, SourceSecretsFileSchema;
68492
+ var init_secrets = __esm(() => {
68493
+ init_zod();
68494
+ init_manifests();
68495
+ SecretNameSchema = exports_external.string().regex(/^[A-Z][A-Z0-9_]*$/, "Secret names must be uppercase env-style identifiers");
68496
+ Base64LikeSchema = exports_external.string().min(1).regex(/^[A-Za-z0-9+/=_-]+$/, {
68497
+ message: "Encrypted secret fields must be encoded strings"
68498
+ });
68499
+ EncryptedSecretValueSchema = exports_external.object({
68500
+ algorithm: exports_external.literal("aes-256-gcm"),
68501
+ keyId: exports_external.string().min(1),
68502
+ nonce: Base64LikeSchema,
68503
+ ciphertext: Base64LikeSchema,
68504
+ tag: Base64LikeSchema
68505
+ }).strict();
68506
+ SourceSecretEntrySchema = exports_external.object({
68507
+ description: exports_external.string().optional(),
68508
+ encrypted: EncryptedSecretValueSchema.optional()
68509
+ }).passthrough().superRefine((entry, ctx) => {
68510
+ const raw = entry;
68511
+ if ("value" in raw || "plaintext" in raw || "secret" in raw) {
68512
+ ctx.addIssue({
68513
+ code: "custom",
68514
+ message: "secrets.enc.yaml must not contain plaintext secret values"
68515
+ });
68516
+ }
68517
+ if (!raw.encrypted) {
68518
+ ctx.addIssue({
68519
+ code: "custom",
68520
+ path: ["encrypted"],
68521
+ message: "Encrypted secret values are required"
68522
+ });
68523
+ }
68524
+ const extraKeys = Object.keys(raw).filter((key) => key !== "description" && key !== "encrypted");
68525
+ for (const key of extraKeys) {
68526
+ if (key === "value" || key === "plaintext" || key === "secret")
68527
+ continue;
68528
+ ctx.addIssue({
68529
+ code: "custom",
68530
+ path: [key],
68531
+ message: `Unknown secret metadata field: ${key}`
68532
+ });
68533
+ }
68534
+ });
68535
+ SourceSecretsFileSchema = exports_external.object({
68536
+ schemaVersion: SourceManifestSchemaVersionSchema,
68537
+ secrets: exports_external.record(SecretNameSchema, SourceSecretEntrySchema)
68538
+ }).strict();
68539
+ });
68540
+
68425
68541
  // ../types/src/git-source/index.ts
68426
68542
  var init_git_source = __esm(() => {
68543
+ init_cutover();
68427
68544
  init_grammar();
68428
68545
  init_manifests();
68546
+ init_secrets();
68429
68547
  });
68430
68548
 
68431
68549
  // ../types/src/storage/paths.ts
@@ -68729,11 +68847,13 @@ __export(exports_src, {
68729
68847
  runInputKey: () => runInputKey,
68730
68848
  rootS3Path: () => rootS3Path,
68731
68849
  resolveEffectiveMimeType: () => resolveEffectiveMimeType,
68850
+ resolveAgentSourceCutover: () => resolveAgentSourceCutover,
68732
68851
  requiresSpecializedParser: () => requiresSpecializedParser,
68733
68852
  pathToDottedPackageName: () => pathToDottedPackageName,
68734
68853
  parseStepType: () => parseStepType,
68735
68854
  parseReleaseTag: () => parseReleaseTag,
68736
68855
  parseFileKey: () => parseFileKey,
68856
+ parseAutomationTarget: () => parseAutomationTarget,
68737
68857
  noopTracingContext: () => noopTracingContext,
68738
68858
  mapOCRAttributes: () => mapOCRAttributes,
68739
68859
  mapLLMAttributes: () => mapLLMAttributes,
@@ -68748,6 +68868,7 @@ __export(exports_src, {
68748
68868
  isOutputSchemaUnknown: () => isOutputSchemaUnknown,
68749
68869
  isNonSuccessTerminalExecutionStatus: () => isNonSuccessTerminalExecutionStatus,
68750
68870
  isLocalAgentResourcePath: () => isLocalAgentResourcePath,
68871
+ isGitBackedAgentSourceEnabled: () => isGitBackedAgentSourceEnabled,
68751
68872
  isFilePathDescriptor: () => isFilePathDescriptor,
68752
68873
  isFileOutput: () => isFileOutput,
68753
68874
  hasTriggerMethod: () => hasTriggerMethod,
@@ -68863,6 +68984,7 @@ __export(exports_src, {
68863
68984
  SpanKindMap: () => SpanKindMap,
68864
68985
  SpanKind: () => import_api.SpanKind,
68865
68986
  SourceVersionRefSchema: () => SourceVersionRefSchema,
68987
+ SourceSecretsFileSchema: () => SourceSecretsFileSchema,
68866
68988
  SourcePackageTypeSchema: () => SourcePackageTypeSchema,
68867
68989
  SourcePackageSegmentSchema: () => SourcePackageSegmentSchema,
68868
68990
  SourcePackagePathSchema: () => SourcePackagePathSchema,
@@ -68872,6 +68994,7 @@ __export(exports_src, {
68872
68994
  SharedResourcePackageManifestSchema: () => SharedResourcePackageManifestSchema,
68873
68995
  SharedEvaluatorReferenceSchema: () => SharedEvaluatorReferenceSchema,
68874
68996
  SharedEvaluatorCompositionItemSchema: () => SharedEvaluatorCompositionItemSchema,
68997
+ SecretNameSchema: () => SecretNameSchema,
68875
68998
  ScopeStackSchema: () => ScopeStackSchema,
68876
68999
  ScopeEntryTypeSchema: () => ScopeEntryTypeSchema,
68877
69000
  ScopeEntrySchema: () => ScopeEntrySchema,
@@ -68880,6 +69003,7 @@ __export(exports_src, {
68880
69003
  STEP_EXECUTION_STATUSES: () => STEP_EXECUTION_STATUSES,
68881
69004
  SOURCE_VERSION_RANGE_PATTERN: () => SOURCE_VERSION_RANGE_PATTERN,
68882
69005
  SOURCE_SEMVER_PATTERN: () => SOURCE_SEMVER_PATTERN,
69006
+ SOURCE_SECRETS_FILENAME: () => SOURCE_SECRETS_FILENAME,
68883
69007
  SOURCE_PACKAGE_SEGMENT_PATTERN: () => SOURCE_PACKAGE_SEGMENT_PATTERN,
68884
69008
  SOURCE_MANIFEST_FILENAME: () => SOURCE_MANIFEST_FILENAME,
68885
69009
  SOURCE_COMMIT_SHA_PATTERN: () => SOURCE_COMMIT_SHA_PATTERN,
@@ -68963,6 +69087,7 @@ __export(exports_src, {
68963
69087
  EvalOverridesSchema: () => EvalOverridesSchema,
68964
69088
  EvalExampleMetaSchema: () => EvalExampleMetaSchema,
68965
69089
  EvalConfigYamlSchema: () => EvalConfigYamlSchema,
69090
+ EncryptedSecretValueSchema: () => EncryptedSecretValueSchema,
68966
69091
  EmailTriggerMethodSchema: () => EmailTriggerMethodSchema,
68967
69092
  Eigenpal: () => Eigenpal,
68968
69093
  EXECUTION_TYPES: () => EXECUTION_TYPES,
@@ -69025,6 +69150,9 @@ __export(exports_src, {
69025
69150
  AiParseConfigSchema: () => AiParseConfigSchema,
69026
69151
  AiExtractOutputSchema: () => AiExtractOutputSchema,
69027
69152
  AiExtractConfigSchema: () => AiExtractConfigSchema,
69153
+ AgentSourceRuntimeModeSchema: () => AgentSourceRuntimeModeSchema,
69154
+ AgentSourceMigrationStateSchema: () => AgentSourceMigrationStateSchema,
69155
+ AgentSourceCutoverSettingsSchema: () => AgentSourceCutoverSettingsSchema,
69028
69156
  AgentPackageManifestSchema: () => AgentPackageManifestSchema,
69029
69157
  ActionTypeValue: () => ActionTypeValue,
69030
69158
  ActionTypeSchema: () => ActionTypeSchema,
@@ -181610,7 +181738,7 @@ import { fileURLToPath as fileURLToPath6 } from "url";
181610
181738
  // package.json
181611
181739
  var package_default = {
181612
181740
  name: "@eigenpal/cli",
181613
- version: "0.5.9",
181741
+ version: "0.5.11",
181614
181742
  description: "Eigenpal CLI — author and run document workflows from your terminal. Agent-ready.",
181615
181743
  keywords: [
181616
181744
  "eigenpal",
@@ -184117,7 +184245,7 @@ init_src();
184117
184245
  init_zod();
184118
184246
  var import_yaml2 = __toESM(require_dist(), 1);
184119
184247
  import { spawnSync as spawnSync2 } from "node:child_process";
184120
- import { createHash as createHash2 } from "node:crypto";
184248
+ import { createCipheriv, createHash as createHash2, randomBytes } from "node:crypto";
184121
184249
  import {
184122
184250
  existsSync as existsSync3,
184123
184251
  mkdirSync as mkdirSync2,
@@ -184280,6 +184408,9 @@ function listRelativeFiles(dir) {
184280
184408
  function readYamlFile(filePath) {
184281
184409
  return import_yaml2.default.parse(readFileSync3(filePath, "utf8"));
184282
184410
  }
184411
+ function writeYamlFile(filePath, value) {
184412
+ writeFileSync2(filePath, import_yaml2.default.stringify(value));
184413
+ }
184283
184414
  function packageManifestExists(gitRoot, packagePath) {
184284
184415
  return existsSync3(path2.join(gitRoot, packagePath, "eigenpal.yaml"));
184285
184416
  }
@@ -184290,6 +184421,28 @@ function releaseTagExists(gitRoot, packagePath, version2) {
184290
184421
  function readPackageManifest(packageRoot) {
184291
184422
  return SourcePackageManifestSchema.parse(readYamlFile(path2.join(packageRoot, "eigenpal.yaml")));
184292
184423
  }
184424
+ function requirePackageContext(opts = {}) {
184425
+ const context = resolveGitSourceContext(opts);
184426
+ if (!context.gitRoot || !context.packageRoot || !context.packagePath) {
184427
+ throw new Error("Run this command inside a source package, or pass --dir.");
184428
+ }
184429
+ return {
184430
+ gitRoot: context.gitRoot,
184431
+ packageRoot: context.packageRoot,
184432
+ packagePath: context.packagePath
184433
+ };
184434
+ }
184435
+ function readMutablePackageManifest(packageRoot) {
184436
+ const manifest = readYamlFile(path2.join(packageRoot, "eigenpal.yaml"));
184437
+ if (!manifest || typeof manifest !== "object" || Array.isArray(manifest)) {
184438
+ throw new Error("Package eigenpal.yaml must be a YAML object.");
184439
+ }
184440
+ return manifest;
184441
+ }
184442
+ function writeMutablePackageManifest(packageRoot, manifest) {
184443
+ SourcePackageManifestSchema.parse(manifest);
184444
+ writeYamlFile(path2.join(packageRoot, "eigenpal.yaml"), manifest);
184445
+ }
184293
184446
  function parsePackageRef(input) {
184294
184447
  const [rawPackage, rawRef, extra] = input.split("@");
184295
184448
  if (!rawPackage || extra !== undefined) {
@@ -184631,6 +184784,11 @@ function checkRepoVersion(gitRoot, mutation) {
184631
184784
  function resolvePackagePath(target) {
184632
184785
  return target.includes("/") ? SourcePackagePathSchema.parse(target) : dottedPackageNameToPath(DottedPackageNameSchema.parse(target));
184633
184786
  }
184787
+ function resolveAgentPackagePath(target) {
184788
+ if (target.includes("/") || target.includes("."))
184789
+ return resolvePackagePath(target);
184790
+ return SourcePackagePathSchema.parse(`agents/${target}`);
184791
+ }
184634
184792
  function isAutomationPackagePath(packagePath) {
184635
184793
  return packagePath.startsWith("agents/") || packagePath.startsWith("workflows/");
184636
184794
  }
@@ -184976,7 +185134,7 @@ async function list(opts) {
184976
185134
  }
184977
185135
  }
184978
185136
  async function show(target, opts) {
184979
- const packagePath = resolvePackagePath(target);
185137
+ const packagePath = resolveAgentPackagePath(target);
184980
185138
  const slug = packagePath.replace(/^agents\//, "");
184981
185139
  const client = new ApiClient(resolveConfig(opts));
184982
185140
  const payload = await client.get(`/api/v1/agents/${encodeURIComponent(slug)}`, {
@@ -185089,7 +185247,7 @@ async function sync(target, opts) {
185089
185247
  if (target?.includes("@")) {
185090
185248
  throw new Error("Sync always uses latest; do not pass a versioned target.");
185091
185249
  }
185092
- const packagePath = target ? resolvePackagePath(target) : context.packagePath;
185250
+ const packagePath = target ? resolveAgentPackagePath(target) : context.packagePath;
185093
185251
  if (!packagePath) {
185094
185252
  throw new Error("Pass an automation target or run sync inside a source package.");
185095
185253
  }
@@ -185098,6 +185256,144 @@ async function sync(target, opts) {
185098
185256
  }
185099
185257
  await syncLatestAutomation(new ApiClient(resolveConfig(opts)), packagePath);
185100
185258
  }
185259
+ function setEmailTriggerAlias(email3, opts) {
185260
+ const context = requirePackageContext(opts);
185261
+ const manifest = readMutablePackageManifest(context.packageRoot);
185262
+ const triggers = { ...manifest.triggers ?? {} };
185263
+ const emailConfig = { ...triggers.email ?? {} };
185264
+ const aliases = Array.isArray(emailConfig.aliases) ? [...emailConfig.aliases] : [];
185265
+ const nextAlias = {
185266
+ address: email3,
185267
+ enabled: !opts.disabled,
185268
+ allowlist: opts.allow ?? [],
185269
+ replyConfig: {
185270
+ ...opts.replyOn ? { on: opts.replyOn } : {},
185271
+ ...opts.replyMode ? { mode: opts.replyMode } : {}
185272
+ },
185273
+ requireSenderAuth: opts.requireSenderAuth ?? true
185274
+ };
185275
+ const filtered = aliases.filter((alias) => typeof alias === "string" ? alias.toLowerCase() !== email3.toLowerCase() : alias.address?.toLowerCase() !== email3.toLowerCase());
185276
+ manifest.triggers = {
185277
+ ...triggers,
185278
+ email: { ...emailConfig, enabled: true, aliases: [...filtered, nextAlias] }
185279
+ };
185280
+ writeMutablePackageManifest(context.packageRoot, manifest);
185281
+ success2(`Updated email trigger ${ui.bold(email3)} in eigenpal.yaml.`);
185282
+ }
185283
+ function setApiTrigger(enabled, opts) {
185284
+ const context = requirePackageContext(opts);
185285
+ const manifest = readMutablePackageManifest(context.packageRoot);
185286
+ const triggers = { ...manifest.triggers ?? {} };
185287
+ manifest.triggers = { ...triggers, api: enabled };
185288
+ writeMutablePackageManifest(context.packageRoot, manifest);
185289
+ success2(`${enabled ? "Enabled" : "Disabled"} API trigger in eigenpal.yaml.`);
185290
+ }
185291
+ function encryptLocalSecret(input) {
185292
+ if (input.key.byteLength !== 32)
185293
+ throw new Error("Secret encryption key must be 32 bytes.");
185294
+ const nonce = randomBytes(12);
185295
+ const cipher = createCipheriv("aes-256-gcm", input.key, nonce);
185296
+ cipher.setAAD(Buffer.from(JSON.stringify({
185297
+ keyId: input.keyId,
185298
+ organizationId: input.organizationId,
185299
+ sourcePath: input.sourcePath,
185300
+ secretName: input.secretName
185301
+ })));
185302
+ const ciphertext = Buffer.concat([cipher.update(input.plaintext, "utf8"), cipher.final()]);
185303
+ return {
185304
+ algorithm: "aes-256-gcm",
185305
+ keyId: input.keyId,
185306
+ nonce: nonce.toString("base64url"),
185307
+ ciphertext: ciphertext.toString("base64url"),
185308
+ tag: cipher.getAuthTag().toString("base64url")
185309
+ };
185310
+ }
185311
+ function readSecretsFile(packageRoot) {
185312
+ const filePath = path2.join(packageRoot, SOURCE_SECRETS_FILENAME);
185313
+ if (!existsSync3(filePath))
185314
+ return { schemaVersion: 1, secrets: {} };
185315
+ return SourceSecretsFileSchema.parse(readYamlFile(filePath));
185316
+ }
185317
+ function writeSecretsFile(packageRoot, value) {
185318
+ const secretsFile = SourceSecretsFileSchema.parse(value);
185319
+ writeYamlFile(path2.join(packageRoot, SOURCE_SECRETS_FILENAME), secretsFile);
185320
+ }
185321
+ async function readSecretInput(opts) {
185322
+ const selected = [opts.stdin, opts.valueFile].filter(Boolean).length;
185323
+ if (selected > 1)
185324
+ throw new Error("Pass only one of --stdin or --value-file.");
185325
+ if (opts.stdin)
185326
+ return readFileSync3(0, "utf8").replace(/\n$/, "");
185327
+ if (opts.valueFile)
185328
+ return readFileSync3(opts.valueFile, "utf8").replace(/\n$/, "");
185329
+ if (process.stdin.isTTY && process.stdout.isTTY) {
185330
+ const { password, isCancel, cancel } = await Promise.resolve().then(() => (init_dist4(), exports_dist));
185331
+ const answer = await password({ message: "Secret value" });
185332
+ if (isCancel(answer)) {
185333
+ cancel("Cancelled");
185334
+ process.exit(1);
185335
+ }
185336
+ return String(answer);
185337
+ }
185338
+ throw new Error("Secret value input is required in noninteractive mode.");
185339
+ }
185340
+ async function setSecret(name, opts) {
185341
+ const context = requirePackageContext(opts);
185342
+ const sourcePath = `${context.packagePath}/${SOURCE_SECRETS_FILENAME}`;
185343
+ const secretsFile = readSecretsFile(context.packageRoot);
185344
+ const secrets = { ...secretsFile.secrets };
185345
+ secrets[name] = {
185346
+ ...opts.description ? { description: opts.description } : {},
185347
+ encrypted: encryptLocalSecret({
185348
+ plaintext: await readSecretInput(opts),
185349
+ keyId: opts.keyId,
185350
+ key: readSecretKeyFile(opts.keyFile),
185351
+ organizationId: opts.organizationId,
185352
+ sourcePath,
185353
+ secretName: name
185354
+ })
185355
+ };
185356
+ writeSecretsFile(context.packageRoot, { schemaVersion: 1, secrets });
185357
+ success2(`Encrypted ${ui.bold(name)} into secrets.enc.yaml.`);
185358
+ }
185359
+ function unsetSecret(name, opts) {
185360
+ const context = requirePackageContext(opts);
185361
+ const secretsFile = readSecretsFile(context.packageRoot);
185362
+ const secrets = { ...secretsFile.secrets };
185363
+ delete secrets[name];
185364
+ writeSecretsFile(context.packageRoot, { schemaVersion: 1, secrets });
185365
+ success2(`Removed ${ui.bold(name)} from secrets.enc.yaml.`);
185366
+ }
185367
+ async function importSecrets(envFile, opts) {
185368
+ const content = readFileSync3(envFile, "utf8");
185369
+ for (const line of content.split(/\r?\n/)) {
185370
+ const trimmed = line.trim();
185371
+ if (!trimmed || trimmed.startsWith("#"))
185372
+ continue;
185373
+ const idx = trimmed.indexOf("=");
185374
+ if (idx === -1)
185375
+ continue;
185376
+ const context = requirePackageContext(opts);
185377
+ const sourcePath = `${context.packagePath}/${SOURCE_SECRETS_FILENAME}`;
185378
+ const secretsFile = readSecretsFile(context.packageRoot);
185379
+ const secrets = { ...secretsFile.secrets };
185380
+ const name = trimmed.slice(0, idx);
185381
+ secrets[name] = {
185382
+ encrypted: encryptLocalSecret({
185383
+ plaintext: trimmed.slice(idx + 1),
185384
+ keyId: opts.keyId,
185385
+ key: readSecretKeyFile(opts.keyFile),
185386
+ organizationId: opts.organizationId,
185387
+ sourcePath,
185388
+ secretName: name
185389
+ })
185390
+ };
185391
+ writeSecretsFile(context.packageRoot, { schemaVersion: 1, secrets });
185392
+ }
185393
+ }
185394
+ function readSecretKeyFile(keyFile) {
185395
+ return Buffer.from(readFileSync3(keyFile, "utf8").trim(), "base64url");
185396
+ }
185101
185397
  async function install(packageRef, opts) {
185102
185398
  const config2 = resolveConfig(opts);
185103
185399
  const context = resolveGitSourceContext();
@@ -185401,6 +185697,16 @@ function parseReleaseVersion(value) {
185401
185697
  }
185402
185698
  return value;
185403
185699
  }
185700
+ function parseBoolean(value) {
185701
+ if (value === "true" || value === "enabled" || value === "on")
185702
+ return true;
185703
+ if (value === "false" || value === "disabled" || value === "off")
185704
+ return false;
185705
+ throw new InvalidArgumentError("Expected true/false, enabled/disabled, or on/off");
185706
+ }
185707
+ function collect2(value, previous) {
185708
+ return [...previous, value];
185709
+ }
185404
185710
  function parseType(value) {
185405
185711
  if (!["agent", "workflow"].includes(value))
185406
185712
  throw new InvalidArgumentError("type must be agent or workflow");
@@ -185431,6 +185737,14 @@ function registerGitCommands(program2) {
185431
185737
  addJsonFlag(withBaseUrl(git.command("versions <package>"))).description("List package release versions.").action(action(versions2));
185432
185738
  withBaseUrl(git.command("release")).description("Create and push a package release tag.").argument("<version>", "Version or bump level", parseReleaseVersion).argument("[dir]", "Package directory").addOption(new Option("-m, --message <message>", "Annotated tag message").makeOptionMandatory()).action(action(async (versionOrBump, dir, opts) => release(versionOrBump, dir, opts)));
185433
185739
  withBaseUrl(git.command("sync [automation]")).description("Sync an automation from the latest Git source release.").option("--dir <dir>", "Directory to inspect").action(action(sync));
185740
+ const trigger = git.command("trigger").description("Edit trigger policy in eigenpal.yaml.");
185741
+ trigger.command("api <enabled>").description("Enable or disable API trigger policy in eigenpal.yaml.").option("--dir <dir>", "Directory to inspect").action(action(async (enabled, opts) => setApiTrigger(parseBoolean(enabled), opts)));
185742
+ const triggerEmail = trigger.command("email").description("Edit email trigger policy.");
185743
+ triggerEmail.command("set <email>").description("Add or update an email trigger alias in eigenpal.yaml.").option("--dir <dir>", "Directory to inspect").option("--disabled", "Write the alias as disabled").option("--allow <entry>", "Allowed sender entry; repeatable", collect2, []).option("--reply-on <never|always>", "Reply behavior").option("--reply-mode <sender|all>", "Reply recipient mode").option("--no-require-sender-auth", "Disable sender-auth checks for this alias").action(action(async (email3, opts) => setEmailTriggerAlias(email3, opts)));
185744
+ const secret = git.command("secret").description("Edit encrypted secrets.enc.yaml.");
185745
+ secret.command("set <name>").description("Encrypt and set a secret value in secrets.enc.yaml.").option("--dir <dir>", "Directory to inspect").option("--stdin", "Read the secret value from stdin").option("--value-file <path>", "Read the secret value from a file").requiredOption("--key-id <id>", "Organization decrypt key id").requiredOption("--key-file <path>", "File containing the base64url-encoded organization key").requiredOption("--organization-id <id>", "Organization id for authenticated data").option("--description <text>", "Secret description").action(action(setSecret));
185746
+ secret.command("unset <name>").description("Remove a secret from secrets.enc.yaml.").option("--dir <dir>", "Directory to inspect").action(action(async (name, opts) => unsetSecret(name, opts)));
185747
+ secret.command("import <env-file>").description("Import KEY=value entries from an env file into secrets.enc.yaml.").option("--dir <dir>", "Directory to inspect").requiredOption("--key-id <id>", "Organization decrypt key id").requiredOption("--key-file <path>", "File containing the base64url-encoded organization key").requiredOption("--organization-id <id>", "Organization id for authenticated data").action(action(importSecrets));
185434
185748
  }
185435
185749
 
185436
185750
  // src/commands/init.ts
@@ -186029,15 +186343,15 @@ function pruneEmptyDirs(root) {
186029
186343
  if (!existsSync5(root))
186030
186344
  return;
186031
186345
  const stack = [];
186032
- const collect2 = (dir) => {
186346
+ const collect3 = (dir) => {
186033
186347
  for (const entry of readdirSync3(dir)) {
186034
186348
  const full = join3(dir, entry);
186035
186349
  if (lstatSync(full).isDirectory())
186036
- collect2(full);
186350
+ collect3(full);
186037
186351
  }
186038
186352
  stack.push(dir);
186039
186353
  };
186040
- collect2(root);
186354
+ collect3(root);
186041
186355
  for (const dir of stack) {
186042
186356
  try {
186043
186357
  if (readdirSync3(dir).length === 0)
@@ -3,7 +3,7 @@ version: 1.0.0
3
3
  description: Smallest possible workflow — echoes the input back through transform.script.
4
4
 
5
5
  triggerMethods:
6
- - api
6
+ - type: api
7
7
 
8
8
  inputs:
9
9
  - name: text
@@ -16,7 +16,7 @@ eigenpal workflow step-type get <type> # JSON Schema for one type's config + o
16
16
  name: extract-invoices # string, lowercase kebab/snake-case, unique within tenant
17
17
  version: 1.0.0 # bare semver `MAJOR.MINOR.PATCH`, no leading `v`
18
18
  description: Parse a PDF and extract invoice fields. # string, optional
19
- triggerMethods: [api] # array, ≥1 entry from: api | cron | email
19
+ triggerMethods: [{ type: api }] # array, ≥1 entry with type: api | manual | email
20
20
  inputs: [...] # array of input definitions (see below)
21
21
  steps: [...] # array of steps, executed in topological order
22
22
  output: {...} # object — the workflow's return shape
@@ -36,13 +36,13 @@ folder.
36
36
 
37
37
  ### `triggerMethods`
38
38
 
39
- Required. Each entry adds an invocation surface:
39
+ Required. Each entry is an object that adds an invocation surface:
40
40
 
41
- - `api` — the workflow can be called via REST or the CLI's `workflow execution run`
42
- - `cron` — scheduled. Add a sibling `cron: { schedule: "0 9 * * *", timezone: "UTC" }`
43
- - `email` — inbound email. Add a sibling `email: { subject?: ..., aliases?: [...] }`
41
+ - `{ type: api }` — the workflow can be called via REST or the CLI's `workflow execution run`
42
+ - `{ type: manual }` — the workflow can be started manually
43
+ - `{ type: email, whitelist?: ... }` — inbound email
44
44
 
45
- If `api` is missing, `eigenpal workflow execution run` and `workflow run` reject with a
45
+ If `{ type: api }` is missing, `eigenpal workflow execution run` rejects with a
46
46
  403 / "Workflow does not have API trigger enabled."
47
47
 
48
48
  ### `inputs`
@@ -4,9 +4,8 @@ description: Replace this with what your workflow does.
4
4
 
5
5
  # `triggerMethods` controls how this workflow can be invoked:
6
6
  # - api: workflow can be called via the REST API and CLI
7
- # - cron: workflow can be scheduled (set `cron` field below)
8
7
  triggerMethods:
9
- - api
8
+ - type: api
10
9
 
11
10
  # `inputs` declares the schema of arguments the workflow accepts. Each entry
12
11
  # becomes a top-level key on the call's `triggerInput` object. Use `file: true`
@@ -3,7 +3,7 @@ version: 1.0.0
3
3
  description: Parse a PDF and extract structured fields with an LLM.
4
4
 
5
5
  triggerMethods:
6
- - api
6
+ - type: api
7
7
 
8
8
  inputs:
9
9
  - name: document
@@ -3,7 +3,7 @@ version: 1.0.0
3
3
  description: Classify free-form text into one of a fixed set of labels.
4
4
 
5
5
  triggerMethods:
6
- - api
6
+ - type: api
7
7
 
8
8
  inputs:
9
9
  - name: text
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@eigenpal/cli",
3
- "version": "0.5.9",
3
+ "version": "0.5.11",
4
4
  "description": "Eigenpal CLI — author and run document workflows from your terminal. Agent-ready.",
5
5
  "keywords": [
6
6
  "eigenpal",