@wraps.dev/cli 3.9.0 → 3.10.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli.js CHANGED
@@ -30451,17 +30451,31 @@ async function attachConsoleRoleInvoke(config2) {
30451
30451
  }
30452
30452
  new aws22.iam.RolePolicy(target.logicalName, {
30453
30453
  role: target.roleName,
30454
- policy: config2.enforcerArn.apply(
30455
- (arn) => JSON.stringify({
30456
- Version: "2012-10-17",
30457
- Statement: [
30458
- {
30459
- Effect: "Allow",
30460
- Action: "lambda:InvokeFunction",
30461
- Resource: arn
30462
- }
30463
- ]
30464
- })
30454
+ policy: config2.policyTableArn.apply(
30455
+ (tableArn) => config2.enforcerArn.apply(
30456
+ (enforcerArn) => JSON.stringify({
30457
+ Version: "2012-10-17",
30458
+ Statement: [
30459
+ {
30460
+ Effect: "Allow",
30461
+ Action: "lambda:InvokeFunction",
30462
+ Resource: enforcerArn
30463
+ },
30464
+ {
30465
+ // syncAgentPolicy() assumes this role and writes the
30466
+ // CONFIG#<agentId> item the enforcer reads to identify an
30467
+ // agent. Without it every send returns "unknown agent" — the
30468
+ // agent is created but permanently unusable.
30469
+ // PutItem is the ONLY DynamoDB action the API performs against
30470
+ // the customer account; policy edits and kills are full-item
30471
+ // Puts through the same path.
30472
+ Effect: "Allow",
30473
+ Action: "dynamodb:PutItem",
30474
+ Resource: tableArn
30475
+ }
30476
+ ]
30477
+ })
30478
+ )
30465
30479
  )
30466
30480
  });
30467
30481
  granted += 1;
@@ -37233,7 +37247,6 @@ Run ${pc17.cyan("wraps email init")} to deploy infrastructure first.
37233
37247
  const smsConfig = metadata.services.sms?.config;
37234
37248
  const policy = buildConsolePolicyDocument(emailConfig, smsConfig);
37235
37249
  const sendingEnabled = !emailConfig || emailConfig.sendingEnabled !== false;
37236
- const eventTracking = emailConfig?.eventTracking;
37237
37250
  const emailArchiving = emailConfig?.emailArchiving;
37238
37251
  const smsEnabled = !!smsConfig;
37239
37252
  const smsSendingEnabled = smsConfig && smsConfig.sendingEnabled !== false;
@@ -37347,9 +37360,6 @@ ${pc17.bold("Permissions:")}`);
37347
37360
  console.log(
37348
37361
  ` ${pc17.green("\u2713")} DynamoDB read access (including DescribeTable)`
37349
37362
  );
37350
- if (eventTracking?.enabled) {
37351
- console.log(` ${pc17.green("\u2713")} EventBridge and SQS access`);
37352
- }
37353
37363
  if (emailArchiving?.enabled) {
37354
37364
  console.log(` ${pc17.green("\u2713")} Mail Manager Archive access`);
37355
37365
  }
@@ -37411,7 +37421,7 @@ function buildConsolePolicyDocument(emailConfig, smsConfig) {
37411
37421
  });
37412
37422
  statements.push({
37413
37423
  Effect: "Allow",
37414
- Action: ["s3:HeadBucket"],
37424
+ Action: ["s3:ListBucket"],
37415
37425
  Resource: "arn:aws:s3:::wraps-inbound-*"
37416
37426
  });
37417
37427
  statements.push({
@@ -37473,26 +37483,6 @@ function buildConsolePolicyDocument(emailConfig, smsConfig) {
37473
37483
  "arn:aws:dynamodb:*:*:table/wraps-email-*/index/*"
37474
37484
  ]
37475
37485
  });
37476
- const eventTracking = emailConfig?.eventTracking;
37477
- if (eventTracking?.enabled) {
37478
- statements.push({
37479
- Effect: "Allow",
37480
- Action: ["events:PutEvents", "events:DescribeEventBus"],
37481
- Resource: "arn:aws:events:*:*:event-bus/wraps-email-*"
37482
- });
37483
- }
37484
- if (eventTracking?.enabled) {
37485
- statements.push({
37486
- Effect: "Allow",
37487
- Action: [
37488
- "sqs:SendMessage",
37489
- "sqs:ReceiveMessage",
37490
- "sqs:DeleteMessage",
37491
- "sqs:GetQueueAttributes"
37492
- ],
37493
- Resource: "arn:aws:sqs:*:*:wraps-email-*"
37494
- });
37495
- }
37496
37486
  const emailArchiving = emailConfig?.emailArchiving;
37497
37487
  if (emailArchiving?.enabled) {
37498
37488
  statements.push({
@@ -37514,12 +37504,7 @@ function buildConsolePolicyDocument(emailConfig, smsConfig) {
37514
37504
  if (inbound?.enabled) {
37515
37505
  statements.push({
37516
37506
  Effect: "Allow",
37517
- Action: [
37518
- "s3:HeadBucket",
37519
- "s3:ListBucket",
37520
- "s3:GetObject",
37521
- "s3:GetObjectTagging"
37522
- ],
37507
+ Action: ["s3:ListBucket", "s3:GetObject", "s3:GetObjectTagging"],
37523
37508
  Resource: [
37524
37509
  "arn:aws:s3:::wraps-inbound-*",
37525
37510
  "arn:aws:s3:::wraps-inbound-*/*"
@@ -39706,7 +39691,8 @@ async function deployEmailStack(config2) {
39706
39691
  });
39707
39692
  const { createAgentUser: createAgentUser2, attachConsoleRoleInvoke: attachConsoleRoleInvoke2 } = await Promise.resolve().then(() => (init_iam_agent_user(), iam_agent_user_exports));
39708
39693
  await attachConsoleRoleInvoke2({
39709
- enforcerArn: enforcer.lambdaFunction.arn
39694
+ enforcerArn: enforcer.lambdaFunction.arn,
39695
+ policyTableArn: policyTable.arn
39710
39696
  });
39711
39697
  agentCredentials = {};
39712
39698
  agentAliasArns = {};
@@ -40231,7 +40217,7 @@ ${suggestion}
40231
40217
  metadata.timestamp = (/* @__PURE__ */ new Date()).toISOString();
40232
40218
  await saveConnectionMetadata(metadata);
40233
40219
  });
40234
- await progress.execute("Syncing agent policy", async () => {
40220
+ const sync = await progress.execute("Syncing agent policy", async () => {
40235
40221
  const resp = await api.post(`/v1/agents/${created.id}/policy-sync`, {
40236
40222
  credentialUserArn: creds.userArn,
40237
40223
  enforcerFunctionArn,
@@ -40240,7 +40226,9 @@ ${suggestion}
40240
40226
  if (!resp.ok) {
40241
40227
  throw new Error(await parseAgentApiError(resp));
40242
40228
  }
40229
+ return await resp.json();
40243
40230
  });
40231
+ const syncFailed = sync.syncStatus === "failed";
40244
40232
  if (isJsonMode()) {
40245
40233
  jsonSuccess("email.agent.create", {
40246
40234
  id: created.id,
@@ -40255,13 +40243,23 @@ ${suggestion}
40255
40243
  policyTableName: outputs.agentPolicyTableName ?? null,
40256
40244
  accessKeyId: creds.accessKeyId,
40257
40245
  secretAccessKey: creds.secretAccessKey,
40258
- userArn: creds.userArn
40246
+ userArn: creds.userArn,
40247
+ // The command DID create the agent and mint a real credential even when
40248
+ // the sync failed — jsonSuccess (not jsonError) is deliberate here so
40249
+ // the credential doesn't have to be smuggled through an error payload a
40250
+ // scripted caller isn't looking at. syncStatus is the field to branch on.
40251
+ syncStatus: sync.syncStatus ?? "unknown",
40252
+ warning: sync.warning ?? null
40259
40253
  });
40260
40254
  return;
40261
40255
  }
40262
40256
  progress.stop();
40263
40257
  console.log();
40264
- clack18.log.success(pc20.bold(`Agent "${name}" is ready.`));
40258
+ if (syncFailed) {
40259
+ clack18.log.warn(pc20.bold(`Agent "${name}" was created but CANNOT send yet.`));
40260
+ } else {
40261
+ clack18.log.success(pc20.bold(`Agent "${name}" is ready.`));
40262
+ }
40265
40263
  console.log();
40266
40264
  console.log(` ${pc20.dim("Address:")} ${pc20.cyan(emailAddress)}`);
40267
40265
  console.log(` ${pc20.dim("Agent ID:")} ${pc20.cyan(created.id)}`);
@@ -40276,14 +40274,25 @@ ${suggestion}
40276
40274
  ].join("\n");
40277
40275
  clack18.note(mcpEnv, "MCP env \u2014 save now, the secret is shown only once");
40278
40276
  console.log();
40279
- console.log(pc20.bold("Next steps:"));
40280
- console.log(
40281
- ` 1. Add the env above to your agent's ${pc20.cyan("@wraps.dev/mcp")} config`
40282
- );
40283
- console.log(
40284
- ` 2. Review pending sends: ${pc20.cyan("wraps email agent list")}`
40285
- );
40286
- console.log();
40277
+ if (syncFailed) {
40278
+ console.log(pc20.bold("This agent cannot send until the sync succeeds:"));
40279
+ if (sync.warning) {
40280
+ console.log(` ${pc20.yellow(sync.warning)}`);
40281
+ }
40282
+ console.log(
40283
+ ` Still failing after that? Reach us: ${pc20.cyan("wraps support")}`
40284
+ );
40285
+ console.log();
40286
+ } else {
40287
+ console.log(pc20.bold("Next steps:"));
40288
+ console.log(
40289
+ ` 1. Add the env above to your agent's ${pc20.cyan("@wraps.dev/mcp")} config`
40290
+ );
40291
+ console.log(
40292
+ ` 2. Review pending sends: ${pc20.cyan("wraps email agent list")}`
40293
+ );
40294
+ console.log();
40295
+ }
40287
40296
  }
40288
40297
  async function agentList(options) {
40289
40298
  const api = await createAgentApiClient(options.token);