@oxygen-agent/cli 1.244.2 → 1.246.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/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.244.2
37
+ Version: 1.246.0
package/dist/index.js CHANGED
@@ -323,6 +323,60 @@ function readCustomIntegrationManifest(options) {
323
323
  }
324
324
  return parseJsonObject(manifestJson ?? readFileSync(resolve(manifestPath ?? ""), "utf8"));
325
325
  }
326
+ const CUSTOM_INTEGRATION_SECRET_KEYS = ["API_KEY", "TOKEN", "PASSWORD", "SECRET"];
327
+ function readCustomIntegrationSecret(options) {
328
+ const apiKey = readOption(options.apiKey);
329
+ const secretsFile = readOption(options.secretsFile);
330
+ if (apiKey && secretsFile) {
331
+ throw new OxygenError("invalid_request", "Pass either --api-key or --secrets-file, not both.", {
332
+ exitCode: 1,
333
+ });
334
+ }
335
+ if (apiKey)
336
+ return apiKey;
337
+ if (!secretsFile) {
338
+ throw new OxygenError("invalid_request", "Pass --api-key or --secrets-file.", {
339
+ exitCode: 1,
340
+ });
341
+ }
342
+ const entries = parseEnvFile(readFileSync(resolve(secretsFile), "utf8"));
343
+ const keys = Object.keys(entries);
344
+ if (keys.length === 0) {
345
+ throw new OxygenError("invalid_request", "Secrets file has no KEY=VALUE entries.", {
346
+ details: { file: secretsFile },
347
+ exitCode: 1,
348
+ });
349
+ }
350
+ if (keys.length === 1)
351
+ return entries[keys[0]];
352
+ const preferred = CUSTOM_INTEGRATION_SECRET_KEYS.find((key) => entries[key] !== undefined);
353
+ if (preferred)
354
+ return entries[preferred];
355
+ throw new OxygenError("invalid_request", "Secrets file is ambiguous: use a single entry or name one API_KEY, TOKEN, PASSWORD, or SECRET.", {
356
+ details: { file: secretsFile, keys },
357
+ exitCode: 1,
358
+ });
359
+ }
360
+ function parseEnvFile(content) {
361
+ const entries = {};
362
+ for (const rawLine of content.split(/\r?\n/)) {
363
+ const line = rawLine.trim();
364
+ if (!line || line.startsWith("#"))
365
+ continue;
366
+ const separator = line.indexOf("=");
367
+ if (separator <= 0)
368
+ continue;
369
+ const key = line.slice(0, separator).trim().replace(/^export\s+/, "");
370
+ let value = line.slice(separator + 1).trim();
371
+ if ((value.startsWith("\"") && value.endsWith("\"") && value.length >= 2)
372
+ || (value.startsWith("'") && value.endsWith("'") && value.length >= 2)) {
373
+ value = value.slice(1, -1);
374
+ }
375
+ if (key && value)
376
+ entries[key] = value;
377
+ }
378
+ return entries;
379
+ }
326
380
  function readFileIfPresent(value) {
327
381
  const candidate = resolve(value);
328
382
  try {
@@ -4205,7 +4259,7 @@ export function createProgram() {
4205
4259
  .command("custom-integrations")
4206
4260
  .description("Custom HTTP integration commands.")
4207
4261
  .addCommand(new Command("apply")
4208
- .description("Create or update a custom HTTP integration manifest. Store credentials from the web Connections page.")
4262
+ .description("Create or update a custom HTTP integration manifest. Attach credentials with `custom-integrations connect`.")
4209
4263
  .option("--manifest <path>", "Path to a custom HTTP manifest JSON file.")
4210
4264
  .option("--manifest-json <json>", "Custom HTTP manifest as a JSON object.")
4211
4265
  .option("--json", "Print a JSON envelope.")
@@ -4217,6 +4271,21 @@ export function createProgram() {
4217
4271
  body: { manifest },
4218
4272
  });
4219
4273
  });
4274
+ }))
4275
+ .addCommand(new Command("connect")
4276
+ .description("Attach the credential (bearer token, API key, or basic password) for an applied custom HTTP integration.")
4277
+ .argument("<slug>", "Custom integration slug from the applied manifest.")
4278
+ .option("--api-key <value>", "Credential value. Prefer --secrets-file to keep it out of shell history.")
4279
+ .option("--secrets-file <path>", "Path to a .env-style file holding the credential (a single entry, or one named API_KEY/TOKEN/PASSWORD/SECRET).")
4280
+ .option("--json", "Print a JSON envelope.")
4281
+ .action(async (slug, options) => {
4282
+ await handleAsyncAction("custom-integrations connect", options, () => {
4283
+ const apiKey = readCustomIntegrationSecret(options);
4284
+ return requestOxygen("/api/cli/custom-integrations/connect", {
4285
+ method: "POST",
4286
+ body: { slug, api_key: apiKey },
4287
+ });
4288
+ });
4220
4289
  }))
4221
4290
  .addCommand(new Command("list")
4222
4291
  .description("List custom HTTP integrations for the active organization.")
@@ -1,2 +1,2 @@
1
- export declare const OXYGEN_VERSION = "1.244.2";
1
+ export declare const OXYGEN_VERSION = "1.246.0";
2
2
  export declare const OXYGEN_MINIMUM_CLI_VERSION = "1.181.0";
@@ -1,4 +1,4 @@
1
- export const OXYGEN_VERSION = "1.244.2";
1
+ export const OXYGEN_VERSION = "1.246.0";
2
2
  // Bump this only when deployed CLI/API contracts require a newer CLI.
3
3
  // 1.181.0: paid table action runs and background columns run require
4
4
  // approved=true in addition to max_credits; older CLIs cannot send the flag.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@oxygen-agent/cli",
3
- "version": "1.244.2",
3
+ "version": "1.246.0",
4
4
  "private": false,
5
5
  "license": "UNLICENSED",
6
6
  "type": "module",