replicas-cli 0.2.715 → 0.2.717
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 +48 -49
- 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.717";
|
|
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(),
|
|
@@ -28125,31 +28127,27 @@ var workspaceTokenClaimsSchema = external_exports.object({
|
|
|
28125
28127
|
organization_id: external_exports.string().uuid(),
|
|
28126
28128
|
workspace_id: external_exports.string().uuid(),
|
|
28127
28129
|
environment_id: external_exports.string().uuid(),
|
|
28128
|
-
creator_id: external_exports.string().uuid().nullable()
|
|
28130
|
+
creator_id: external_exports.string().uuid().nullable(),
|
|
28131
|
+
creator_email: external_exports.string().nullable().default(null)
|
|
28129
28132
|
}).passthrough();
|
|
28130
|
-
var
|
|
28133
|
+
var workspaceTokenResponseSchema = external_exports.object({
|
|
28134
|
+
issuer: external_exports.string(),
|
|
28135
|
+
audience: external_exports.string(),
|
|
28136
|
+
token: external_exports.string(),
|
|
28137
|
+
expires_at: external_exports.string()
|
|
28138
|
+
});
|
|
28139
|
+
var legacyWorkspaceTokenBundleSchema = external_exports.object({
|
|
28131
28140
|
version: external_exports.literal(1),
|
|
28132
28141
|
issuer: external_exports.string(),
|
|
28133
28142
|
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()
|
|
28143
|
+
tokens: external_exports.record(external_exports.string(), external_exports.object({ token: external_exports.string(), expires_at: external_exports.string() }))
|
|
28144
28144
|
});
|
|
28145
28145
|
var mcpWorkloadAuthSchema = external_exports.strictObject({
|
|
28146
28146
|
type: external_exports.literal("workspace_identity"),
|
|
28147
|
-
audience:
|
|
28147
|
+
audience: workspaceAudienceSchema
|
|
28148
28148
|
});
|
|
28149
|
-
function
|
|
28150
|
-
|
|
28151
|
-
if (!entry || Date.parse(entry.expires_at) <= now) return null;
|
|
28152
|
-
return entry.token;
|
|
28149
|
+
function identityTokenUrl() {
|
|
28150
|
+
return `http://127.0.0.1:${IDENTITY_PROXY_PORT}${IDENTITY_TOKEN_PATH}`;
|
|
28153
28151
|
}
|
|
28154
28152
|
|
|
28155
28153
|
// src/lib/monolith-url.ts
|
|
@@ -28653,26 +28651,27 @@ var import_node_child_process = require("child_process");
|
|
|
28653
28651
|
var import_node_os = require("os");
|
|
28654
28652
|
var import_node_path = require("path");
|
|
28655
28653
|
var import_chalk5 = __toESM(require("chalk"));
|
|
28656
|
-
function
|
|
28657
|
-
|
|
28658
|
-
let bundle;
|
|
28654
|
+
async function fetchToken(audience) {
|
|
28655
|
+
let response;
|
|
28659
28656
|
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(", ")}`
|
|
28657
|
+
response = await fetch(identityTokenUrl(), {
|
|
28658
|
+
method: "POST",
|
|
28659
|
+
headers: { "content-type": "application/json" },
|
|
28660
|
+
body: JSON.stringify(audience ? { audience } : {})
|
|
28670
28661
|
});
|
|
28662
|
+
} catch {
|
|
28663
|
+
return createErrorResult({ message: "Workspace identity is only available inside a running Replicas workspace." });
|
|
28664
|
+
}
|
|
28665
|
+
const body = await response.json().catch(() => null);
|
|
28666
|
+
const parsed = workspaceTokenResponseSchema.safeParse(body);
|
|
28667
|
+
if (!response.ok || !parsed.success) {
|
|
28668
|
+
const detail = isRecord(body) && typeof body.error === "string" ? body.error : `HTTP ${response.status}`;
|
|
28669
|
+
return createErrorResult({ message: `Could not obtain a workspace token: ${detail}` });
|
|
28671
28670
|
}
|
|
28672
|
-
return createSuccessResult(
|
|
28671
|
+
return createSuccessResult(parsed.data);
|
|
28673
28672
|
}
|
|
28674
|
-
function identityTokenCommand(options) {
|
|
28675
|
-
const result =
|
|
28673
|
+
async function identityTokenCommand(options) {
|
|
28674
|
+
const result = await fetchToken(options.audience);
|
|
28676
28675
|
if (!result.ok) {
|
|
28677
28676
|
if (options.format === "gcp") {
|
|
28678
28677
|
process.stdout.write(`${JSON.stringify({ version: 1, success: false, code: "TOKEN_UNAVAILABLE", message: result.error.message })}
|
|
@@ -28683,23 +28682,23 @@ function identityTokenCommand(options) {
|
|
|
28683
28682
|
process.exitCode = 1;
|
|
28684
28683
|
return;
|
|
28685
28684
|
}
|
|
28686
|
-
const { token,
|
|
28685
|
+
const { token, expires_at } = result.data;
|
|
28687
28686
|
const output = options.format === "gcp" ? JSON.stringify({
|
|
28688
28687
|
version: 1,
|
|
28689
28688
|
success: true,
|
|
28690
28689
|
token_type: "urn:ietf:params:oauth:token-type:jwt",
|
|
28691
28690
|
id_token: token,
|
|
28692
|
-
expiration_time: Math.floor(
|
|
28691
|
+
expiration_time: Math.floor(Date.parse(expires_at) / 1e3)
|
|
28693
28692
|
}) : token;
|
|
28694
28693
|
process.stdout.write(`${output}
|
|
28695
28694
|
`);
|
|
28696
28695
|
}
|
|
28697
|
-
function identityExecCommand(command, options) {
|
|
28696
|
+
async function identityExecCommand(command, options) {
|
|
28698
28697
|
if (command.length === 0) {
|
|
28699
28698
|
console.error(import_chalk5.default.red("Provide a command to run: replicas identity exec -- <command>"));
|
|
28700
28699
|
process.exit(1);
|
|
28701
28700
|
}
|
|
28702
|
-
const tokenResult =
|
|
28701
|
+
const tokenResult = await fetchToken(options.audience);
|
|
28703
28702
|
if (!tokenResult.ok) {
|
|
28704
28703
|
console.error(import_chalk5.default.red(tokenResult.error.message));
|
|
28705
28704
|
process.exitCode = 1;
|
|
@@ -28712,8 +28711,8 @@ function identityExecCommand(command, options) {
|
|
|
28712
28711
|
});
|
|
28713
28712
|
process.exit(result.status ?? 1);
|
|
28714
28713
|
}
|
|
28715
|
-
function identityAwsCredentialsCommand(options) {
|
|
28716
|
-
const result =
|
|
28714
|
+
async function identityAwsCredentialsCommand(options) {
|
|
28715
|
+
const result = await fetchToken(options.audience);
|
|
28717
28716
|
if (!result.ok) {
|
|
28718
28717
|
console.error(import_chalk5.default.red(result.error.message));
|
|
28719
28718
|
process.exitCode = 1;
|
|
@@ -33109,10 +33108,10 @@ if (isAgentMode()) {
|
|
|
33109
33108
|
});
|
|
33110
33109
|
}
|
|
33111
33110
|
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>", "
|
|
33111
|
+
const identity = program.command("identity").description("Obtain short-lived workspace identity tokens (OIDC) for the services this workspace calls");
|
|
33112
|
+
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);
|
|
33113
|
+
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);
|
|
33114
|
+
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
33115
|
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
33116
|
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
33117
|
try {
|