@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
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.
|
|
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.
|
|
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.
|
|
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.
|