replicas-cli 0.2.715 → 0.2.716
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.cjs +46 -48
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -27439,7 +27439,7 @@ var headlessFilesystemAgentResultSchema = external_exports.object({
|
|
|
27439
27439
|
});
|
|
27440
27440
|
|
|
27441
27441
|
// ../shared/src/cli-version.ts
|
|
27442
|
-
var CLI_VERSION = "0.2.
|
|
27442
|
+
var CLI_VERSION = "0.2.716";
|
|
27443
27443
|
|
|
27444
27444
|
// ../shared/src/version.ts
|
|
27445
27445
|
function compareVersions(v1, v2) {
|
|
@@ -28105,15 +28105,17 @@ async function readSseStream(body, onEvent, shouldContinue = () => true) {
|
|
|
28105
28105
|
var import_yaml2 = __toESM(require_dist());
|
|
28106
28106
|
|
|
28107
28107
|
// ../shared/src/workspace-identity.ts
|
|
28108
|
-
var WORKSPACE_IDENTITY_AUDIENCE = "replicas:workspace";
|
|
28109
28108
|
var WORKSPACE_TOKEN_TTL_SECONDS = 15 * 60;
|
|
28110
|
-
var
|
|
28109
|
+
var IDENTITY_PROXY_PORT = 17323;
|
|
28110
|
+
var IDENTITY_TOKEN_PATH = "/token";
|
|
28111
28111
|
var WORKSPACE_TOKEN_ENV = {
|
|
28112
28112
|
TOKEN: "REPLICAS_WORKSPACE_TOKEN",
|
|
28113
|
-
|
|
28114
|
-
AUDIENCE: "REPLICAS_WORKSPACE_TOKEN_AUDIENCE",
|
|
28115
|
-
ISSUER: "REPLICAS_WORKSPACE_IDENTITY_ISSUER"
|
|
28113
|
+
AUDIENCE: "REPLICAS_WORKSPACE_TOKEN_AUDIENCE"
|
|
28116
28114
|
};
|
|
28115
|
+
var workspaceAudienceSchema = external_exports.string().min(1).max(255).regex(/^[\x21-\x7e]+$/, "Audience must be a single printable token without spaces");
|
|
28116
|
+
var workspaceTokenRequestSchema = external_exports.object({
|
|
28117
|
+
audience: workspaceAudienceSchema.optional()
|
|
28118
|
+
});
|
|
28117
28119
|
var workspaceTokenClaimsSchema = external_exports.object({
|
|
28118
28120
|
iss: external_exports.string(),
|
|
28119
28121
|
sub: external_exports.string(),
|
|
@@ -28127,29 +28129,24 @@ var workspaceTokenClaimsSchema = external_exports.object({
|
|
|
28127
28129
|
environment_id: external_exports.string().uuid(),
|
|
28128
28130
|
creator_id: external_exports.string().uuid().nullable()
|
|
28129
28131
|
}).passthrough();
|
|
28130
|
-
var
|
|
28132
|
+
var workspaceTokenResponseSchema = external_exports.object({
|
|
28133
|
+
issuer: external_exports.string(),
|
|
28134
|
+
audience: external_exports.string(),
|
|
28135
|
+
token: external_exports.string(),
|
|
28136
|
+
expires_at: external_exports.string()
|
|
28137
|
+
});
|
|
28138
|
+
var legacyWorkspaceTokenBundleSchema = external_exports.object({
|
|
28131
28139
|
version: external_exports.literal(1),
|
|
28132
28140
|
issuer: external_exports.string(),
|
|
28133
28141
|
default_audience: external_exports.string(),
|
|
28134
|
-
tokens: external_exports.record(
|
|
28135
|
-
external_exports.string(),
|
|
28136
|
-
external_exports.strictObject({ token: external_exports.string(), expires_at: external_exports.string() })
|
|
28137
|
-
)
|
|
28138
|
-
});
|
|
28139
|
-
var workloadAudienceInput = external_exports.strictObject({
|
|
28140
|
-
name: external_exports.string().trim().min(1).max(64),
|
|
28141
|
-
audience: external_exports.string().min(1).max(255).regex(/^[\x21-\x7e]+$/, "Audience must be a single printable token without spaces").refine((value) => value !== WORKSPACE_IDENTITY_AUDIENCE, "Reserved audience"),
|
|
28142
|
-
enabled: external_exports.boolean(),
|
|
28143
|
-
is_default: external_exports.boolean()
|
|
28142
|
+
tokens: external_exports.record(external_exports.string(), external_exports.object({ token: external_exports.string(), expires_at: external_exports.string() }))
|
|
28144
28143
|
});
|
|
28145
28144
|
var mcpWorkloadAuthSchema = external_exports.strictObject({
|
|
28146
28145
|
type: external_exports.literal("workspace_identity"),
|
|
28147
|
-
audience:
|
|
28146
|
+
audience: workspaceAudienceSchema
|
|
28148
28147
|
});
|
|
28149
|
-
function
|
|
28150
|
-
|
|
28151
|
-
if (!entry || Date.parse(entry.expires_at) <= now) return null;
|
|
28152
|
-
return entry.token;
|
|
28148
|
+
function identityTokenUrl() {
|
|
28149
|
+
return `http://127.0.0.1:${IDENTITY_PROXY_PORT}${IDENTITY_TOKEN_PATH}`;
|
|
28153
28150
|
}
|
|
28154
28151
|
|
|
28155
28152
|
// src/lib/monolith-url.ts
|
|
@@ -28653,26 +28650,27 @@ var import_node_child_process = require("child_process");
|
|
|
28653
28650
|
var import_node_os = require("os");
|
|
28654
28651
|
var import_node_path = require("path");
|
|
28655
28652
|
var import_chalk5 = __toESM(require("chalk"));
|
|
28656
|
-
function
|
|
28657
|
-
|
|
28658
|
-
let bundle;
|
|
28653
|
+
async function fetchToken(audience) {
|
|
28654
|
+
let response;
|
|
28659
28655
|
try {
|
|
28660
|
-
|
|
28661
|
-
|
|
28662
|
-
|
|
28663
|
-
|
|
28664
|
-
const selected = audience ?? bundle.default_audience;
|
|
28665
|
-
const token = currentWorkspaceToken(bundle, selected);
|
|
28666
|
-
const expiresAt = Date.parse(bundle.tokens[selected]?.expires_at);
|
|
28667
|
-
if (!token || !Number.isFinite(expiresAt)) {
|
|
28668
|
-
return createErrorResult({
|
|
28669
|
-
message: bundle.tokens[selected] ? `The workspace token for ${selected} has expired or has an invalid expiry and has not been renewed yet.` : `No workspace token is issued for audience ${selected}. Registered: ${Object.keys(bundle.tokens).join(", ")}`
|
|
28656
|
+
response = await fetch(identityTokenUrl(), {
|
|
28657
|
+
method: "POST",
|
|
28658
|
+
headers: { "content-type": "application/json" },
|
|
28659
|
+
body: JSON.stringify(audience ? { audience } : {})
|
|
28670
28660
|
});
|
|
28661
|
+
} catch {
|
|
28662
|
+
return createErrorResult({ message: "Workspace identity is only available inside a running Replicas workspace." });
|
|
28663
|
+
}
|
|
28664
|
+
const body = await response.json().catch(() => null);
|
|
28665
|
+
const parsed = workspaceTokenResponseSchema.safeParse(body);
|
|
28666
|
+
if (!response.ok || !parsed.success) {
|
|
28667
|
+
const detail = isRecord(body) && typeof body.error === "string" ? body.error : `HTTP ${response.status}`;
|
|
28668
|
+
return createErrorResult({ message: `Could not obtain a workspace token: ${detail}` });
|
|
28671
28669
|
}
|
|
28672
|
-
return createSuccessResult(
|
|
28670
|
+
return createSuccessResult(parsed.data);
|
|
28673
28671
|
}
|
|
28674
|
-
function identityTokenCommand(options) {
|
|
28675
|
-
const result =
|
|
28672
|
+
async function identityTokenCommand(options) {
|
|
28673
|
+
const result = await fetchToken(options.audience);
|
|
28676
28674
|
if (!result.ok) {
|
|
28677
28675
|
if (options.format === "gcp") {
|
|
28678
28676
|
process.stdout.write(`${JSON.stringify({ version: 1, success: false, code: "TOKEN_UNAVAILABLE", message: result.error.message })}
|
|
@@ -28683,23 +28681,23 @@ function identityTokenCommand(options) {
|
|
|
28683
28681
|
process.exitCode = 1;
|
|
28684
28682
|
return;
|
|
28685
28683
|
}
|
|
28686
|
-
const { token,
|
|
28684
|
+
const { token, expires_at } = result.data;
|
|
28687
28685
|
const output = options.format === "gcp" ? JSON.stringify({
|
|
28688
28686
|
version: 1,
|
|
28689
28687
|
success: true,
|
|
28690
28688
|
token_type: "urn:ietf:params:oauth:token-type:jwt",
|
|
28691
28689
|
id_token: token,
|
|
28692
|
-
expiration_time: Math.floor(
|
|
28690
|
+
expiration_time: Math.floor(Date.parse(expires_at) / 1e3)
|
|
28693
28691
|
}) : token;
|
|
28694
28692
|
process.stdout.write(`${output}
|
|
28695
28693
|
`);
|
|
28696
28694
|
}
|
|
28697
|
-
function identityExecCommand(command, options) {
|
|
28695
|
+
async function identityExecCommand(command, options) {
|
|
28698
28696
|
if (command.length === 0) {
|
|
28699
28697
|
console.error(import_chalk5.default.red("Provide a command to run: replicas identity exec -- <command>"));
|
|
28700
28698
|
process.exit(1);
|
|
28701
28699
|
}
|
|
28702
|
-
const tokenResult =
|
|
28700
|
+
const tokenResult = await fetchToken(options.audience);
|
|
28703
28701
|
if (!tokenResult.ok) {
|
|
28704
28702
|
console.error(import_chalk5.default.red(tokenResult.error.message));
|
|
28705
28703
|
process.exitCode = 1;
|
|
@@ -28712,8 +28710,8 @@ function identityExecCommand(command, options) {
|
|
|
28712
28710
|
});
|
|
28713
28711
|
process.exit(result.status ?? 1);
|
|
28714
28712
|
}
|
|
28715
|
-
function identityAwsCredentialsCommand(options) {
|
|
28716
|
-
const result =
|
|
28713
|
+
async function identityAwsCredentialsCommand(options) {
|
|
28714
|
+
const result = await fetchToken(options.audience);
|
|
28717
28715
|
if (!result.ok) {
|
|
28718
28716
|
console.error(import_chalk5.default.red(result.error.message));
|
|
28719
28717
|
process.exitCode = 1;
|
|
@@ -33109,10 +33107,10 @@ if (isAgentMode()) {
|
|
|
33109
33107
|
});
|
|
33110
33108
|
}
|
|
33111
33109
|
if (isAgentMode()) {
|
|
33112
|
-
const identity = program.command("identity").description("
|
|
33113
|
-
identity.command("token").description("Print
|
|
33114
|
-
identity.command("aws-credentials").description("Exchange the current token for temporary AWS credentials (for AWS credential_process)").requiredOption("--role-arn <arn>", "IAM role that trusts the Replicas issuer").option("-a, --audience <audience>", "
|
|
33115
|
-
identity.command("exec [command...]").description("Run a command with REPLICAS_WORKSPACE_TOKEN set to a fresh token: replicas identity exec -- curl ...").option("-a, --audience <audience>", "
|
|
33110
|
+
const identity = program.command("identity").description("Obtain short-lived workspace identity tokens (OIDC) for the services this workspace calls");
|
|
33111
|
+
identity.command("token").description("Print a workspace token for an audience (defaults to replicas:workspace)").option("-a, --audience <audience>", "Audience (`aud`) the receiving service verifies, for example its URL").addOption(new import_commander.Option("--format <format>", "Output a raw token or Google executable credentials").choices(["text", "gcp"]).default("text")).action(identityTokenCommand);
|
|
33112
|
+
identity.command("aws-credentials").description("Exchange the current token for temporary AWS credentials (for AWS credential_process)").requiredOption("--role-arn <arn>", "IAM role that trusts the Replicas issuer").option("-a, --audience <audience>", "Audience configured on the IAM OIDC provider", "sts.amazonaws.com").option("--region <region>", "AWS region for the STS exchange").option("--session-name <name>", "AWS role session name", "replicas").action(identityAwsCredentialsCommand);
|
|
33113
|
+
identity.command("exec [command...]").description("Run a command with REPLICAS_WORKSPACE_TOKEN set to a fresh token: replicas identity exec -- curl ...").option("-a, --audience <audience>", "Audience (`aud`) the receiving service verifies").action((command, options) => identityExecCommand(command, options));
|
|
33116
33114
|
const service = program.command("service").description("Run long-lived services (dev servers, daemons) detached from the agent session so they survive workspace sleep/wake");
|
|
33117
33115
|
service.command("start <name> [command...]").description('Start (or restart) a named service as a detached daemon. Quote shell operators: replicas service start web "cd app && bun dev"').option("-d, --cwd <dir>", "Working directory for the service (defaults to the current directory)").action(async (name, commandParts, options) => {
|
|
33118
33116
|
try {
|