@tryarcanist/cli 0.1.160 → 0.1.161
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/index.js +194 -265
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -138,6 +138,16 @@ async function apiFetchText(config, path, init) {
|
|
|
138
138
|
const res = await apiRequest(config, path, init);
|
|
139
139
|
return res.text();
|
|
140
140
|
}
|
|
141
|
+
async function resolveBusinessId(config, options) {
|
|
142
|
+
if (options.business && options.business.trim()) return options.business.trim();
|
|
143
|
+
const whoami = await apiFetch(config, "/api/auth/whoami");
|
|
144
|
+
if (whoami.businessId && whoami.businessId.trim()) return whoami.businessId;
|
|
145
|
+
throw new CliError("user", "--business is required when the authenticated token has no business context.");
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
// src/runtime.ts
|
|
149
|
+
import { randomUUID } from "crypto";
|
|
150
|
+
import { createInterface } from "readline/promises";
|
|
141
151
|
|
|
142
152
|
// src/config.ts
|
|
143
153
|
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "fs";
|
|
@@ -289,8 +299,6 @@ function isLoopbackHost(parsed) {
|
|
|
289
299
|
}
|
|
290
300
|
|
|
291
301
|
// src/runtime.ts
|
|
292
|
-
import { randomUUID } from "crypto";
|
|
293
|
-
import { createInterface } from "readline/promises";
|
|
294
302
|
var ASCII_FIRST_PRINTABLE = 32;
|
|
295
303
|
var ASCII_DELETE = 127;
|
|
296
304
|
var ANSI_CONTROL_SEQUENCE = /\u001b\[[0-9:;<=>?]*[ -/]*[@-~]/g;
|
|
@@ -306,6 +314,17 @@ function writeJson(value) {
|
|
|
306
314
|
process.stdout.write(`${JSON.stringify(value)}
|
|
307
315
|
`);
|
|
308
316
|
}
|
|
317
|
+
function emit(command, options, payload, printer) {
|
|
318
|
+
if (isJson(command, options)) {
|
|
319
|
+
writeJson(payload);
|
|
320
|
+
return;
|
|
321
|
+
}
|
|
322
|
+
printer(payload);
|
|
323
|
+
}
|
|
324
|
+
function resolveBusinessContext(command, options = {}) {
|
|
325
|
+
const runtime = getRuntimeOptions(command, options);
|
|
326
|
+
return { runtime, config: requireConfig(runtime) };
|
|
327
|
+
}
|
|
309
328
|
async function readStdin() {
|
|
310
329
|
const chunks = [];
|
|
311
330
|
for await (const chunk of process.stdin) {
|
|
@@ -468,15 +487,12 @@ function isControlCharacter(char) {
|
|
|
468
487
|
|
|
469
488
|
// src/commands/auth.ts
|
|
470
489
|
async function whoamiCommand(options, command) {
|
|
471
|
-
const
|
|
472
|
-
const config = requireConfig(runtime);
|
|
490
|
+
const { config } = resolveBusinessContext(command, options);
|
|
473
491
|
const payload = await apiFetch(config, "/api/auth/whoami");
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
}
|
|
478
|
-
console.log(`User: ${String(payload.email ?? payload.userId ?? "unknown")}`);
|
|
479
|
-
if (payload.tokenScope) console.log(`Token scope: ${String(payload.tokenScope)}`);
|
|
492
|
+
emit(command, options, payload, (whoami) => {
|
|
493
|
+
console.log(`User: ${String(whoami.email ?? whoami.userId ?? "unknown")}`);
|
|
494
|
+
if (whoami.tokenScope) console.log(`Token scope: ${String(whoami.tokenScope)}`);
|
|
495
|
+
});
|
|
480
496
|
}
|
|
481
497
|
|
|
482
498
|
// ../../shared/github/repo-url.ts
|
|
@@ -1517,6 +1533,7 @@ function mergeToolCall(previous, incoming) {
|
|
|
1517
1533
|
...incoming.inputEstimatedTokens === void 0 && previous.inputEstimatedTokens !== void 0 ? { inputEstimatedTokens: previous.inputEstimatedTokens } : {},
|
|
1518
1534
|
...incoming.outputEstimatedTokens === void 0 && previous.outputEstimatedTokens !== void 0 ? { outputEstimatedTokens: previous.outputEstimatedTokens } : {},
|
|
1519
1535
|
...incoming.outputChars === void 0 && previous.outputChars !== void 0 ? { outputChars: previous.outputChars } : {},
|
|
1536
|
+
...incoming.failure === void 0 && previous.failure !== void 0 ? { failure: previous.failure } : {},
|
|
1520
1537
|
...incoming.duplicateCount === void 0 && previous.duplicateCount !== void 0 ? { duplicateCount: previous.duplicateCount } : {}
|
|
1521
1538
|
};
|
|
1522
1539
|
}
|
|
@@ -1530,6 +1547,7 @@ function applyToolCallUpdate(previous, data) {
|
|
|
1530
1547
|
...toolStatus ? { toolStatus } : {},
|
|
1531
1548
|
...typeof data?.outputEstimatedTokens === "number" ? { outputEstimatedTokens: data.outputEstimatedTokens } : {},
|
|
1532
1549
|
...typeof data?.outputChars === "number" ? { outputChars: data.outputChars } : {},
|
|
1550
|
+
...isRecord(data?.failure) ? { failure: data.failure } : {},
|
|
1533
1551
|
...typeof data?.truncated === "boolean" ? { truncated: data.truncated } : {}
|
|
1534
1552
|
};
|
|
1535
1553
|
}
|
|
@@ -1800,7 +1818,8 @@ function projectToolCall(data, state) {
|
|
|
1800
1818
|
...typeof data?.truncated === "boolean" ? { truncated: data.truncated } : {},
|
|
1801
1819
|
...typeof data?.inputEstimatedTokens === "number" ? { inputEstimatedTokens: data.inputEstimatedTokens } : {},
|
|
1802
1820
|
...typeof data?.outputEstimatedTokens === "number" ? { outputEstimatedTokens: data.outputEstimatedTokens } : {},
|
|
1803
|
-
...typeof data?.outputChars === "number" ? { outputChars: data.outputChars } : {}
|
|
1821
|
+
...typeof data?.outputChars === "number" ? { outputChars: data.outputChars } : {},
|
|
1822
|
+
...isRecord(data?.failure) ? { failure: data.failure } : {}
|
|
1804
1823
|
};
|
|
1805
1824
|
state.merged[existingIdx] = mergeToolCall(previous, nextEntry);
|
|
1806
1825
|
}
|
|
@@ -1817,7 +1836,8 @@ function projectToolCall(data, state) {
|
|
|
1817
1836
|
...typeof data?.truncated === "boolean" ? { truncated: data.truncated } : {},
|
|
1818
1837
|
...typeof data?.inputEstimatedTokens === "number" ? { inputEstimatedTokens: data.inputEstimatedTokens } : {},
|
|
1819
1838
|
...typeof data?.outputEstimatedTokens === "number" ? { outputEstimatedTokens: data.outputEstimatedTokens } : {},
|
|
1820
|
-
...typeof data?.outputChars === "number" ? { outputChars: data.outputChars } : {}
|
|
1839
|
+
...typeof data?.outputChars === "number" ? { outputChars: data.outputChars } : {},
|
|
1840
|
+
...isRecord(data?.failure) ? { failure: data.failure } : {}
|
|
1821
1841
|
};
|
|
1822
1842
|
state.toolCallIndexById.set(id, state.merged.length);
|
|
1823
1843
|
state.merged.push(nextEntry);
|
|
@@ -2972,105 +2992,88 @@ function parseRepoArg(value) {
|
|
|
2972
2992
|
if (!owner || !repo || extra) throw new CliError("user", "repo must be owner/name or a GitHub URL");
|
|
2973
2993
|
return { owner, repo };
|
|
2974
2994
|
}
|
|
2975
|
-
function encodePathSegment(value) {
|
|
2976
|
-
return encodeURIComponent(value);
|
|
2977
|
-
}
|
|
2978
|
-
async function resolveBusinessId(config, options) {
|
|
2979
|
-
if (options.business && options.business.trim()) return options.business.trim();
|
|
2980
|
-
const whoami = await apiFetch(config, "/api/auth/whoami");
|
|
2981
|
-
if (whoami.businessId && whoami.businessId.trim()) return whoami.businessId;
|
|
2982
|
-
throw new CliError("user", "--business is required when the authenticated token has no business context.");
|
|
2983
|
-
}
|
|
2984
2995
|
async function egressSourceSetCommand(sourceRepoArg, options = {}, command) {
|
|
2985
|
-
const
|
|
2986
|
-
const config = requireConfig(runtime);
|
|
2996
|
+
const { config } = resolveBusinessContext(command, options);
|
|
2987
2997
|
const businessId = await resolveBusinessId(config, options);
|
|
2988
2998
|
const source = parseRepoArg(sourceRepoArg);
|
|
2989
2999
|
const payload = await apiFetch(
|
|
2990
3000
|
config,
|
|
2991
|
-
`/api/businesses/${
|
|
3001
|
+
`/api/businesses/${encodeURIComponent(businessId)}/egress-allowlist/source`,
|
|
2992
3002
|
{
|
|
2993
3003
|
method: "PUT",
|
|
2994
3004
|
body: JSON.stringify({ sourceRepoOwner: source.owner, sourceRepoName: source.repo })
|
|
2995
3005
|
}
|
|
2996
3006
|
);
|
|
2997
|
-
|
|
2998
|
-
|
|
2999
|
-
|
|
3000
|
-
|
|
3001
|
-
|
|
3007
|
+
emit(
|
|
3008
|
+
command,
|
|
3009
|
+
options,
|
|
3010
|
+
payload,
|
|
3011
|
+
() => console.log(`Set egress allowlist source to ${source.owner}/${source.repo}:${EGRESS_ALLOWLIST_SOURCE_PATH}.`)
|
|
3012
|
+
);
|
|
3002
3013
|
}
|
|
3003
3014
|
async function egressSourceGetCommand(options = {}, command) {
|
|
3004
|
-
const
|
|
3005
|
-
const config = requireConfig(runtime);
|
|
3015
|
+
const { config } = resolveBusinessContext(command, options);
|
|
3006
3016
|
const businessId = await resolveBusinessId(config, options);
|
|
3007
3017
|
const payload = await apiFetch(
|
|
3008
3018
|
config,
|
|
3009
|
-
`/api/businesses/${
|
|
3019
|
+
`/api/businesses/${encodeURIComponent(businessId)}/egress-allowlist/source`
|
|
3010
3020
|
);
|
|
3011
|
-
|
|
3012
|
-
|
|
3013
|
-
|
|
3014
|
-
|
|
3015
|
-
|
|
3016
|
-
console.log(
|
|
3017
|
-
|
|
3018
|
-
|
|
3019
|
-
|
|
3020
|
-
|
|
3021
|
-
);
|
|
3022
|
-
console.log(`${payload.domains.length} ${payload.domains.length === 1 ? "domain" : "domains"}.`);
|
|
3021
|
+
emit(command, options, payload, (sourcePayload) => {
|
|
3022
|
+
if (!sourcePayload.source) {
|
|
3023
|
+
console.log("No egress allowlist source configured.");
|
|
3024
|
+
return;
|
|
3025
|
+
}
|
|
3026
|
+
console.log(
|
|
3027
|
+
`${sourcePayload.source.sourceRepoOwner}/${sourcePayload.source.sourceRepoName}:${sourcePayload.path} (${sourcePayload.defaultBranch ?? "default branch"})`
|
|
3028
|
+
);
|
|
3029
|
+
console.log(`${sourcePayload.domains.length} ${sourcePayload.domains.length === 1 ? "domain" : "domains"}.`);
|
|
3030
|
+
});
|
|
3023
3031
|
}
|
|
3024
3032
|
async function egressAddCommand(domains, options = {}, command) {
|
|
3025
|
-
const
|
|
3026
|
-
const config = requireConfig(runtime);
|
|
3033
|
+
const { config } = resolveBusinessContext(command, options);
|
|
3027
3034
|
const businessId = await resolveBusinessId(config, options);
|
|
3028
3035
|
const normalized = normalizeEgressDomains(domains, "domains");
|
|
3029
3036
|
const payload = await apiFetch(
|
|
3030
3037
|
config,
|
|
3031
|
-
`/api/businesses/${
|
|
3038
|
+
`/api/businesses/${encodeURIComponent(businessId)}/egress-allowlist/pull-request`,
|
|
3032
3039
|
{
|
|
3033
3040
|
method: "POST",
|
|
3034
3041
|
body: JSON.stringify({ domains: normalized, ...options.reason ? { reason: options.reason } : {} })
|
|
3035
3042
|
}
|
|
3036
3043
|
);
|
|
3037
|
-
|
|
3038
|
-
|
|
3039
|
-
|
|
3040
|
-
|
|
3041
|
-
|
|
3042
|
-
console.log(
|
|
3043
|
-
|
|
3044
|
-
}
|
|
3045
|
-
console.log(`Egress allowlist PR ${payload.status}: ${payload.prUrl}`);
|
|
3046
|
-
console.log(`Added: ${payload.addedDomains.join(", ")}`);
|
|
3044
|
+
emit(command, options, payload, (addPayload) => {
|
|
3045
|
+
if (addPayload.status === "unchanged") {
|
|
3046
|
+
console.log("All requested domains are already present in the source file.");
|
|
3047
|
+
return;
|
|
3048
|
+
}
|
|
3049
|
+
console.log(`Egress allowlist PR ${addPayload.status}: ${addPayload.prUrl}`);
|
|
3050
|
+
console.log(`Added: ${addPayload.addedDomains.join(", ")}`);
|
|
3051
|
+
});
|
|
3047
3052
|
}
|
|
3048
3053
|
async function egressSyncCommand(options = {}, command) {
|
|
3049
|
-
const
|
|
3050
|
-
const config = requireConfig(runtime);
|
|
3054
|
+
const { config } = resolveBusinessContext(command, options);
|
|
3051
3055
|
const businessId = await resolveBusinessId(config, options);
|
|
3052
3056
|
const payload = await apiFetch(
|
|
3053
3057
|
config,
|
|
3054
|
-
`/api/businesses/${
|
|
3058
|
+
`/api/businesses/${encodeURIComponent(businessId)}/egress-allowlist/sync`,
|
|
3055
3059
|
{ method: "POST" }
|
|
3056
3060
|
);
|
|
3057
|
-
|
|
3058
|
-
|
|
3059
|
-
|
|
3060
|
-
|
|
3061
|
-
|
|
3062
|
-
|
|
3061
|
+
emit(
|
|
3062
|
+
command,
|
|
3063
|
+
options,
|
|
3064
|
+
payload,
|
|
3065
|
+
(syncPayload) => console.log(
|
|
3066
|
+
`Applied ${syncPayload.egressAllowlist.length} egress allowlist domains from ${syncPayload.source.sourceRepoOwner}/${syncPayload.source.sourceRepoName}:${syncPayload.path}.`
|
|
3067
|
+
)
|
|
3063
3068
|
);
|
|
3064
3069
|
}
|
|
3065
3070
|
async function egressValidateCommand(path = EGRESS_ALLOWLIST_SOURCE_PATH, options = {}, command) {
|
|
3066
3071
|
const content = readFileSync2(path, "utf8");
|
|
3067
3072
|
const domains = parseEgressAllowlistSourceFile(content, path);
|
|
3068
|
-
|
|
3069
|
-
|
|
3070
|
-
|
|
3071
|
-
}
|
|
3072
|
-
console.log(`Valid egress allowlist: ${path}`);
|
|
3073
|
-
console.log(`${domains.length} ${domains.length === 1 ? "domain" : "domains"}.`);
|
|
3073
|
+
emit(command, options, { ok: true, path, domains }, (payload) => {
|
|
3074
|
+
console.log(`Valid egress allowlist: ${payload.path}`);
|
|
3075
|
+
console.log(`${payload.domains.length} ${payload.domains.length === 1 ? "domain" : "domains"}.`);
|
|
3076
|
+
});
|
|
3074
3077
|
}
|
|
3075
3078
|
|
|
3076
3079
|
// src/commands/login.ts
|
|
@@ -3714,15 +3717,6 @@ function parseRepoArg2(value, fallback) {
|
|
|
3714
3717
|
function repoPath(repo) {
|
|
3715
3718
|
return `${repo.owner}/${repo.repo}`;
|
|
3716
3719
|
}
|
|
3717
|
-
function encodePathSegment2(value) {
|
|
3718
|
-
return encodeURIComponent(value);
|
|
3719
|
-
}
|
|
3720
|
-
async function resolveBusinessId2(config, options) {
|
|
3721
|
-
if (options.business && options.business.trim()) return options.business.trim();
|
|
3722
|
-
const whoami = await apiFetch(config, "/api/auth/whoami");
|
|
3723
|
-
if (whoami.businessId && whoami.businessId.trim()) return whoami.businessId;
|
|
3724
|
-
throw new CliError("user", "--business is required when the authenticated token has no business context.");
|
|
3725
|
-
}
|
|
3726
3720
|
function parsePollInterval2(value) {
|
|
3727
3721
|
if (!value) return DEFAULT_POLL_INTERVAL_MS;
|
|
3728
3722
|
const parsed = Number(value);
|
|
@@ -3731,9 +3725,6 @@ function parsePollInterval2(value) {
|
|
|
3731
3725
|
}
|
|
3732
3726
|
return parsed;
|
|
3733
3727
|
}
|
|
3734
|
-
function sleep2(ms) {
|
|
3735
|
-
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
3736
|
-
}
|
|
3737
3728
|
function printBuildRequest(buildRequest) {
|
|
3738
3729
|
console.log(
|
|
3739
3730
|
[
|
|
@@ -3856,7 +3847,7 @@ function buildLogsPath(businessId, buildId, options = {}) {
|
|
|
3856
3847
|
if (options.afterSequence != null) params.set("afterSequence", String(options.afterSequence));
|
|
3857
3848
|
if (options.limit != null) params.set("limit", String(options.limit));
|
|
3858
3849
|
const suffix = params.toString() ? `?${params.toString()}` : "";
|
|
3859
|
-
return `/api/businesses/${
|
|
3850
|
+
return `/api/businesses/${encodeURIComponent(businessId)}/sandbox-layer/build-requests/${encodeURIComponent(
|
|
3860
3851
|
buildId
|
|
3861
3852
|
)}/logs${suffix}`;
|
|
3862
3853
|
}
|
|
@@ -3873,12 +3864,12 @@ async function waitForBuild(config, businessId, buildId, options) {
|
|
|
3873
3864
|
}
|
|
3874
3865
|
const status = await apiFetch(
|
|
3875
3866
|
config,
|
|
3876
|
-
`/api/businesses/${
|
|
3867
|
+
`/api/businesses/${encodeURIComponent(businessId)}/sandbox-layer/build-requests/${encodeURIComponent(buildId)}`
|
|
3877
3868
|
);
|
|
3878
3869
|
if (TERMINAL_BUILD_STATUSES.has(status.buildRequest.status)) {
|
|
3879
3870
|
return status.buildRequest;
|
|
3880
3871
|
}
|
|
3881
|
-
await
|
|
3872
|
+
await sleep(options.pollIntervalMs);
|
|
3882
3873
|
}
|
|
3883
3874
|
}
|
|
3884
3875
|
function formatValidationPayload(input) {
|
|
@@ -3953,11 +3944,7 @@ async function sandboxInitCommand(options = {}, command) {
|
|
|
3953
3944
|
"utf8"
|
|
3954
3945
|
);
|
|
3955
3946
|
const payload = { ok: true, manifestPath: DEFAULT_MANIFEST_PATH, layerPath };
|
|
3956
|
-
|
|
3957
|
-
writeJson(payload);
|
|
3958
|
-
return;
|
|
3959
|
-
}
|
|
3960
|
-
console.log(`Created ${DEFAULT_MANIFEST_PATH} and ${layerPath}`);
|
|
3947
|
+
emit(command, runtime, payload, () => console.log(`Created ${DEFAULT_MANIFEST_PATH} and ${layerPath}`));
|
|
3961
3948
|
}
|
|
3962
3949
|
async function sandboxValidateCommand(options = {}, command) {
|
|
3963
3950
|
const manifestPath = options.manifest ?? DEFAULT_MANIFEST_PATH;
|
|
@@ -3970,34 +3957,31 @@ async function sandboxValidateCommand(options = {}, command) {
|
|
|
3970
3957
|
const layerText = readFileSync3(layerPath, "utf8");
|
|
3971
3958
|
const parsed = await parseSandboxLayerSource({ manifestPath, manifestText, layerPath, layerText });
|
|
3972
3959
|
const payload = formatValidationPayload({ manifestPath, layerPath, parsed });
|
|
3973
|
-
|
|
3974
|
-
|
|
3975
|
-
|
|
3976
|
-
|
|
3977
|
-
|
|
3978
|
-
|
|
3979
|
-
|
|
3980
|
-
|
|
3981
|
-
|
|
3982
|
-
console.log(`Smoke commands: ${payload.smokeCommandCount}`);
|
|
3983
|
-
console.log(`Next: ${nextBuildCommand(manifestPath)}`);
|
|
3960
|
+
emit(command, options, payload, (validationPayload) => {
|
|
3961
|
+
console.log("Valid sandbox template.");
|
|
3962
|
+
console.log(`Manifest: ${validationPayload.manifestPath}`);
|
|
3963
|
+
console.log(`Layer: ${validationPayload.layerPath}`);
|
|
3964
|
+
console.log(`Normalized source hash: ${validationPayload.normalizedSourceHash}`);
|
|
3965
|
+
console.log(`Instructions: ${validationPayload.instructionCount}`);
|
|
3966
|
+
console.log(`Smoke commands: ${validationPayload.smokeCommandCount}`);
|
|
3967
|
+
console.log(`Next: ${nextBuildCommand(manifestPath)}`);
|
|
3968
|
+
});
|
|
3984
3969
|
} catch (err) {
|
|
3985
3970
|
handleValidationError(err, options, command);
|
|
3986
3971
|
}
|
|
3987
3972
|
}
|
|
3988
3973
|
async function sandboxBuildCommand(sourceRepoArg, options = {}, command) {
|
|
3989
|
-
const
|
|
3990
|
-
const config = requireConfig(runtime);
|
|
3974
|
+
const { config } = resolveBusinessContext(command, options);
|
|
3991
3975
|
const manifestPath = options.manifest ?? DEFAULT_MANIFEST_PATH;
|
|
3992
3976
|
assertManifestExists(manifestPath);
|
|
3993
3977
|
if (!options.ref) assertCleanAndPushed();
|
|
3994
3978
|
const sourceRepo = parseRepoArg2(sourceRepoArg, currentRepo);
|
|
3995
3979
|
const targetRepo = options.targetRepo ? parseRepoArg2(options.targetRepo, currentRepo) : null;
|
|
3996
|
-
const businessId = await
|
|
3980
|
+
const businessId = await resolveBusinessId(config, options);
|
|
3997
3981
|
const ref = options.ref ?? currentRef();
|
|
3998
3982
|
const payload = await apiFetch(
|
|
3999
3983
|
config,
|
|
4000
|
-
`/api/businesses/${
|
|
3984
|
+
`/api/businesses/${encodeURIComponent(businessId)}/repos/${encodeURIComponent(sourceRepo.owner)}/${encodeURIComponent(
|
|
4001
3985
|
sourceRepo.repo
|
|
4002
3986
|
)}/sandbox-layer/build-requests`,
|
|
4003
3987
|
{
|
|
@@ -4009,8 +3993,7 @@ async function sandboxBuildCommand(sourceRepoArg, options = {}, command) {
|
|
|
4009
3993
|
})
|
|
4010
3994
|
}
|
|
4011
3995
|
);
|
|
4012
|
-
|
|
4013
|
-
else printBuildRequest(payload.buildRequest);
|
|
3996
|
+
emit(command, options, payload, (buildPayload) => printBuildRequest(buildPayload.buildRequest));
|
|
4014
3997
|
if (!options.wait && !options.follow) return;
|
|
4015
3998
|
const json = isJson(command, options);
|
|
4016
3999
|
const finalBuild = await waitForBuild(config, businessId, payload.buildRequest.id, {
|
|
@@ -4025,26 +4008,20 @@ async function sandboxBuildCommand(sourceRepoArg, options = {}, command) {
|
|
|
4025
4008
|
}
|
|
4026
4009
|
}
|
|
4027
4010
|
async function sandboxStatusCommand(repoArg, options = {}, command) {
|
|
4028
|
-
const
|
|
4029
|
-
const
|
|
4030
|
-
const businessId = await resolveBusinessId2(config, options);
|
|
4011
|
+
const { config } = resolveBusinessContext(command, options);
|
|
4012
|
+
const businessId = await resolveBusinessId(config, options);
|
|
4031
4013
|
const repo = parseRepoArg2(repoArg, currentRepo);
|
|
4032
4014
|
const payload = await apiFetch(
|
|
4033
4015
|
config,
|
|
4034
|
-
`/api/businesses/${
|
|
4016
|
+
`/api/businesses/${encodeURIComponent(businessId)}/repos/${encodeURIComponent(repo.owner)}/${encodeURIComponent(
|
|
4035
4017
|
repo.repo
|
|
4036
4018
|
)}/sandbox-layer/resolution`
|
|
4037
4019
|
);
|
|
4038
|
-
|
|
4039
|
-
writeJson(payload);
|
|
4040
|
-
return;
|
|
4041
|
-
}
|
|
4042
|
-
printSandboxStatus(payload);
|
|
4020
|
+
emit(command, options, payload, printSandboxStatus);
|
|
4043
4021
|
}
|
|
4044
4022
|
async function sandboxHistoryCommand(sourceRepoArg, options = {}, command) {
|
|
4045
|
-
const
|
|
4046
|
-
const
|
|
4047
|
-
const businessId = await resolveBusinessId2(config, options);
|
|
4023
|
+
const { config } = resolveBusinessContext(command, options);
|
|
4024
|
+
const businessId = await resolveBusinessId(config, options);
|
|
4048
4025
|
const sourceRepo = parseRepoArg2(sourceRepoArg, currentRepo);
|
|
4049
4026
|
const params = new URLSearchParams({ sourceRepo: repoPath(sourceRepo) });
|
|
4050
4027
|
if (options.targetRepo) params.set("targetRepo", repoPath(parseRepoArg2(options.targetRepo, currentRepo)));
|
|
@@ -4058,24 +4035,19 @@ async function sandboxHistoryCommand(sourceRepoArg, options = {}, command) {
|
|
|
4058
4035
|
}
|
|
4059
4036
|
const payload = await apiFetch(
|
|
4060
4037
|
config,
|
|
4061
|
-
`/api/businesses/${
|
|
4038
|
+
`/api/businesses/${encodeURIComponent(businessId)}/sandbox-layer/build-requests?${params.toString()}`
|
|
4062
4039
|
);
|
|
4063
|
-
|
|
4064
|
-
writeJson(payload);
|
|
4065
|
-
return;
|
|
4066
|
-
}
|
|
4067
|
-
printBuildHistory(payload.builds);
|
|
4040
|
+
emit(command, options, payload, (historyPayload) => printBuildHistory(historyPayload.builds));
|
|
4068
4041
|
}
|
|
4069
4042
|
async function sandboxRebuildStaleCommand(options = {}, command) {
|
|
4070
|
-
const
|
|
4071
|
-
const config = requireConfig(runtime);
|
|
4043
|
+
const { config } = resolveBusinessContext(command, options);
|
|
4072
4044
|
if (!options.dryRun && !options.yes) {
|
|
4073
4045
|
throw new CliError("user", "Use --dry-run to preview or --yes to start a rebuild campaign.");
|
|
4074
4046
|
}
|
|
4075
4047
|
if (options.all && options.business) {
|
|
4076
4048
|
throw new CliError("user", "Use either --all or --business, not both.");
|
|
4077
4049
|
}
|
|
4078
|
-
const businessId = options.all ? null : await
|
|
4050
|
+
const businessId = options.all ? null : await resolveBusinessId(config, options);
|
|
4079
4051
|
let payload = await apiFetch(config, "/api/admin/sandbox-layer/rebuild-campaigns", {
|
|
4080
4052
|
method: "POST",
|
|
4081
4053
|
body: JSON.stringify({
|
|
@@ -4093,20 +4065,16 @@ async function sandboxRebuildStaleCommand(options = {}, command) {
|
|
|
4093
4065
|
if (options.follow && !options.dryRun) {
|
|
4094
4066
|
payload = await followRebuildCampaign(config, payload.campaign.id);
|
|
4095
4067
|
}
|
|
4096
|
-
|
|
4097
|
-
writeJson(payload);
|
|
4098
|
-
return;
|
|
4099
|
-
}
|
|
4100
|
-
printRebuildCampaign(payload);
|
|
4068
|
+
emit(command, options, payload, printRebuildCampaign);
|
|
4101
4069
|
}
|
|
4102
4070
|
async function followRebuildCampaign(config, campaignId) {
|
|
4103
4071
|
for (; ; ) {
|
|
4104
4072
|
const payload = await apiFetch(
|
|
4105
4073
|
config,
|
|
4106
|
-
`/api/admin/sandbox-layer/rebuild-campaigns/${
|
|
4074
|
+
`/api/admin/sandbox-layer/rebuild-campaigns/${encodeURIComponent(campaignId)}`
|
|
4107
4075
|
);
|
|
4108
4076
|
if (isCampaignTerminal(payload.campaign.status)) return payload;
|
|
4109
|
-
await
|
|
4077
|
+
await sleep(DEFAULT_POLL_INTERVAL_MS);
|
|
4110
4078
|
}
|
|
4111
4079
|
}
|
|
4112
4080
|
function isCampaignTerminal(status) {
|
|
@@ -4130,9 +4098,8 @@ function printRebuildCampaign(payload) {
|
|
|
4130
4098
|
}
|
|
4131
4099
|
}
|
|
4132
4100
|
async function sandboxLogsCommand(buildId, options = {}, command) {
|
|
4133
|
-
const
|
|
4134
|
-
const
|
|
4135
|
-
const businessId = await resolveBusinessId2(config, options);
|
|
4101
|
+
const { config } = resolveBusinessContext(command, options);
|
|
4102
|
+
const businessId = await resolveBusinessId(config, options);
|
|
4136
4103
|
let afterSequence = options.afterSequence == null ? void 0 : Number(options.afterSequence);
|
|
4137
4104
|
if (afterSequence != null && (!Number.isInteger(afterSequence) || afterSequence < 0)) {
|
|
4138
4105
|
throw new CliError("user", "--after-sequence must be a non-negative integer.");
|
|
@@ -4150,88 +4117,72 @@ async function sandboxLogsCommand(buildId, options = {}, command) {
|
|
|
4150
4117
|
else printLogs(payload.logs);
|
|
4151
4118
|
if (!options.follow) return;
|
|
4152
4119
|
if (payload.logs.length > 0) afterSequence = payload.logs[payload.logs.length - 1].sequence;
|
|
4153
|
-
await
|
|
4120
|
+
await sleep(parsePollInterval2(options.pollInterval));
|
|
4154
4121
|
}
|
|
4155
4122
|
}
|
|
4156
4123
|
async function sandboxAssignDefaultCommand(sourceRepoArg, options = {}, command) {
|
|
4157
|
-
const
|
|
4158
|
-
const
|
|
4159
|
-
const businessId = await resolveBusinessId2(config, options);
|
|
4124
|
+
const { config } = resolveBusinessContext(command, options);
|
|
4125
|
+
const businessId = await resolveBusinessId(config, options);
|
|
4160
4126
|
const sourceRepo = parseRepoArg2(sourceRepoArg, currentRepo);
|
|
4161
4127
|
const manifestPath = options.manifest ?? DEFAULT_MANIFEST_PATH;
|
|
4162
4128
|
const payload = await apiFetch(
|
|
4163
4129
|
config,
|
|
4164
|
-
`/api/businesses/${
|
|
4130
|
+
`/api/businesses/${encodeURIComponent(businessId)}/sandbox-layer/default-source`,
|
|
4165
4131
|
{ method: "PUT", body: JSON.stringify(sourceBody(sourceRepo, manifestPath)) }
|
|
4166
4132
|
);
|
|
4167
|
-
|
|
4168
|
-
|
|
4169
|
-
|
|
4170
|
-
|
|
4171
|
-
|
|
4172
|
-
|
|
4173
|
-
`Build missing target coverage with: arcanist sandbox build ${repoPath(sourceRepo)} --business ${businessId}`
|
|
4174
|
-
);
|
|
4133
|
+
emit(command, options, payload, () => {
|
|
4134
|
+
console.log(`Set default sandbox layer source to ${repoPath(sourceRepo)}.`);
|
|
4135
|
+
console.log(
|
|
4136
|
+
`Build missing target coverage with: arcanist sandbox build ${repoPath(sourceRepo)} --business ${businessId}`
|
|
4137
|
+
);
|
|
4138
|
+
});
|
|
4175
4139
|
}
|
|
4176
4140
|
async function sandboxAssignRepoCommand(targetRepoArg, sourceRepoArg, options = {}, command) {
|
|
4177
|
-
const
|
|
4178
|
-
const
|
|
4179
|
-
const businessId = await resolveBusinessId2(config, options);
|
|
4141
|
+
const { config } = resolveBusinessContext(command, options);
|
|
4142
|
+
const businessId = await resolveBusinessId(config, options);
|
|
4180
4143
|
const targetRepo = parseRepoArg2(targetRepoArg, currentRepo);
|
|
4181
4144
|
const sourceRepo = parseRepoArg2(sourceRepoArg, currentRepo);
|
|
4182
4145
|
const manifestPath = options.manifest ?? DEFAULT_MANIFEST_PATH;
|
|
4183
4146
|
const payload = await apiFetch(
|
|
4184
4147
|
config,
|
|
4185
|
-
`/api/businesses/${
|
|
4148
|
+
`/api/businesses/${encodeURIComponent(businessId)}/repos/${encodeURIComponent(targetRepo.owner)}/${encodeURIComponent(
|
|
4186
4149
|
targetRepo.repo
|
|
4187
4150
|
)}/sandbox-layer/assignment`,
|
|
4188
4151
|
{ method: "PUT", body: JSON.stringify(sourceBody(sourceRepo, manifestPath)) }
|
|
4189
4152
|
);
|
|
4190
|
-
|
|
4191
|
-
|
|
4192
|
-
|
|
4193
|
-
|
|
4194
|
-
|
|
4195
|
-
|
|
4196
|
-
|
|
4197
|
-
|
|
4198
|
-
)} --business ${businessId}`
|
|
4199
|
-
);
|
|
4153
|
+
emit(command, options, payload, () => {
|
|
4154
|
+
console.log(`Assigned ${repoPath(sourceRepo)} as sandbox layer source for ${repoPath(targetRepo)}.`);
|
|
4155
|
+
console.log(
|
|
4156
|
+
`Build target coverage with: arcanist sandbox build ${repoPath(sourceRepo)} --target-repo ${repoPath(
|
|
4157
|
+
targetRepo
|
|
4158
|
+
)} --business ${businessId}`
|
|
4159
|
+
);
|
|
4160
|
+
});
|
|
4200
4161
|
}
|
|
4201
4162
|
async function sandboxUnassignDefaultCommand(options = {}, command) {
|
|
4202
|
-
const
|
|
4203
|
-
const
|
|
4204
|
-
const businessId = await resolveBusinessId2(config, options);
|
|
4163
|
+
const { config } = resolveBusinessContext(command, options);
|
|
4164
|
+
const businessId = await resolveBusinessId(config, options);
|
|
4205
4165
|
if (!options.yes) await confirmOrThrow("Clear the business default sandbox layer source?");
|
|
4206
4166
|
const payload = await apiFetch(
|
|
4207
4167
|
config,
|
|
4208
|
-
`/api/businesses/${
|
|
4168
|
+
`/api/businesses/${encodeURIComponent(businessId)}/sandbox-layer/default-source`,
|
|
4209
4169
|
{ method: "DELETE" }
|
|
4210
4170
|
);
|
|
4211
|
-
|
|
4212
|
-
writeJson(payload);
|
|
4213
|
-
return;
|
|
4214
|
-
}
|
|
4215
|
-
console.log("Cleared default sandbox layer source.");
|
|
4171
|
+
emit(command, options, payload, () => console.log("Cleared default sandbox layer source."));
|
|
4216
4172
|
}
|
|
4217
4173
|
async function sandboxUnassignRepoCommand(targetRepoArg, options = {}, command) {
|
|
4218
|
-
const
|
|
4219
|
-
const
|
|
4220
|
-
const businessId = await resolveBusinessId2(config, options);
|
|
4174
|
+
const { config } = resolveBusinessContext(command, options);
|
|
4175
|
+
const businessId = await resolveBusinessId(config, options);
|
|
4221
4176
|
const targetRepo = parseRepoArg2(targetRepoArg, currentRepo);
|
|
4222
4177
|
if (!options.yes) await confirmOrThrow(`Clear sandbox layer assignment for ${repoPath(targetRepo)}?`);
|
|
4223
4178
|
const payload = await apiFetch(
|
|
4224
4179
|
config,
|
|
4225
|
-
`/api/businesses/${
|
|
4180
|
+
`/api/businesses/${encodeURIComponent(businessId)}/repos/${encodeURIComponent(targetRepo.owner)}/${encodeURIComponent(
|
|
4226
4181
|
targetRepo.repo
|
|
4227
4182
|
)}/sandbox-layer/assignment`,
|
|
4228
4183
|
{ method: "DELETE" }
|
|
4229
4184
|
);
|
|
4230
|
-
|
|
4231
|
-
writeJson(payload);
|
|
4232
|
-
return;
|
|
4233
|
-
}
|
|
4234
|
-
console.log(`Cleared sandbox layer assignment for ${repoPath(targetRepo)}.`);
|
|
4185
|
+
emit(command, options, payload, () => console.log(`Cleared sandbox layer assignment for ${repoPath(targetRepo)}.`));
|
|
4235
4186
|
}
|
|
4236
4187
|
|
|
4237
4188
|
// src/commands/sessions.ts
|
|
@@ -4369,8 +4320,7 @@ async function usageCommand(sessionId, options, command) {
|
|
|
4369
4320
|
|
|
4370
4321
|
// src/commands/stop.ts
|
|
4371
4322
|
async function stopCommand(sessionId, options = {}, command) {
|
|
4372
|
-
const
|
|
4373
|
-
const config = requireConfig(runtime);
|
|
4323
|
+
const { config } = resolveBusinessContext(command, options);
|
|
4374
4324
|
let status;
|
|
4375
4325
|
try {
|
|
4376
4326
|
const response = await apiFetch(config, `/api/sessions/${sessionId}/stop`, {
|
|
@@ -4382,17 +4332,15 @@ async function stopCommand(sessionId, options = {}, command) {
|
|
|
4382
4332
|
if (!parsed) throw err;
|
|
4383
4333
|
status = parsed.reason;
|
|
4384
4334
|
}
|
|
4385
|
-
|
|
4386
|
-
|
|
4387
|
-
|
|
4388
|
-
|
|
4389
|
-
|
|
4390
|
-
|
|
4391
|
-
|
|
4392
|
-
|
|
4393
|
-
}
|
|
4394
|
-
console.log(`Session ${sessionId} cannot be stopped from phase=${status}.`);
|
|
4395
|
-
}
|
|
4335
|
+
emit(command, options, { sessionId, status }, (payload) => {
|
|
4336
|
+
if (payload.status === "already_stopped") {
|
|
4337
|
+
console.log(`Session ${payload.sessionId} is already stopped.`);
|
|
4338
|
+
} else if (payload.status === "stopping" || payload.status === "stopped") {
|
|
4339
|
+
console.log(`Stop requested for session ${payload.sessionId}.`);
|
|
4340
|
+
} else {
|
|
4341
|
+
console.log(`Session ${payload.sessionId} cannot be stopped from phase=${payload.status}.`);
|
|
4342
|
+
}
|
|
4343
|
+
});
|
|
4396
4344
|
}
|
|
4397
4345
|
function parseStopBlocked(err) {
|
|
4398
4346
|
if (!(err instanceof ApiError) || err.status !== 409) return null;
|
|
@@ -4428,26 +4376,22 @@ function readValue(options) {
|
|
|
4428
4376
|
return raw.replace(/\r?\n$/, "");
|
|
4429
4377
|
}
|
|
4430
4378
|
async function listTestCredentialsCommand(repo, options, command) {
|
|
4431
|
-
const
|
|
4432
|
-
const config = requireConfig(runtime);
|
|
4379
|
+
const { config } = resolveBusinessContext(command, options);
|
|
4433
4380
|
const repoArg = parseRepoArg3(repo);
|
|
4434
4381
|
const payload = await apiFetch(config, basePath(options.business, repoArg));
|
|
4435
|
-
|
|
4436
|
-
|
|
4437
|
-
|
|
4438
|
-
|
|
4439
|
-
|
|
4440
|
-
|
|
4441
|
-
|
|
4442
|
-
|
|
4443
|
-
|
|
4444
|
-
|
|
4445
|
-
console.log(`${cred.name} ${ts} ${cred.rotatedByUserId ?? "-"}`);
|
|
4446
|
-
}
|
|
4382
|
+
emit(command, options, payload, (listPayload) => {
|
|
4383
|
+
if (listPayload.credentials.length === 0) {
|
|
4384
|
+
console.log(`No test credentials configured for ${repoArg.owner}/${repoArg.name}.`);
|
|
4385
|
+
return;
|
|
4386
|
+
}
|
|
4387
|
+
for (const cred of listPayload.credentials) {
|
|
4388
|
+
const ts = new Date(cred.updatedAt).toISOString();
|
|
4389
|
+
console.log(`${cred.name} ${ts} ${cred.rotatedByUserId ?? "-"}`);
|
|
4390
|
+
}
|
|
4391
|
+
});
|
|
4447
4392
|
}
|
|
4448
4393
|
async function setTestCredentialCommand(repo, name, options, command) {
|
|
4449
|
-
const
|
|
4450
|
-
const config = requireConfig(runtime);
|
|
4394
|
+
const { config } = resolveBusinessContext(command, options);
|
|
4451
4395
|
const repoArg = parseRepoArg3(repo);
|
|
4452
4396
|
const value = readValue(options);
|
|
4453
4397
|
const payload = await apiFetch(
|
|
@@ -4455,11 +4399,12 @@ async function setTestCredentialCommand(repo, name, options, command) {
|
|
|
4455
4399
|
`${basePath(options.business, repoArg)}/${encodeURIComponent(name)}`,
|
|
4456
4400
|
{ method: "PUT", body: JSON.stringify({ value }) }
|
|
4457
4401
|
);
|
|
4458
|
-
|
|
4459
|
-
|
|
4460
|
-
|
|
4461
|
-
|
|
4462
|
-
|
|
4402
|
+
emit(
|
|
4403
|
+
command,
|
|
4404
|
+
options,
|
|
4405
|
+
payload,
|
|
4406
|
+
() => console.log(`Set test credential '${name}' for ${repoArg.owner}/${repoArg.name}.`)
|
|
4407
|
+
);
|
|
4463
4408
|
}
|
|
4464
4409
|
async function deleteTestCredentialCommand(repo, name, options, command) {
|
|
4465
4410
|
if (isJson(command, options) && options.yes !== true) {
|
|
@@ -4469,25 +4414,24 @@ async function deleteTestCredentialCommand(repo, name, options, command) {
|
|
|
4469
4414
|
const repoArg2 = parseRepoArg3(repo);
|
|
4470
4415
|
await confirmOrThrow(`Delete test credential '${name}' for ${repoArg2.owner}/${repoArg2.name}?`);
|
|
4471
4416
|
}
|
|
4472
|
-
const
|
|
4473
|
-
const config = requireConfig(runtime);
|
|
4417
|
+
const { config } = resolveBusinessContext(command, options);
|
|
4474
4418
|
const repoArg = parseRepoArg3(repo);
|
|
4475
4419
|
const payload = await apiFetch(
|
|
4476
4420
|
config,
|
|
4477
4421
|
`${basePath(options.business, repoArg)}/${encodeURIComponent(name)}`,
|
|
4478
4422
|
{ method: "DELETE" }
|
|
4479
4423
|
);
|
|
4480
|
-
|
|
4481
|
-
|
|
4482
|
-
|
|
4483
|
-
|
|
4484
|
-
|
|
4424
|
+
emit(
|
|
4425
|
+
command,
|
|
4426
|
+
options,
|
|
4427
|
+
payload,
|
|
4428
|
+
() => console.log(`Deleted test credential '${name}' for ${repoArg.owner}/${repoArg.name}.`)
|
|
4429
|
+
);
|
|
4485
4430
|
}
|
|
4486
4431
|
|
|
4487
4432
|
// src/commands/tokens.ts
|
|
4488
4433
|
async function listTokensCommand(options, command) {
|
|
4489
|
-
const
|
|
4490
|
-
const config = requireConfig(runtime);
|
|
4434
|
+
const { config } = resolveBusinessContext(command, options);
|
|
4491
4435
|
const query = new URLSearchParams();
|
|
4492
4436
|
if (options.limit) query.set("limit", options.limit);
|
|
4493
4437
|
if (options.cursor) query.set("cursor", options.cursor);
|
|
@@ -4495,24 +4439,21 @@ async function listTokensCommand(options, command) {
|
|
|
4495
4439
|
config,
|
|
4496
4440
|
`/api/cli-tokens${query.size ? `?${query.toString()}` : ""}`
|
|
4497
4441
|
);
|
|
4498
|
-
|
|
4499
|
-
|
|
4500
|
-
|
|
4501
|
-
|
|
4502
|
-
|
|
4503
|
-
|
|
4504
|
-
|
|
4505
|
-
|
|
4506
|
-
|
|
4507
|
-
|
|
4508
|
-
|
|
4509
|
-
|
|
4510
|
-
}
|
|
4511
|
-
if (payload.nextCursor) console.log(`Next cursor: ${payload.nextCursor}`);
|
|
4442
|
+
emit(command, options, payload, (listPayload) => {
|
|
4443
|
+
if (listPayload.data.length === 0) {
|
|
4444
|
+
console.log("No CLI tokens found.");
|
|
4445
|
+
return;
|
|
4446
|
+
}
|
|
4447
|
+
for (const token of listPayload.data) {
|
|
4448
|
+
console.log(
|
|
4449
|
+
`${String(token.id)} ${String(token.scope)} ${String(token.tokenPrefix)} ${String(token.revokedAt ? "revoked" : "active")}`
|
|
4450
|
+
);
|
|
4451
|
+
}
|
|
4452
|
+
if (listPayload.nextCursor) console.log(`Next cursor: ${listPayload.nextCursor}`);
|
|
4453
|
+
});
|
|
4512
4454
|
}
|
|
4513
4455
|
async function createTokenCommand(options, command) {
|
|
4514
|
-
const
|
|
4515
|
-
const config = requireConfig(runtime);
|
|
4456
|
+
const { config } = resolveBusinessContext(command, options);
|
|
4516
4457
|
const expiresInDays = options.expiresInDays === void 0 ? void 0 : Number(options.expiresInDays);
|
|
4517
4458
|
if (expiresInDays !== void 0 && (!Number.isInteger(expiresInDays) || expiresInDays <= 0)) {
|
|
4518
4459
|
throw new CliError("user", "expiresInDays must be a positive integer.");
|
|
@@ -4524,13 +4465,11 @@ async function createTokenCommand(options, command) {
|
|
|
4524
4465
|
...expiresInDays !== void 0 ? { expiresInDays } : {}
|
|
4525
4466
|
})
|
|
4526
4467
|
});
|
|
4527
|
-
|
|
4528
|
-
|
|
4529
|
-
|
|
4530
|
-
|
|
4531
|
-
|
|
4532
|
-
console.log(`ID: ${String(payload.id)}`);
|
|
4533
|
-
console.log(`Scope: ${String(payload.scope)}`);
|
|
4468
|
+
emit(command, options, payload, (tokenPayload) => {
|
|
4469
|
+
console.log(`Token: ${String(tokenPayload.token)}`);
|
|
4470
|
+
console.log(`ID: ${String(tokenPayload.id)}`);
|
|
4471
|
+
console.log(`Scope: ${String(tokenPayload.scope)}`);
|
|
4472
|
+
});
|
|
4534
4473
|
}
|
|
4535
4474
|
async function revokeTokenCommand(tokenId, options, command) {
|
|
4536
4475
|
if (isJson(command, options) && options.yes !== true) {
|
|
@@ -4539,28 +4478,18 @@ async function revokeTokenCommand(tokenId, options, command) {
|
|
|
4539
4478
|
if (options.yes !== true) {
|
|
4540
4479
|
await confirmOrThrow(`Revoke CLI token ${tokenId}?`);
|
|
4541
4480
|
}
|
|
4542
|
-
const
|
|
4543
|
-
const config = requireConfig(runtime);
|
|
4481
|
+
const { config } = resolveBusinessContext(command, options);
|
|
4544
4482
|
const payload = await apiFetch(config, `/api/cli-tokens/${tokenId}/revoke`, {
|
|
4545
4483
|
method: "POST"
|
|
4546
4484
|
});
|
|
4547
|
-
|
|
4548
|
-
writeJson(payload);
|
|
4549
|
-
return;
|
|
4550
|
-
}
|
|
4551
|
-
console.log(`Revoked token ${tokenId}.`);
|
|
4485
|
+
emit(command, options, payload, () => console.log(`Revoked token ${tokenId}.`));
|
|
4552
4486
|
}
|
|
4553
4487
|
|
|
4554
4488
|
// src/commands/transcript.ts
|
|
4555
4489
|
async function transcriptCommand(sessionId, options, command) {
|
|
4556
|
-
const
|
|
4557
|
-
const config = requireConfig(runtime);
|
|
4490
|
+
const { config } = resolveBusinessContext(command, options);
|
|
4558
4491
|
const exportData = await apiFetch(config, `/api/sessions/${sessionId}/export`);
|
|
4559
|
-
|
|
4560
|
-
writeJson(exportData);
|
|
4561
|
-
return;
|
|
4562
|
-
}
|
|
4563
|
-
console.log(renderSessionTranscript(exportData));
|
|
4492
|
+
emit(command, options, exportData, (payload) => console.log(renderSessionTranscript(payload)));
|
|
4564
4493
|
}
|
|
4565
4494
|
|
|
4566
4495
|
// src/index.ts
|