@oxygen-agent/cli 1.837.5 → 1.837.9

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/README.md CHANGED
@@ -34,4 +34,4 @@ oxygen update
34
34
 
35
35
  For product documentation, visit https://oxygen-agent.com/docs. For support, visit https://oxygen-agent.com.
36
36
 
37
- Version: 1.837.5
37
+ Version: 1.837.9
package/dist/index.js CHANGED
@@ -10552,7 +10552,7 @@ fixed scan; watermark_cursor starts a later bounded replay. Consumers must retai
10552
10552
  }));
10553
10553
  }))
10554
10554
  .addCommand(new Command("set-photo")
10555
- .description("Set the sender's profile picture — the face that goes on every mailbox you order for this person. Pick exactly one source: --file (upload your own image; Oxygen hosts it permanently), --url (a public https image), --from-linkedin (re-mirror the photo from the attached LinkedIn account), or --clear. Hosting matters: an inbox vendor fetches the photo from its own servers HOURS after the order, so a LinkedIn CDN link (media.licdn.com, e=<epoch>) has already expired by then and the mailbox ships faceless. --file and --from-linkedin both end up Oxygen-hosted, which is why they are the safe choices. Free — no credits.")
10555
+ .description("Set the reusable sender identity's profile picture for FUTURE managed-inbox orders made with --sender <id>. Pick exactly one source: --file (upload your own image; Oxygen hosts it permanently), --url (a public https image), --from-linkedin (re-mirror the photo from the attached LinkedIn account), or --clear. Hosting matters: an inbox vendor fetches the photo HOURS after an order, so an expiring LinkedIn CDN URL can ship the mailbox faceless. This updates Oxygen's sender profile only: it does not change already-provisioned mailbox photos or call the inbox provider. For a one-off typed-name order using profile_picture_url in --mailboxes JSON, use `oxygen managed-inboxes upload-avatar <path>` instead. Free — no credits.")
10556
10556
  .argument("<id>", "Sender profile id (from `oxygen senders profiles list`).")
10557
10557
  .option("--file <path>", "Upload a PNG, JPEG, or WebP from disk (max 8MB) and use it. Oxygen hosts the image permanently, so an inbox vendor can still fetch it at provisioning time.")
10558
10558
  .option("--url <url>", "Use an image already published at a public https URL. If the link expires (e.g. media.licdn.com with e=<epoch>) the photo is kept for Oxygen's own UI but marked non-durable and NEVER sent to an inbox vendor.")
@@ -13456,7 +13456,7 @@ fixed scan; watermark_cursor starts a later bounded replay. Consumers must retai
13456
13456
  });
13457
13457
  }))
13458
13458
  .addCommand(new Command("upload-avatar")
13459
- .description("Host a mailbox profile picture and print the URL to pass as profile_picture_url. The inbox vendor FETCHES that URL from its own servers when it provisions the mailbox — often long after the order — so it must be public and permanent. A LinkedIn photo URL is neither: media.licdn.com links carry an e=<epoch> expiry and the mailbox ends up faceless. Uploads a PNG, JPEG, or WebP (max 8MB); nothing is charged.")
13459
+ .description("Host a one-off mailbox profile picture and print the URL to pass as profile_picture_url in --mailboxes JSON. For a reusable sender identity used by FUTURE --sender <id> orders, prefer `oxygen senders profiles set-photo <id> --file <path>` instead. The inbox vendor FETCHES the hosted URL when it provisions the mailbox, often long after the order, so it must be public and permanent. Uploads a PNG, JPEG, or WebP (max 8MB), then normalizes it to a metadata-free 400x400 PNG at a matching .png URL. This only hosts the image: it does not update a sender, place an order, call the inbox provider, or charge credits.")
13460
13460
  .argument("<path>", "Path to a PNG, JPEG, or WebP image.")
13461
13461
  .option("--json", "Print a JSON envelope.")
13462
13462
  .action(async (path, options) => {
@@ -144,6 +144,22 @@ export declare function putInboxAvatarObject(input: {
144
144
  storageKey: string;
145
145
  contentLength: number;
146
146
  }>;
147
+ /**
148
+ * Replace one staged avatar with provider-compatible bytes while preserving its
149
+ * public URL. The upload presign exposes that URL before confirmation, so moving
150
+ * the object to a new key during normalization would break an existing API
151
+ * promise. The org-bound key check is load-bearing: this is a bare S3 overwrite
152
+ * in a bucket shared by every tenant and several non-avatar namespaces.
153
+ */
154
+ export declare function replaceInboxAvatarObject(input: {
155
+ organizationId: string;
156
+ storageKey: string;
157
+ body: Uint8Array;
158
+ contentType: string;
159
+ }): Promise<{
160
+ storageKey: string;
161
+ contentLength: number;
162
+ }>;
147
163
  /**
148
164
  * Read an avatar back, bounded. `maxBytes` is a hard stop rather than a hint:
149
165
  * this is called from an unauthenticated route, so an object that somehow grew
@@ -334,6 +334,27 @@ export async function putInboxAvatarObject(input) {
334
334
  }));
335
335
  return { storageKey, contentLength: input.body.byteLength };
336
336
  }
337
+ /**
338
+ * Replace one staged avatar with provider-compatible bytes while preserving its
339
+ * public URL. The upload presign exposes that URL before confirmation, so moving
340
+ * the object to a new key during normalization would break an existing API
341
+ * promise. The org-bound key check is load-bearing: this is a bare S3 overwrite
342
+ * in a bucket shared by every tenant and several non-avatar namespaces.
343
+ */
344
+ export async function replaceInboxAvatarObject(input) {
345
+ if (!isInboxAvatarObjectKeyForOrganization(input.storageKey, input.organizationId)) {
346
+ throw new OxygenError("invalid_object_key", "Refusing to replace an avatar that belongs to another organization.", { exitCode: 1 });
347
+ }
348
+ const { client, config } = resolveClient();
349
+ await client.send(new PutObjectCommand({
350
+ Bucket: config.bucket,
351
+ Key: input.storageKey,
352
+ Body: input.body,
353
+ ContentLength: input.body.byteLength,
354
+ ContentType: input.contentType,
355
+ }));
356
+ return { storageKey: input.storageKey, contentLength: input.body.byteLength };
357
+ }
337
358
  /**
338
359
  * Read an avatar back, bounded. `maxBytes` is a hard stop rather than a hint:
339
360
  * this is called from an unauthenticated route, so an object that somehow grew
@@ -1,4 +1,4 @@
1
- export declare const OXYGEN_VERSION = "1.837.5";
1
+ export declare const OXYGEN_VERSION = "1.837.9";
2
2
  export declare const OXYGEN_MINIMUM_CLI_VERSION = "1.181.0";
3
3
  export declare const MANAGED_INBOX_MINIMUM_CLI_VERSION = "1.326.2";
4
4
  export declare const SUPPORT_AGENT_REPLY_MINIMUM_CLI_VERSION = "1.747.0";
@@ -1,4 +1,4 @@
1
- export const OXYGEN_VERSION = "1.837.5";
1
+ export const OXYGEN_VERSION = "1.837.9";
2
2
  // The GLOBAL CLI compatibility floor: the oldest CLI allowed to call any
3
3
  // operational route. Raising it hard-rejects every older CLI from the entire
4
4
  // product, so it obeys one law, enforced by scripts/ci/cli-min-version-gate.mjs:
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@oxygen-agent/cli",
3
- "version": "1.837.5",
3
+ "version": "1.837.9",
4
4
  "private": false,
5
5
  "license": "UNLICENSED",
6
6
  "type": "module",