@seekrit/cli 1.8.0 → 1.9.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.
Files changed (2) hide show
  1. package/dist/index.js +188 -33
  2. package/package.json +2 -2
package/dist/index.js CHANGED
@@ -2561,7 +2561,8 @@ const SYNC_PROVIDER_KINDS = [
2561
2561
  "langgraph-platform",
2562
2562
  "azure-key-vault",
2563
2563
  "huggingface-spaces",
2564
- "openai-vault"
2564
+ "openai-vault",
2565
+ "claude-managed-agents"
2565
2566
  ];
2566
2567
  z.enum(SYNC_PROVIDER_KINDS);
2567
2568
  /**
@@ -2967,6 +2968,23 @@ const azureKeyVaultConnectionConfigSchema = z.object({
2967
2968
  const huggingfaceSpacesConnectionConfigSchema = z.object({ provider: z.literal("huggingface-spaces") });
2968
2969
  /** The wrapped credential is an OpenAI project API key with vault read/write access. */
2969
2970
  const openaiVaultConnectionConfigSchema = z.object({ provider: z.literal("openai-vault") });
2971
+ /**
2972
+ * Claude Managed Agents account scope — empty, for Hugging Face's reason.
2973
+ *
2974
+ * An Anthropic API key belongs to exactly one **workspace**, and vaults are
2975
+ * workspace-scoped: the key can reach every vault in its workspace and none
2976
+ * outside it. A vault ID is globally unique. So the key plus the destination is
2977
+ * the whole address, and the API's `anthropic-workspace-id` header — which
2978
+ * exists for credentials that span several workspaces — has nothing to select.
2979
+ *
2980
+ * There is no `baseUrl`, and adding one would not be enough. Bedrock, Vertex
2981
+ * AI, and Foundry do not offer Managed Agents at all. Claude Platform on AWS
2982
+ * does, at `aws-external-anthropic.{region}.api.aws` — but it authenticates
2983
+ * with SigV4 over an IAM credential, not an API key, so it is a different
2984
+ * credential shape and a different connector (one that would reuse
2985
+ * `lib/leases/aws-sigv4.ts`), not a different host for this one.
2986
+ */
2987
+ const claudeManagedAgentsConnectionConfigSchema = z.object({ provider: z.literal("claude-managed-agents") });
2970
2988
  const syncConnectionConfigSchema = z.discriminatedUnion("provider", [
2971
2989
  vercelConnectionConfigSchema,
2972
2990
  cloudflareWorkersConnectionConfigSchema,
@@ -2987,7 +3005,8 @@ const syncConnectionConfigSchema = z.discriminatedUnion("provider", [
2987
3005
  langgraphPlatformConnectionConfigSchema,
2988
3006
  azureKeyVaultConnectionConfigSchema,
2989
3007
  huggingfaceSpacesConnectionConfigSchema,
2990
- openaiVaultConnectionConfigSchema
3008
+ openaiVaultConnectionConfigSchema,
3009
+ claudeManagedAgentsConnectionConfigSchema
2991
3010
  ]);
2992
3011
  /** Vercel's three deployment targets. A binding writes to one or more. */
2993
3012
  const VERCEL_TARGETS = [
@@ -3818,6 +3837,85 @@ const openaiVaultDestinationSchema = z.object({
3818
3837
  vaultId: z.string().trim().regex(/^vault_[A-Za-z0-9_-]+$/, "must be an OpenAI vault ID"),
3819
3838
  allowedHosts: z.array(z.string().trim().toLowerCase().max(253).regex(/^(?=.{1,253}$)[a-z0-9](?:[a-z0-9-]*[a-z0-9])?(?:\.[a-z0-9](?:[a-z0-9-]*[a-z0-9])?)+$/, "must be an exact hostname without scheme, port, path, or wildcard")).min(1).max(100).refine((hosts) => new Set(hosts).size === hosts.length, "hostnames must be unique")
3820
3839
  });
3840
+ /**
3841
+ * A vault ID as the Claude Console and API show it: `vlt_` and an opaque
3842
+ * alphanumeric tail. Held to that shape because the habitual slip — pasting the
3843
+ * vault's display name — is a 404 from inside an alarm, which says nothing
3844
+ * about which half of the address was wrong.
3845
+ */
3846
+ const claudeVaultIdSchema = z.string().trim().regex(/^vlt_[A-Za-z0-9]{1,128}$/, "must be a vault ID, e.g. vlt_01ABC… — not its display name");
3847
+ /** Ceiling on per-name host rules; a vault itself holds at most 20 credentials. */
3848
+ const CLAUDE_VAULT_MAX_HOST_RULES = 100;
3849
+ /** A hostname of two or more labels whose last label starts with a letter. */
3850
+ const CLAUDE_VAULT_HOSTNAME = /^(?:\*\.)?(?:[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?\.)+[a-z](?:[a-z0-9-]{0,61}[a-z0-9])?$/;
3851
+ const CLAUDE_VAULT_IPV4 = /^(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(?:\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}$/;
3852
+ /**
3853
+ * One host a secret's value may be substituted on, in the three forms the vault
3854
+ * API takes: a bare hostname (`api.openai.com`), a `*.`-prefixed wildcard
3855
+ * (`*.stripe.com`), or an IPv4 address.
3856
+ *
3857
+ * The API refuses URLs, ports, paths, and IPv6, so those are refused here too —
3858
+ * pasting `https://api.openai.com/v1` is the slip this exists for. Note the
3859
+ * wildcard's documented reach: `*.stripe.com` matches every subdomain of
3860
+ * `stripe.com` **but not `stripe.com` itself**, so a service reached at its apex
3861
+ * needs both entries. A bare TLD wildcard (`*.com`) is refused by shape.
3862
+ */
3863
+ const claudeVaultHostSchema = z.string().trim().toLowerCase().max(253).refine((host) => CLAUDE_VAULT_HOSTNAME.test(host) || CLAUDE_VAULT_IPV4.test(host), "must be a bare hostname (api.example.com), a *.example.com wildcard, or an IPv4 address — not a URL");
3864
+ /**
3865
+ * Where one secret's value may be substituted: a list of hosts, or the literal
3866
+ * `"unrestricted"`, which lets it reach any host the agent's *environment*
3867
+ * permits. The literal is spelled out rather than implied by an empty list, so
3868
+ * the widest setting is never something a binding arrives at by omission.
3869
+ */
3870
+ const claudeVaultHostRuleSchema = z.union([z.literal("unrestricted"), z.array(claudeVaultHostSchema).min(1).max(16)]);
3871
+ /**
3872
+ * Which parts of an outbound request a secret's placeholder is swapped in. The
3873
+ * API's own default when the field is omitted is both; seekrit's is `header`,
3874
+ * the narrower one — request bodies are often assembled from content the agent
3875
+ * is working with, and most services read an API key from a header. It is also
3876
+ * what the Claude Console creates by default, so the two agree.
3877
+ */
3878
+ const CLAUDE_VAULT_INJECTION_LOCATIONS = [
3879
+ "header",
3880
+ "body",
3881
+ "both"
3882
+ ];
3883
+ /**
3884
+ * One **Claude Managed Agents vault**, whose `environment_variable` credentials
3885
+ * a binding owns.
3886
+ *
3887
+ * Like `openai-vault`, a destination where the workload never holds the
3888
+ * plaintext either: an agent's sandbox sees an opaque placeholder in the
3889
+ * variable, and Anthropic's egress proxy swaps the real value in only on a
3890
+ * request to a host the credential names. So every name needs somewhere it is
3891
+ * allowed to go, and that is most of this shape:
3892
+ *
3893
+ * - `allowedHostsByName` — per destination name, after `nameTransform`. The
3894
+ * right tool: a Stripe key belongs on `api.stripe.com` and nowhere else.
3895
+ * - `allowedHosts` — for every name without its own rule.
3896
+ *
3897
+ * At least one must be given. A pushed name covered by neither **fails** rather
3898
+ * than going out `unrestricted` — the default-deny stance `apps/proxy` takes, so
3899
+ * a secret added to the environment later cannot silently widen where values
3900
+ * flow. Both levels apply beside the agent environment's own network policy,
3901
+ * which must also let the host through; this shape cannot see that policy.
3902
+ */
3903
+ const claudeManagedAgentsDestinationSchema = z.object({
3904
+ provider: z.literal("claude-managed-agents"),
3905
+ /** The vault's ID, e.g. `vlt_01ABC…`. */
3906
+ vaultId: claudeVaultIdSchema,
3907
+ /** Hosts for every name without its own entry in `allowedHostsByName`. */
3908
+ allowedHosts: claudeVaultHostRuleSchema.optional(),
3909
+ /** Destination name → the hosts that one value may be substituted on. */
3910
+ allowedHostsByName: z.record(secretNameSchema, claudeVaultHostRuleSchema).optional(),
3911
+ injectionLocation: z.enum(CLAUDE_VAULT_INJECTION_LOCATIONS).default("header")
3912
+ }).refine((d) => d.allowedHosts !== void 0 || Object.keys(d.allowedHostsByName ?? {}).length > 0, {
3913
+ message: "name the hosts each secret may be used on — allowedHosts for all of them, allowedHostsByName per name, or \"unrestricted\"",
3914
+ path: ["allowedHosts"]
3915
+ }).refine((d) => Object.keys(d.allowedHostsByName ?? {}).length <= CLAUDE_VAULT_MAX_HOST_RULES, {
3916
+ message: `at most ${CLAUDE_VAULT_MAX_HOST_RULES} per-name host rules`,
3917
+ path: ["allowedHostsByName"]
3918
+ });
3821
3919
  const syncDestinationSchema = z.discriminatedUnion("provider", [
3822
3920
  vercelDestinationSchema,
3823
3921
  cloudflareWorkersDestinationSchema,
@@ -3838,7 +3936,8 @@ const syncDestinationSchema = z.discriminatedUnion("provider", [
3838
3936
  langgraphPlatformDestinationSchema,
3839
3937
  azureKeyVaultDestinationSchema,
3840
3938
  huggingfaceSpacesDestinationSchema,
3841
- openaiVaultDestinationSchema
3939
+ openaiVaultDestinationSchema,
3940
+ claudeManagedAgentsDestinationSchema
3842
3941
  ]);
3843
3942
  /**
3844
3943
  * How seekrit secret names become destination key names. Applied in order:
@@ -5126,7 +5225,7 @@ async function createAgentTaskToken() {
5126
5225
  }
5127
5226
  //#endregion
5128
5227
  //#region package.json
5129
- var version = "1.8.0";
5228
+ var version = "1.9.1";
5130
5229
  //#endregion
5131
5230
  //#region ../../packages/api-client/src/index.ts
5132
5231
  /**
@@ -7690,7 +7789,7 @@ async function syncGrantsForGroupLink(ctx, orgId, envId, envSlug, groupId) {
7690
7789
  //#endregion
7691
7790
  //#region src/kms.ts
7692
7791
  /** Collect a repeatable option into a list. */
7693
- function collect$8(value, acc = []) {
7792
+ function collect$9(value, acc = []) {
7694
7793
  acc.push(value);
7695
7794
  return acc;
7696
7795
  }
@@ -7758,7 +7857,7 @@ async function kmsRecoverMaterial(ctx, orgId, keyId, version) {
7758
7857
  }
7759
7858
  function registerKmsCommands(program) {
7760
7859
  const kms = program.command("kms").description("managed keys for application-layer encryption & signing (client-side)");
7761
- kms.command("create").description("create a managed key (material is generated locally and wrapped, never sent)").requiredOption("--name <name>", "org-unique key name").requiredOption("--purpose <purpose>", "encrypt | sign").option("--org <slug>", "organization slug (defaults to seekrit.json, or your only org)").option("--app <slug>", "scope the key to an application").option("--group <slug>", "scope the key to a group").option("--grant-user <email>", "also grant an org member (repeatable)", collect$8, []).option("--grant-token <tokenId>", "also grant a service token (repeatable)", collect$8, []).action(async (options) => {
7860
+ kms.command("create").description("create a managed key (material is generated locally and wrapped, never sent)").requiredOption("--name <name>", "org-unique key name").requiredOption("--purpose <purpose>", "encrypt | sign").option("--org <slug>", "organization slug (defaults to seekrit.json, or your only org)").option("--app <slug>", "scope the key to an application").option("--group <slug>", "scope the key to a group").option("--grant-user <email>", "also grant an org member (repeatable)", collect$9, []).option("--grant-token <tokenId>", "also grant a service token (repeatable)", collect$9, []).action(async (options) => {
7762
7861
  if (options.purpose !== "encrypt" && options.purpose !== "sign") fail("--purpose must be encrypt or sign");
7763
7862
  if (options.app && options.group) fail("pass at most one of --app or --group");
7764
7863
  const ctx = buildContext();
@@ -7980,7 +8079,7 @@ function registerKmsCommands(program) {
7980
8079
  //#endregion
7981
8080
  //#region src/recovery.ts
7982
8081
  /** Collect a repeatable option into a list. */
7983
- function collect$7(value, acc = []) {
8082
+ function collect$8(value, acc = []) {
7984
8083
  acc.push(value);
7985
8084
  return acc;
7986
8085
  }
@@ -8077,7 +8176,7 @@ function registerRecoveryCommands(program) {
8077
8176
  for (const cst of status.custodians) console.log(` - ${cst.label ?? cst.principalId} (${cst.principalType}, share #${cst.shareIndex})`);
8078
8177
  if (status.coverage.unprotectedEnvIds.length > 0) console.log(`${status.coverage.unprotectedEnvIds.length} environment(s) not yet protected — run \`seekrit recovery sync\``);
8079
8178
  });
8080
- recovery.command("setup").description("enable recovery: split a fresh recovery key across custodians").requiredOption("--threshold <M>", "custodians required to recover (M in M-of-N)").option("--custodian <email|skt_id>", "a recovery custodian (repeatable)", collect$7, []).option("--org <slug>", "organization slug (defaults to seekrit.json, or your only org)").action(async (options) => {
8179
+ recovery.command("setup").description("enable recovery: split a fresh recovery key across custodians").requiredOption("--threshold <M>", "custodians required to recover (M in M-of-N)").option("--custodian <email|skt_id>", "a recovery custodian (repeatable)", collect$8, []).option("--org <slug>", "organization slug (defaults to seekrit.json, or your only org)").action(async (options) => {
8081
8180
  const ctx = buildContext();
8082
8181
  const org = await resolveOrg(ctx, options.org);
8083
8182
  const config = await buildRecoveryConfig(ctx, org.id, options.threshold, options.custodian);
@@ -8095,7 +8194,7 @@ function registerRecoveryCommands(program) {
8095
8194
  const { wrapped, skipped } = await syncRecoveryGrants(ctx, (await resolveOrg(ctx, options.org)).id);
8096
8195
  console.error(`recovery-protected ${wrapped} environment(s); skipped ${skipped} you cannot decrypt`);
8097
8196
  });
8098
- recovery.command("rotate").description("rotate the recovery key (new keypair, custodians, and env re-wraps)").requiredOption("--threshold <M>", "custodians required to recover (M in M-of-N)").option("--custodian <email|skt_id>", "a recovery custodian (repeatable)", collect$7, []).option("--org <slug>", "organization slug (defaults to seekrit.json, or your only org)").action(async (options) => {
8197
+ recovery.command("rotate").description("rotate the recovery key (new keypair, custodians, and env re-wraps)").requiredOption("--threshold <M>", "custodians required to recover (M in M-of-N)").option("--custodian <email|skt_id>", "a recovery custodian (repeatable)", collect$8, []).option("--org <slug>", "organization slug (defaults to seekrit.json, or your only org)").action(async (options) => {
8099
8198
  const ctx = buildContext();
8100
8199
  const org = await resolveOrg(ctx, options.org);
8101
8200
  const config = await buildRecoveryConfig(ctx, org.id, options.threshold, options.custodian);
@@ -9238,7 +9337,7 @@ function formatSecrets(values, format) {
9238
9337
  * `buildContext()` in any of them silently breaks the promise the feature makes.
9239
9338
  */
9240
9339
  /** Collect a repeatable option into a list. */
9241
- function collect$6(value, acc = []) {
9340
+ function collect$7(value, acc = []) {
9242
9341
  acc.push(value);
9243
9342
  return acc;
9244
9343
  }
@@ -9515,7 +9614,7 @@ function registerArchiveCommands(program) {
9515
9614
  } catch {}
9516
9615
  fail("none of the recovery shares in this archive unwrap with that key");
9517
9616
  });
9518
- archive.command("decrypt <file>").description("decrypt an archive's secrets with your own key (offline)").option("-o, --out <dir>", "write one file per environment into this directory").option("--stdout", "print plaintext to stdout instead of writing files").option("--env <label>", "only this environment (app/env, group@env, slug, or id)").option("--format <format>", "dotenv | json | shell", "dotenv").option("--token <skt_…>", "decrypt as a service token instead of a passphrase").option("--key-file <path>", "decrypt with a private key JWK file").option("--share <file>", "custodian share for an offline quorum (repeatable)", collect$6).option("-y, --yes", "skip the confirmation when printing plaintext to stdout").action(async (file, options) => {
9617
+ archive.command("decrypt <file>").description("decrypt an archive's secrets with your own key (offline)").option("-o, --out <dir>", "write one file per environment into this directory").option("--stdout", "print plaintext to stdout instead of writing files").option("--env <label>", "only this environment (app/env, group@env, slug, or id)").option("--format <format>", "dotenv | json | shell", "dotenv").option("--token <skt_…>", "decrypt as a service token instead of a passphrase").option("--key-file <path>", "decrypt with a private key JWK file").option("--share <file>", "custodian share for an offline quorum (repeatable)", collect$7).option("-y, --yes", "skip the confirmation when printing plaintext to stdout").action(async (file, options) => {
9519
9618
  if (!options.out && !options.stdout) fail("choose a destination: --out <dir> to write files, or --stdout to print plaintext");
9520
9619
  if (![
9521
9620
  "dotenv",
@@ -11562,7 +11661,7 @@ function parseTtlSeconds$4(input) {
11562
11661
  }[m[2] || "s"] ?? 1);
11563
11662
  }
11564
11663
  /** Collect a repeatable option into an array. */
11565
- function collect$5(value, previous) {
11664
+ function collect$6(value, previous) {
11566
11665
  return [...previous, value];
11567
11666
  }
11568
11667
  /** Parse `readWrite@app` → { role, db } for a custom target. */
@@ -11587,7 +11686,7 @@ function resolveAdminUri(uri) {
11587
11686
  function registerMongoCommands(program) {
11588
11687
  const mongo = program.command("mongodb").description("temporary MongoDB credentials (createUser, zero-knowledge delivery)");
11589
11688
  const target = mongo.command("target").description("manage MongoDB targets");
11590
- target.command("add").description("register a MongoDB cluster to issue temporary credentials from").requiredOption("--name <name>", "display name, e.g. prod-app").requiredOption("--database <db>", "the database leased users get access to, e.g. app").option("--uri <uri>", "admin connection string (else SEEKRIT_MONGODB_ADMIN_URL)").option("--org <slug>", "organization slug (defaults to seekrit.json, or your only org)").option("--access <level>", "readonly | readwrite | custom", "readonly").option("--role <role@db>", "grant for a custom target (repeatable)", collect$5, []).option("--auth-source <db>", "authentication database (default admin)").option("--max-ttl <duration>", "clamp requested credential lifetime, e.g. 8h").option("--no-tls", "disable TLS to the cluster (TLS is on by default)").action(async (options) => {
11689
+ target.command("add").description("register a MongoDB cluster to issue temporary credentials from").requiredOption("--name <name>", "display name, e.g. prod-app").requiredOption("--database <db>", "the database leased users get access to, e.g. app").option("--uri <uri>", "admin connection string (else SEEKRIT_MONGODB_ADMIN_URL)").option("--org <slug>", "organization slug (defaults to seekrit.json, or your only org)").option("--access <level>", "readonly | readwrite | custom", "readonly").option("--role <role@db>", "grant for a custom target (repeatable)", collect$6, []).option("--auth-source <db>", "authentication database (default admin)").option("--max-ttl <duration>", "clamp requested credential lifetime, e.g. 8h").option("--no-tls", "disable TLS to the cluster (TLS is on by default)").action(async (options) => {
11591
11690
  const ctx = buildContext();
11592
11691
  const org = await resolveOrg(ctx, options.org);
11593
11692
  const adminUri = resolveAdminUri(options.uri);
@@ -11749,7 +11848,7 @@ function generateUserName$1(prefix = "tmp") {
11749
11848
  function registerMysqlCommands(program) {
11750
11849
  const mysql = program.command("mysql").description("temporary MySQL/MariaDB credentials (short-lived, zero-knowledge)");
11751
11850
  const target = mysql.command("target").description("manage provisioning targets");
11752
- target.command("add").description("register a MySQL/MariaDB server to lease credentials from").requiredOption("--name <name>", "display name, e.g. prod-db").option("--org <slug>", "organization slug (defaults to seekrit.json, or your only org)").requiredOption("--host <host>", "database host").option("--port <port>", "database port", "3306").requiredOption("--database <name>", "database to grant access to").option("--access <level>", "readonly | readwrite | custom", "readonly").option("--user-host <host>", "host part of created accounts ('name'@'<host>')", "%").option("--executor <mode>", "in_do | remote", "in_do").option("--provisioner-url <url>", "customer provisioner URL (remote executor)").option("--hmac-key <base64>", "shared HMAC key for the remote executor (or set SEEKRIT_PROVISIONER_HMAC_KEY); `seekrit provisioner keygen` mints one").option("--admin-url <url>", "in_do: admin mysql:// connection string (or set SEEKRIT_MYSQL_ADMIN_URL); wrapped locally").option("--create-statement <sql>", "custom CREATE template (repeatable)", collect$4, []).option("--revoke-statement <sql>", "custom REVOKE template (repeatable)", collect$4, []).action(async (options) => {
11851
+ target.command("add").description("register a MySQL/MariaDB server to lease credentials from").requiredOption("--name <name>", "display name, e.g. prod-db").option("--org <slug>", "organization slug (defaults to seekrit.json, or your only org)").requiredOption("--host <host>", "database host").option("--port <port>", "database port", "3306").requiredOption("--database <name>", "database to grant access to").option("--access <level>", "readonly | readwrite | custom", "readonly").option("--user-host <host>", "host part of created accounts ('name'@'<host>')", "%").option("--executor <mode>", "in_do | remote", "in_do").option("--provisioner-url <url>", "customer provisioner URL (remote executor)").option("--hmac-key <base64>", "shared HMAC key for the remote executor (or set SEEKRIT_PROVISIONER_HMAC_KEY); `seekrit provisioner keygen` mints one").option("--admin-url <url>", "in_do: admin mysql:// connection string (or set SEEKRIT_MYSQL_ADMIN_URL); wrapped locally").option("--create-statement <sql>", "custom CREATE template (repeatable)", collect$5, []).option("--revoke-statement <sql>", "custom REVOKE template (repeatable)", collect$5, []).action(async (options) => {
11753
11852
  const ctx = buildContext();
11754
11853
  const org = await resolveOrg(ctx, options.org);
11755
11854
  const executor = options.executor === "remote" ? "remote" : "in_do";
@@ -11852,7 +11951,7 @@ function registerMysqlCommands(program) {
11852
11951
  });
11853
11952
  }
11854
11953
  /** Collect a repeatable option into an array. */
11855
- function collect$4(value, acc) {
11954
+ function collect$5(value, acc) {
11856
11955
  acc.push(value);
11857
11956
  return acc;
11858
11957
  }
@@ -11892,7 +11991,7 @@ function collect$4(value, acc) {
11892
11991
  * release-please-config.json), so the pin follows the crate without anyone
11893
11992
  * remembering to move it.
11894
11993
  */
11895
- const PROXY_VERSION = "0.12.2";
11994
+ const PROXY_VERSION = "0.12.3";
11896
11995
  const BIN = "seekrit-proxy";
11897
11996
  /**
11898
11997
  * Host → Rust target triple.
@@ -11928,7 +12027,7 @@ function versionPrefix(version) {
11928
12027
  return version.startsWith("v") ? version : `v${version}`;
11929
12028
  }
11930
12029
  function resolveVersion(explicit) {
11931
- return explicit ?? process.env.SEEKRIT_PROXY_VERSION ?? "0.12.2";
12030
+ return explicit ?? process.env.SEEKRIT_PROXY_VERSION ?? "0.12.3";
11932
12031
  }
11933
12032
  function resolveBaseUrl(explicit) {
11934
12033
  return (explicit ?? process.env.SEEKRIT_PROXY_BASE_URL ?? "https://proxy.seekrit.dev").replace(/\/+$/, "");
@@ -12086,7 +12185,7 @@ const PLUGIN_BIN = "seekrit-nomad-secrets";
12086
12185
  * entry in release-please-config.json), so the pin follows the crate without
12087
12186
  * anyone remembering to move it — the same arrangement `PROXY_VERSION` has.
12088
12187
  */
12089
- const NOMAD_PLUGIN_VERSION = "0.2.1";
12188
+ const NOMAD_PLUGIN_VERSION = "0.2.2";
12090
12189
  /** Public artifact host. Mirrors GitHub Releases; public, no egress fees. */
12091
12190
  const DEFAULT_BASE_URL = "https://nomad.seekrit.dev";
12092
12191
  /** Where the plugin reads its node config, matching `config::DEFAULT_CONFIG_PATH`. */
@@ -12173,7 +12272,7 @@ async function fetchBytes(url) {
12173
12272
  * let Nomad fingerprint a half-written executable.
12174
12273
  */
12175
12274
  async function installPlugin(pluginDir, options = {}) {
12176
- const version = options.version ?? "0.2.1";
12275
+ const version = options.version ?? "0.2.2";
12177
12276
  const baseUrl = (options.baseUrl ?? "https://nomad.seekrit.dev").replace(/\/+$/, "");
12178
12277
  const { target, exe } = detectTarget();
12179
12278
  if (exe !== "") fail("Nomad secret provider plugins are not supported on Windows clients");
@@ -12304,12 +12403,12 @@ function requirePluginDir(explicit) {
12304
12403
  if (found) return found;
12305
12404
  fail("could not find the Nomad plugin directory — pass --plugin-dir <path> matching your agent's client.common_plugin_dir");
12306
12405
  }
12307
- function collect$3(value, previous = []) {
12406
+ function collect$4(value, previous = []) {
12308
12407
  return [...previous, value];
12309
12408
  }
12310
12409
  function registerNomadCommands(program) {
12311
12410
  const nomad = program.command("nomad").description("wire seekrit into Nomad as a secret provider (`seekrit nomad --help`)");
12312
- nomad.command("init").description("print the agent stanza, plugin config, and job snippet for this client").option("--plugin-dir <path>", "the agent's client.common_plugin_dir").option("--profile <name>", "profile name jobs will reference in `path`", "default").option("--token-file <path>", "where the profile's service token lives").option("--namespace <ns>", "restrict the profile to a Nomad namespace (repeatable)", collect$3).option("--job <id>", "restrict the profile to a Nomad job id (repeatable)", collect$3).option("--config <path>", "plugin config path", DEFAULT_CONFIG_PATH).option("--write", "write the plugin config file instead of printing it").option("--json", "machine-readable output").action((options) => {
12411
+ nomad.command("init").description("print the agent stanza, plugin config, and job snippet for this client").option("--plugin-dir <path>", "the agent's client.common_plugin_dir").option("--profile <name>", "profile name jobs will reference in `path`", "default").option("--token-file <path>", "where the profile's service token lives").option("--namespace <ns>", "restrict the profile to a Nomad namespace (repeatable)", collect$4).option("--job <id>", "restrict the profile to a Nomad job id (repeatable)", collect$4).option("--config <path>", "plugin config path", DEFAULT_CONFIG_PATH).option("--write", "write the plugin config file instead of printing it").option("--json", "machine-readable output").action((options) => {
12313
12412
  const pluginDir = options.pluginDir ? resolve(options.pluginDir) : detectPluginDir() ?? PLUGIN_DIR_CANDIDATES[0];
12314
12413
  const profile = options.profile ?? "default";
12315
12414
  const tokenFile = options.tokenFile ?? `/etc/seekrit/tokens/${profile}`;
@@ -13428,7 +13527,7 @@ function generateRoleName(prefix = "tmp") {
13428
13527
  function registerPgCommands(program) {
13429
13528
  const pg = program.command("pg").description("temporary Postgres credentials (short-lived, zero-knowledge)");
13430
13529
  const target = pg.command("target").description("manage provisioning targets");
13431
- target.command("add").description("register a Postgres cluster to lease credentials from").requiredOption("--name <name>", "display name, e.g. prod-db").option("--org <slug>", "organization slug (defaults to seekrit.json, or your only org)").requiredOption("--host <host>", "database host").option("--port <port>", "database port", "5432").requiredOption("--database <name>", "database to connect to").option("--access <level>", "readonly | readwrite | custom", "readonly").option("--schema <name>", "schema for preset grants", "public").option("--executor <mode>", "in_do | remote", "in_do").option("--provisioner-url <url>", "customer provisioner URL (remote executor)").option("--hmac-key <base64>", "shared HMAC key for the remote executor (or set SEEKRIT_PROVISIONER_HMAC_KEY); `seekrit provisioner keygen` mints one").option("--admin-url <url>", "in_do: admin postgres:// connection string (or set SEEKRIT_PG_ADMIN_URL); wrapped locally").option("--create-statement <sql>", "custom CREATE template (repeatable)", collect$2, []).option("--revoke-statement <sql>", "custom REVOKE template (repeatable)", collect$2, []).action(async (options) => {
13530
+ target.command("add").description("register a Postgres cluster to lease credentials from").requiredOption("--name <name>", "display name, e.g. prod-db").option("--org <slug>", "organization slug (defaults to seekrit.json, or your only org)").requiredOption("--host <host>", "database host").option("--port <port>", "database port", "5432").requiredOption("--database <name>", "database to connect to").option("--access <level>", "readonly | readwrite | custom", "readonly").option("--schema <name>", "schema for preset grants", "public").option("--executor <mode>", "in_do | remote", "in_do").option("--provisioner-url <url>", "customer provisioner URL (remote executor)").option("--hmac-key <base64>", "shared HMAC key for the remote executor (or set SEEKRIT_PROVISIONER_HMAC_KEY); `seekrit provisioner keygen` mints one").option("--admin-url <url>", "in_do: admin postgres:// connection string (or set SEEKRIT_PG_ADMIN_URL); wrapped locally").option("--create-statement <sql>", "custom CREATE template (repeatable)", collect$3, []).option("--revoke-statement <sql>", "custom REVOKE template (repeatable)", collect$3, []).action(async (options) => {
13432
13531
  const ctx = buildContext();
13433
13532
  const org = await resolveOrg(ctx, options.org);
13434
13533
  const executor = options.executor === "remote" ? "remote" : "in_do";
@@ -13544,7 +13643,7 @@ function registerPgCommands(program) {
13544
13643
  });
13545
13644
  }
13546
13645
  /** Collect a repeatable option into an array. */
13547
- function collect$2(value, acc) {
13646
+ function collect$3(value, acc) {
13548
13647
  acc.push(value);
13549
13648
  return acc;
13550
13649
  }
@@ -13878,10 +13977,10 @@ Next:
13878
13977
  });
13879
13978
  console.log(path);
13880
13979
  const { target } = detectTarget();
13881
- process.stderr.write(`seekrit-proxy ${versionPrefix(options.proxyVersion ?? "0.12.2")} (${target})\n`);
13980
+ process.stderr.write(`seekrit-proxy ${versionPrefix(options.proxyVersion ?? "0.12.3")} (${target})\n`);
13882
13981
  });
13883
13982
  proxy.command("where").description("show which binary `seekrit proxy run` would use, without fetching it").option("--proxy-version <version>", `version to report (default: ${PROXY_VERSION})`).option("--json", "machine-readable output").action((options) => {
13884
- const version = options.proxyVersion ?? process.env.SEEKRIT_PROXY_VERSION ?? "0.12.2";
13983
+ const version = options.proxyVersion ?? process.env.SEEKRIT_PROXY_VERSION ?? "0.12.3";
13885
13984
  const override = process.env.SEEKRIT_PROXY_BIN;
13886
13985
  const { target, exe } = detectTarget();
13887
13986
  const path = override ?? proxyBinaryPath(version, target, exe);
@@ -13940,7 +14039,7 @@ Next:
13940
14039
  process.stdout.write(renderComposeSnippet(plan, {
13941
14040
  service: options.service,
13942
14041
  workload: options.workload,
13943
- image: options.image ?? `seekritdev/proxy:0.12.2`,
14042
+ image: options.image ?? `seekritdev/proxy:0.12.3`,
13944
14043
  publish: Boolean(options.publish)
13945
14044
  }));
13946
14045
  });
@@ -13979,7 +14078,7 @@ function generateUserName(prefix = "tmp") {
13979
14078
  function registerRedisCommands(program) {
13980
14079
  const redis = program.command("redis").description("temporary Redis credentials (short-lived, zero-knowledge)");
13981
14080
  const target = redis.command("target").description("manage provisioning targets");
13982
- target.command("add").description("register a Redis server to lease credentials from").requiredOption("--name <name>", "display name, e.g. prod-cache").option("--org <slug>", "organization slug (defaults to seekrit.json, or your only org)").requiredOption("--host <host>", "redis host").option("--port <port>", "redis port", "6379").option("--db <index>", "logical database index (the /<n> in the URL)").option("--access <level>", "readonly | readwrite | custom", "readonly").option("--executor <mode>", "in_do | remote", "in_do").option("--provisioner-url <url>", "customer provisioner URL (remote executor)").option("--hmac-key <base64>", "shared HMAC key for the remote executor (or set SEEKRIT_PROVISIONER_HMAC_KEY); `seekrit provisioner keygen` mints one").option("--admin-url <url>", "in_do: admin redis:// (or rediss://) connection string (or set SEEKRIT_REDIS_ADMIN_URL); wrapped locally").option("--create-statement <cmd>", "custom SETUSER template (repeatable)", collect$1, []).option("--revoke-statement <cmd>", "custom DELUSER template (repeatable)", collect$1, []).action(async (options) => {
14081
+ target.command("add").description("register a Redis server to lease credentials from").requiredOption("--name <name>", "display name, e.g. prod-cache").option("--org <slug>", "organization slug (defaults to seekrit.json, or your only org)").requiredOption("--host <host>", "redis host").option("--port <port>", "redis port", "6379").option("--db <index>", "logical database index (the /<n> in the URL)").option("--access <level>", "readonly | readwrite | custom", "readonly").option("--executor <mode>", "in_do | remote", "in_do").option("--provisioner-url <url>", "customer provisioner URL (remote executor)").option("--hmac-key <base64>", "shared HMAC key for the remote executor (or set SEEKRIT_PROVISIONER_HMAC_KEY); `seekrit provisioner keygen` mints one").option("--admin-url <url>", "in_do: admin redis:// (or rediss://) connection string (or set SEEKRIT_REDIS_ADMIN_URL); wrapped locally").option("--create-statement <cmd>", "custom SETUSER template (repeatable)", collect$2, []).option("--revoke-statement <cmd>", "custom DELUSER template (repeatable)", collect$2, []).action(async (options) => {
13983
14082
  const ctx = buildContext();
13984
14083
  const org = await resolveOrg(ctx, options.org);
13985
14084
  const executor = options.executor === "remote" ? "remote" : "in_do";
@@ -14082,7 +14181,7 @@ function registerRedisCommands(program) {
14082
14181
  });
14083
14182
  }
14084
14183
  /** Collect a repeatable option into an array. */
14085
- function collect$1(value, acc) {
14184
+ function collect$2(value, acc) {
14086
14185
  acc.push(value);
14087
14186
  return acc;
14088
14187
  }
@@ -14281,7 +14380,7 @@ function parseTtlSeconds(input) {
14281
14380
  function registerSshCommands(program) {
14282
14381
  const ssh = program.command("ssh").description("temporary SSH access (short-lived certificates, zero-knowledge)");
14283
14382
  const target = ssh.command("target").description("manage SSH CA targets");
14284
- target.command("add").description("create an SSH certificate authority to issue certs from").requiredOption("--name <name>", "display name, e.g. prod-fleet").option("--org <slug>", "organization slug (defaults to seekrit.json, or your only org)").option("--host <host>", "default host the printed ssh command connects to").option("--user <login>", "default login user (a cert principal)").option("--principal <name>", "allow-list a principal certs may request (repeatable)", collect, []).option("--extension <name>", "cert extension to grant, e.g. permit-pty (repeatable)", collect, []).option("--max-ttl <duration>", "clamp requested cert lifetime, e.g. 8h").action(async (options) => {
14383
+ target.command("add").description("create an SSH certificate authority to issue certs from").requiredOption("--name <name>", "display name, e.g. prod-fleet").option("--org <slug>", "organization slug (defaults to seekrit.json, or your only org)").option("--host <host>", "default host the printed ssh command connects to").option("--user <login>", "default login user (a cert principal)").option("--principal <name>", "allow-list a principal certs may request (repeatable)", collect$1, []).option("--extension <name>", "cert extension to grant, e.g. permit-pty (repeatable)", collect$1, []).option("--max-ttl <duration>", "clamp requested cert lifetime, e.g. 8h").action(async (options) => {
14285
14384
  const ctx = buildContext();
14286
14385
  const org = await resolveOrg(ctx, options.org);
14287
14386
  const ca = await generateSshCaKeyPair(`seekrit-ca:${options.name}`);
@@ -14337,7 +14436,7 @@ function registerSshCommands(program) {
14337
14436
  await ctx.client.deleteLeaseTarget(org.id, targetId);
14338
14437
  console.error(`deleted ${targetId}`);
14339
14438
  });
14340
- ssh.command("lease <target>").description("mint a short-lived SSH certificate; prints a ready-to-run ssh command").option("--org <slug>", "organization slug (defaults to seekrit.json, or your only org)").option("--principal <name>", "login user to request (repeatable; default from target)", collect, []).option("--ttl <duration>", "certificate lifetime, e.g. 30m, 1h, 8h", "1h").option("--out <dir>", "directory to write the key + cert (default: a temp dir)").option("--json", "print key/cert paths and the certificate as JSON").action(async (targetRef, options) => {
14439
+ ssh.command("lease <target>").description("mint a short-lived SSH certificate; prints a ready-to-run ssh command").option("--org <slug>", "organization slug (defaults to seekrit.json, or your only org)").option("--principal <name>", "login user to request (repeatable; default from target)", collect$1, []).option("--ttl <duration>", "certificate lifetime, e.g. 30m, 1h, 8h", "1h").option("--out <dir>", "directory to write the key + cert (default: a temp dir)").option("--json", "print key/cert paths and the certificate as JSON").action(async (targetRef, options) => {
14341
14440
  const ctx = buildContext();
14342
14441
  const org = await resolveOrg(ctx, options.org);
14343
14442
  const { targets } = await ctx.client.listLeaseTargets(org.id);
@@ -14393,7 +14492,7 @@ function registerSshCommands(program) {
14393
14492
  });
14394
14493
  }
14395
14494
  /** Collect a repeatable option into an array. */
14396
- function collect(value, acc) {
14495
+ function collect$1(value, acc) {
14397
14496
  acc.push(value);
14398
14497
  return acc;
14399
14498
  }
@@ -14403,6 +14502,36 @@ function collect(value, acc) {
14403
14502
  function list(raw, fallback) {
14404
14503
  return (raw ?? fallback).split(",").map((item) => item.trim()).filter(Boolean);
14405
14504
  }
14505
+ /** Accumulate a repeatable flag, in the order given. */
14506
+ function collect(value, acc = []) {
14507
+ return [...acc, value];
14508
+ }
14509
+ /**
14510
+ * One host rule as typed on the command line: a comma-separated host list, or
14511
+ * the literal `unrestricted`. The schema does the real validation; this only
14512
+ * turns the spelling into the shape it checks.
14513
+ */
14514
+ function hostRule(raw) {
14515
+ const trimmed = raw.trim();
14516
+ if (trimmed.toLowerCase() === "unrestricted") return "unrestricted";
14517
+ return list(trimmed, "");
14518
+ }
14519
+ /**
14520
+ * `--allowed-hosts-for NAME=host,host`, repeated — one per destination name.
14521
+ * A name given twice is refused rather than merged or last-wins, since either
14522
+ * reading would silently widen or narrow what the other occurrence said.
14523
+ */
14524
+ function hostRulesByName(entries) {
14525
+ const rules = {};
14526
+ for (const entry of entries ?? []) {
14527
+ const eq = entry.indexOf("=");
14528
+ const name = eq > 0 ? entry.slice(0, eq).trim() : "";
14529
+ if (!name || eq === entry.length - 1) fail(`--allowed-hosts-for takes NAME=host[,host…] (or NAME=unrestricted), not "${entry}"`);
14530
+ if (Object.hasOwn(rules, name)) fail(`--allowed-hosts-for names ${name} twice`);
14531
+ rules[name] = hostRule(entry.slice(eq + 1));
14532
+ }
14533
+ return rules;
14534
+ }
14406
14535
  /** Reject list members outside a known set, naming both the strays and the choices. */
14407
14536
  function assertMembers(values, allowed, flag) {
14408
14537
  const unknown = values.filter((v) => !allowed.includes(v));
@@ -14567,6 +14696,7 @@ function credentialNoun(provider) {
14567
14696
  if (provider === "azure-key-vault") return "client secret";
14568
14697
  if (provider === "huggingface-spaces") return "user access token";
14569
14698
  if (provider === "openai-vault") return "OpenAI project API key";
14699
+ if (provider === "claude-managed-agents") return "Anthropic API key";
14570
14700
  return "API token";
14571
14701
  }
14572
14702
  /**
@@ -14657,9 +14787,13 @@ function buildConfig(provider, options) {
14657
14787
  }
14658
14788
  case "huggingface-spaces": return { provider: "huggingface-spaces" };
14659
14789
  case "openai-vault": return { provider: "openai-vault" };
14790
+ case "claude-managed-agents": return { provider: "claude-managed-agents" };
14660
14791
  }
14661
14792
  }
14662
- /** Where inside the platform a binding writes. */
14793
+ /**
14794
+ * Where inside the platform a binding writes. Exported for its tests: the
14795
+ * flags are the one part of a binding the API cannot see as typed.
14796
+ */
14663
14797
  function buildDestination(provider, options) {
14664
14798
  switch (provider) {
14665
14799
  case "vercel": {
@@ -14882,6 +15016,22 @@ function buildDestination(provider, options) {
14882
15016
  vaultId: options.openaiVault.trim(),
14883
15017
  allowedHosts: list(options.openaiHosts, "")
14884
15018
  };
15019
+ case "claude-managed-agents": {
15020
+ if (!options.vault) fail("--vault is required for claude-managed-agents — the vault ID, e.g. vlt_01ABC…");
15021
+ const byName = hostRulesByName(options.allowedHostsFor);
15022
+ const parsed = claudeManagedAgentsDestinationSchema.safeParse({
15023
+ provider: "claude-managed-agents",
15024
+ vaultId: options.vault,
15025
+ ...options.allowedHosts !== void 0 ? { allowedHosts: hostRule(options.allowedHosts) } : {},
15026
+ ...Object.keys(byName).length > 0 ? { allowedHostsByName: byName } : {},
15027
+ injectionLocation: assertMember(options.injectionLocation, CLAUDE_VAULT_INJECTION_LOCATIONS, "--injection-location", "header")
15028
+ });
15029
+ if (!parsed.success) {
15030
+ const issue = parsed.error.issues[0];
15031
+ fail(`claude-managed-agents: ${issue?.path.length ? `${issue.path.join(".")}: ` : ""}${issue?.message ?? "invalid destination"} — pass --allowed-hosts <host,…> for every name, and/or --allowed-hosts-for NAME=<host,…> per name`);
15032
+ }
15033
+ return parsed.data;
15034
+ }
14885
15035
  }
14886
15036
  }
14887
15037
  /** One-line description of a destination, for list output. */
@@ -14906,6 +15056,11 @@ function describeDestination(destination) {
14906
15056
  case "azure-key-vault": return `${destination.vault}${destination.prefix ? ` (${destination.prefix}*)` : ""}`;
14907
15057
  case "huggingface-spaces": return `space ${destination.repoId}`;
14908
15058
  case "openai-vault": return `${destination.vaultId} (${destination.allowedHosts.join(", ")})`;
15059
+ case "claude-managed-agents": {
15060
+ const rules = Object.keys(destination.allowedHostsByName ?? {}).length;
15061
+ const hosts = destination.allowedHosts === void 0 ? "no default hosts" : destination.allowedHosts === "unrestricted" ? "unrestricted by default" : destination.allowedHosts.join(", ");
15062
+ return `vault ${destination.vaultId} (${hosts}${rules ? ` · ${rules} per-name` : ""} · ${destination.injectionLocation})`;
15063
+ }
14909
15064
  case "github-actions": switch (destination.kind) {
14910
15065
  case "repo": return `${destination.owner}/${destination.repo}`;
14911
15066
  case "environment": return `${destination.owner}/${destination.repo} @${destination.environment}`;
@@ -14921,7 +15076,7 @@ function describeDestination(destination) {
14921
15076
  * application whose environment the binding reads from.
14922
15077
  */
14923
15078
  function destinationOptions(command) {
14924
- return command.option("--project <id>", "vercel: project id or name · cloudflare-pages / northflank: project name or slug · bunnyshell: project ID (writes variables new environments inherit)").option("--target <list>", "vercel / cloudflare-pages: comma-separated deployment targets", "production").option("--git-branch <branch>", "vercel: restrict preview writes to one branch").option("--script <name>", "cloudflare-workers: Worker script name").option("--store-id <id>", "cloudflare-secrets-store: store ID (32 hex)").option("--scopes <list>", "cloudflare-secrets-store: comma-separated scopes", "workers").option("--railway-project <id>", "railway: project ID (a UUID)").option("--railway-environment <id>", "railway: environment ID (a UUID)").option("--service <id>", "railway: service ID (omit for the environment's shared variables) · render: service ID (srv-…, or crn-… for a cron job)").option("--skip-deploys", "railway: stage values without triggering a redeploy").option("--path <path>", "aws-parameter-store: hierarchy, e.g. /prod/storefront/ · aws-secrets-manager, azure-key-vault: name prefix").option("--layout <layout>", `aws-secrets-manager: ${AWS_SECRETS_MANAGER_LAYOUTS.join(" | ")}`).option("--secret-name <name>", "aws-secrets-manager: the secret a json-bundle writes to").option("--param-type <type>", `aws-parameter-store: ${AWS_PARAMETER_TYPES.join(" | ")}`).option("--tier <tier>", `aws-parameter-store: ${AWS_PARAMETER_TIERS.join(" | ")}`).option("--kms-key-id <id>", "aws: customer-managed KMS key id, ARN, or alias").option("--env-group <id>", "render: environment group ID (evg-…)").option("--fly-app <name>", "fly: app name, as `fly apps list` shows it").option("--secret-group <id>", "northflank: secret group ID (the slug in its URL)").option("--do-app <id>", "digitalocean: App Platform app ID (the UUID in its URL)").option("--component <name>", "digitalocean: write to one component's variables (omit for app-level)").option("--env-scope <scope>", `digitalocean: ${DIGITALOCEAN_ENV_SCOPES.join(" | ")}`).option("--heroku-app <name>", "heroku: app name, as `heroku apps` shows it (or its UUID)").option("--netlify-site <id>", "netlify: site API ID (the UUID under Project configuration)").option("--no-netlify-secret", "netlify: create readable variables instead of Netlify secrets (write-only)").option("--bunnyshell-environment <id>", "bunnyshell: environment ID (omit to write a project)").option("--no-bunnyshell-secret", "bunnyshell: create variables visible in the dashboard instead of secret ones").option("--gh-repo <owner/name>", "github-actions: repository, e.g. acme/storefront").option("--gh-environment <name>", "github-actions: write to one deployment environment's secrets (needs --gh-repo)").option("--gh-org <login>", "github-actions: write organization secrets instead of a repo's").option("--gh-visibility <v>", `github-actions org secrets: ${GITHUB_ACTIONS_VISIBILITIES.join(" | ")}`).option("--gh-repo-ids <ids>", "github-actions: comma-separated numeric repository IDs for --gh-visibility selected").option("--langgraph-deployment <id>", "langgraph-platform: deployment UUID (the one in its dashboard URL)").option("--gcp-prefix <prefix>", "gcp: prepended to every secret ID, e.g. prod-storefront-").option("--gcp-replication <policy>", `gcp: ${GCP_REPLICATION_POLICIES.join(" | ")}`, "automatic").option("--gcp-locations <list>", "gcp: regions for user-managed replication, e.g. us-east1").option("--gcp-kms-key <name>", "gcp: Cloud KMS key (projects/…/cryptoKeys/…)").option("--gcp-prune-versions", "gcp: destroy the version each push supersedes, keeping one active version").option("--vault <name>", "azure-key-vault: vault name, e.g. acme-prod").option("--openai-vault <id>", "openai-vault: existing OpenAI Vault ID (vault_…)").option("--openai-hosts <hosts>", "openai-vault: comma-separated exact HTTPS hostnames").option("--hf-space <owner/name>", "huggingface-spaces: Space ID, e.g. acme/support-demo (its owner and name, not a URL)").option("--name-mode <mode>", `azure-key-vault: ${AZURE_KEY_VAULT_NAME_MODES.join(" | ")} — Key Vault stores no underscores, so DATABASE_URL becomes DATABASE-URL unless you reject instead`);
15079
+ return command.option("--project <id>", "vercel: project id or name · cloudflare-pages / northflank: project name or slug · bunnyshell: project ID (writes variables new environments inherit)").option("--target <list>", "vercel / cloudflare-pages: comma-separated deployment targets", "production").option("--git-branch <branch>", "vercel: restrict preview writes to one branch").option("--script <name>", "cloudflare-workers: Worker script name").option("--store-id <id>", "cloudflare-secrets-store: store ID (32 hex)").option("--scopes <list>", "cloudflare-secrets-store: comma-separated scopes", "workers").option("--railway-project <id>", "railway: project ID (a UUID)").option("--railway-environment <id>", "railway: environment ID (a UUID)").option("--service <id>", "railway: service ID (omit for the environment's shared variables) · render: service ID (srv-…, or crn-… for a cron job)").option("--skip-deploys", "railway: stage values without triggering a redeploy").option("--path <path>", "aws-parameter-store: hierarchy, e.g. /prod/storefront/ · aws-secrets-manager, azure-key-vault: name prefix").option("--layout <layout>", `aws-secrets-manager: ${AWS_SECRETS_MANAGER_LAYOUTS.join(" | ")}`).option("--secret-name <name>", "aws-secrets-manager: the secret a json-bundle writes to").option("--param-type <type>", `aws-parameter-store: ${AWS_PARAMETER_TYPES.join(" | ")}`).option("--tier <tier>", `aws-parameter-store: ${AWS_PARAMETER_TIERS.join(" | ")}`).option("--kms-key-id <id>", "aws: customer-managed KMS key id, ARN, or alias").option("--env-group <id>", "render: environment group ID (evg-…)").option("--fly-app <name>", "fly: app name, as `fly apps list` shows it").option("--secret-group <id>", "northflank: secret group ID (the slug in its URL)").option("--do-app <id>", "digitalocean: App Platform app ID (the UUID in its URL)").option("--component <name>", "digitalocean: write to one component's variables (omit for app-level)").option("--env-scope <scope>", `digitalocean: ${DIGITALOCEAN_ENV_SCOPES.join(" | ")}`).option("--heroku-app <name>", "heroku: app name, as `heroku apps` shows it (or its UUID)").option("--netlify-site <id>", "netlify: site API ID (the UUID under Project configuration)").option("--no-netlify-secret", "netlify: create readable variables instead of Netlify secrets (write-only)").option("--bunnyshell-environment <id>", "bunnyshell: environment ID (omit to write a project)").option("--no-bunnyshell-secret", "bunnyshell: create variables visible in the dashboard instead of secret ones").option("--gh-repo <owner/name>", "github-actions: repository, e.g. acme/storefront").option("--gh-environment <name>", "github-actions: write to one deployment environment's secrets (needs --gh-repo)").option("--gh-org <login>", "github-actions: write organization secrets instead of a repo's").option("--gh-visibility <v>", `github-actions org secrets: ${GITHUB_ACTIONS_VISIBILITIES.join(" | ")}`).option("--gh-repo-ids <ids>", "github-actions: comma-separated numeric repository IDs for --gh-visibility selected").option("--langgraph-deployment <id>", "langgraph-platform: deployment UUID (the one in its dashboard URL)").option("--gcp-prefix <prefix>", "gcp: prepended to every secret ID, e.g. prod-storefront-").option("--gcp-replication <policy>", `gcp: ${GCP_REPLICATION_POLICIES.join(" | ")}`, "automatic").option("--gcp-locations <list>", "gcp: regions for user-managed replication, e.g. us-east1").option("--gcp-kms-key <name>", "gcp: Cloud KMS key (projects/…/cryptoKeys/…)").option("--gcp-prune-versions", "gcp: destroy the version each push supersedes, keeping one active version").option("--vault <name>", "azure-key-vault: vault name, e.g. acme-prod · claude-managed-agents: vault ID (vlt_…)").option("--allowed-hosts <list>", "claude-managed-agents: hosts every secret may be used on, comma-separated (api.example.com, *.example.com, an IPv4) — or `unrestricted`").option("--allowed-hosts-for <NAME=hosts>", "claude-managed-agents: hosts for one secret, overriding --allowed-hosts (repeatable)", collect).option("--injection-location <where>", `claude-managed-agents: ${CLAUDE_VAULT_INJECTION_LOCATIONS.join(" | ")} — which parts of a request the value is substituted into (default header)`).option("--openai-vault <id>", "openai-vault: existing OpenAI Vault ID (vault_…)").option("--openai-hosts <hosts>", "openai-vault: comma-separated exact HTTPS hostnames").option("--hf-space <owner/name>", "huggingface-spaces: Space ID, e.g. acme/support-demo (its owner and name, not a URL)").option("--name-mode <mode>", `azure-key-vault: ${AZURE_KEY_VAULT_NAME_MODES.join(" | ")} — Key Vault stores no underscores, so DATABASE_URL becomes DATABASE-URL unless you reject instead`);
14925
15080
  }
14926
15081
  /** Find a connection by id or name — nobody keeps `syc_…` ids in their head. */
14927
15082
  async function resolveConnection(ctx, orgId, ref) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@seekrit/cli",
3
- "version": "1.8.0",
3
+ "version": "1.9.1",
4
4
  "description": "End-to-end encrypted secrets manager CLI — inject decrypted secrets into any command.",
5
5
  "type": "module",
6
6
  "publishConfig": {
@@ -22,7 +22,7 @@
22
22
  "node": ">=20"
23
23
  },
24
24
  "dependencies": {
25
- "@modelcontextprotocol/sdk": "^1.30.0",
25
+ "@modelcontextprotocol/sdk": "^1.30.1",
26
26
  "commander": "^15.0.0",
27
27
  "zod": "^4.6.5"
28
28
  },