replicas-cli 0.2.757 → 0.2.760
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 +77 -68
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -22927,12 +22927,14 @@ function coerceClaudePartialMessagePayload(payload) {
|
|
|
22927
22927
|
const parentToolUseId = payload.parent_tool_use_id;
|
|
22928
22928
|
const text2 = typeof payload.text === "string" && payload.text ? payload.text : void 0;
|
|
22929
22929
|
const thinking = typeof payload.thinking === "string" && payload.thinking ? payload.thinking : void 0;
|
|
22930
|
-
|
|
22930
|
+
const tool = isRecord(payload.tool) && typeof payload.tool.id === "string" && typeof payload.tool.name === "string" ? typeof payload.tool.filePath === "string" ? { id: payload.tool.id, name: payload.tool.name, filePath: payload.tool.filePath } : typeof payload.tool.command === "string" ? { id: payload.tool.id, name: payload.tool.name, command: payload.tool.command } : void 0 : void 0;
|
|
22931
|
+
if (!text2 && !thinking && !tool) return null;
|
|
22931
22932
|
return {
|
|
22932
22933
|
streamId,
|
|
22933
22934
|
parent_tool_use_id: typeof parentToolUseId === "string" ? parentToolUseId : null,
|
|
22934
22935
|
...text2 ? { text: text2 } : {},
|
|
22935
22936
|
...thinking ? { thinking } : {},
|
|
22937
|
+
...tool ? { tool } : {},
|
|
22936
22938
|
status: payload.status === "completed" ? "completed" : "in_progress"
|
|
22937
22939
|
};
|
|
22938
22940
|
}
|
|
@@ -24152,7 +24154,7 @@ Use subagents for broad, independent analysis when available, but read the files
|
|
|
24152
24154
|
|
|
24153
24155
|
The user may be watching the panel or may have walked away, so ask early and wait late:
|
|
24154
24156
|
|
|
24155
|
-
1. Right after step 1, request
|
|
24157
|
+
1. Right after step 1, request in one batch only the secrets you need to run the app and test its main flow (usually including sign-in) that you cannot replace locally. First check for a local stand-in the app supports, such as a local database, an auth emulator, or documented test credentials. Do not request values you can generate, values that duplicate another key, or values that are not secret, and list optional integrations in the proposal instead of requesting them. \`required\` means the app cannot start, or its main flow cannot be tested, without it.
|
|
24156
24158
|
|
|
24157
24159
|
\`\`\`bash
|
|
24158
24160
|
replicas environment-setup request-variables --file /tmp/variables.json
|
|
@@ -24161,24 +24163,23 @@ replicas environment-setup request-variables --file /tmp/variables.json
|
|
|
24161
24163
|
\`\`\`json
|
|
24162
24164
|
{
|
|
24163
24165
|
"variables": [
|
|
24164
|
-
{ "key": "
|
|
24165
|
-
{ "key": "STRIPE_SECRET_KEY", "description": "Stripe test-mode key; checkout cannot run without it", "required": true }
|
|
24166
|
+
{ "key": "FIREBASE_PRIVATE_KEY", "description": "Service account private key for a dev Firebase project; sign-in cannot be tested without it", "required": true }
|
|
24166
24167
|
]
|
|
24167
24168
|
}
|
|
24168
24169
|
\`\`\`
|
|
24169
24170
|
|
|
24170
24171
|
2. Keep working on everything that does not need the values. The request appears in the Environment panel next to the chat; the user types values there (stored encrypted on the environment, never in chat) or skips them.
|
|
24171
|
-
3. At the point you actually need a value, block on it:
|
|
24172
|
+
3. At the point you actually need a value, say in chat which keys you are waiting for and why, then block on it once:
|
|
24172
24173
|
|
|
24173
24174
|
\`\`\`bash
|
|
24174
|
-
replicas environment-setup wait-variables --timeout
|
|
24175
|
-
replicas environment-setup wait-variables --keys
|
|
24175
|
+
replicas environment-setup wait-variables --timeout 15m
|
|
24176
|
+
replicas environment-setup wait-variables --keys FIREBASE_PRIVATE_KEY --timeout 15m
|
|
24176
24177
|
\`\`\`
|
|
24177
24178
|
|
|
24178
24179
|
Without \`--keys\` it waits for every pending required key. It returns when the keys are provided or skipped, or when the time runs out, and prints which happened. Provided keys are exported for every new shell; restart anything you started with \`replicas service start\` before that point so it picks them up. Never print the values.
|
|
24179
|
-
4. For anything skipped or unanswered, use the safest local substitute (local database, mock, documented test value), say so in the verification rows, and list the key
|
|
24180
|
+
4. For anything skipped or still unanswered after that wait, use the safest local substitute (local database, mock, documented test value), say so in the verification rows, and list the key in the proposal, marked required only if the app cannot start or its main flow cannot be tested without it. A key the user skipped is not asked again; do not resend it.
|
|
24180
24181
|
5. Values the user provided are already saved on the environment. Still list those keys in the proposal so the review shows them as set.
|
|
24181
|
-
6. Requests are only accepted before you propose. Anything still missing after that goes into the proposal
|
|
24182
|
+
6. Requests are only accepted before you propose. Anything still missing after that goes into the proposal for the user to fill in at review.
|
|
24182
24183
|
|
|
24183
24184
|
## 2. Install and run
|
|
24184
24185
|
|
|
@@ -24191,7 +24192,7 @@ Work from the smallest failing layer, in this workspace:
|
|
|
24191
24192
|
|
|
24192
24193
|
Use the repository's pinned package manager and lockfile. Do not upgrade dependencies, rewrite lockfiles, or change application code to make setup pass; environment configuration and narrowly necessary fixes to setup scripts are in scope. Do not deploy, publish, or touch production resources.
|
|
24193
24194
|
|
|
24194
|
-
When something needs a secret you do not have, request it and run \`wait-variables\` at the point you need it (see "Asking for variables"). If it is skipped or unanswered, use the safest local substitute, keep going, and record the variable
|
|
24195
|
+
When something needs a secret you do not have, request it and run \`wait-variables\` at the point you need it (see "Asking for variables"). If it is skipped or unanswered, use the safest local substitute, keep going, and record the variable in the proposal with a clear description. Never invent or paste secret values anywhere.
|
|
24195
24196
|
|
|
24196
24197
|
## 3. Verify and record
|
|
24197
24198
|
|
|
@@ -25405,7 +25406,7 @@ In agent mode the CLI hides commands that don't make sense for in-workspace agen
|
|
|
25405
25406
|
| \`replicas whoami\` | Print the workspace + org identity |
|
|
25406
25407
|
| \`replicas identity token [--audience <aud>]\` | Print the current short-lived workspace identity token for an audience |
|
|
25407
25408
|
| \`replicas identity token --format gcp --audience <aud>\` | Supply a current token to Google's executable credential source |
|
|
25408
|
-
| \`replicas identity aws-credentials --role-arn <arn> [--region <region>]\` | Exchange the current token for AWS credential_process JSON (requires AWS CLI) |
|
|
25409
|
+
| \`replicas identity aws-credentials --role-arn <arn> [--region <region>] [--source-identity]\` | Exchange the current token for AWS credential_process JSON (requires AWS CLI); \`--source-identity\` records the workspace ID in CloudTrail and needs \`sts:SetSourceIdentity\` in the role trust policy |
|
|
25409
25410
|
| \`replicas identity exec [--audience <aud>] -- <command>\` | Run a command with the current token and audience in its environment |
|
|
25410
25411
|
| \`replicas init\` | Create a \`replicas.json\` / \`replicas.yaml\` in the current directory |
|
|
25411
25412
|
| \`replicas connect <name>\` | SSH into another workspace (requires user creds \u2014 usually only useful when scripting locally) |
|
|
@@ -27063,6 +27064,51 @@ function parseMcpToolName(name) {
|
|
|
27063
27064
|
|
|
27064
27065
|
// ../shared/src/display-message/parsers/claude-parser.ts
|
|
27065
27066
|
var ABORTED_TERMINAL_REASONS = /* @__PURE__ */ new Set(["aborted_streaming", "aborted_tools"]);
|
|
27067
|
+
var COMMAND_TOOL_NAMES = /* @__PURE__ */ new Set(["Bash", "bash", "shell"]);
|
|
27068
|
+
var FILE_TOOL_NAMES = /* @__PURE__ */ new Set(["Write", "Edit"]);
|
|
27069
|
+
function fileOrCommandMessage(toolName, toolUseId, input, timestamp) {
|
|
27070
|
+
if (COMMAND_TOOL_NAMES.has(toolName)) {
|
|
27071
|
+
const command = typeof input.command === "string" ? input.command : "";
|
|
27072
|
+
const skillNames = skillNamesFromCommand(command);
|
|
27073
|
+
return {
|
|
27074
|
+
id: `command-${toolUseId}`,
|
|
27075
|
+
type: "command",
|
|
27076
|
+
command,
|
|
27077
|
+
...skillNames.length > 0 ? { skillNames } : {},
|
|
27078
|
+
output: "",
|
|
27079
|
+
status: "in_progress",
|
|
27080
|
+
timestamp
|
|
27081
|
+
};
|
|
27082
|
+
}
|
|
27083
|
+
const filePath = typeof input.file_path === "string" ? input.file_path : "";
|
|
27084
|
+
let diff;
|
|
27085
|
+
if (toolName === "Edit" && typeof input.old_string === "string" && typeof input.new_string === "string") {
|
|
27086
|
+
const oldLines = input.old_string.replace(/\n$/, "").split("\n");
|
|
27087
|
+
const newLines = input.new_string.replace(/\n$/, "").split("\n");
|
|
27088
|
+
diff = [
|
|
27089
|
+
`--- a/${filePath}`,
|
|
27090
|
+
`+++ b/${filePath}`,
|
|
27091
|
+
`@@ -1,${oldLines.length} +1,${newLines.length} @@`,
|
|
27092
|
+
...oldLines.map((l) => `-${l}`),
|
|
27093
|
+
...newLines.map((l) => `+${l}`)
|
|
27094
|
+
].join("\n");
|
|
27095
|
+
} else if (toolName === "Write" && typeof input.content === "string") {
|
|
27096
|
+
const newLines = input.content.replace(/\n$/, "").split("\n");
|
|
27097
|
+
diff = [
|
|
27098
|
+
`--- /dev/null`,
|
|
27099
|
+
`+++ b/${filePath}`,
|
|
27100
|
+
`@@ -0,0 +1,${newLines.length} @@`,
|
|
27101
|
+
...newLines.map((l) => `+${l}`)
|
|
27102
|
+
].join("\n");
|
|
27103
|
+
}
|
|
27104
|
+
return {
|
|
27105
|
+
id: `patch-${toolUseId}`,
|
|
27106
|
+
type: "patch",
|
|
27107
|
+
operations: [{ action: toolName === "Write" ? "add" : "update", path: filePath, diff }],
|
|
27108
|
+
status: "in_progress",
|
|
27109
|
+
timestamp
|
|
27110
|
+
};
|
|
27111
|
+
}
|
|
27066
27112
|
function createSubagentMessage(messageIndex, timestamp, fields) {
|
|
27067
27113
|
const { id = `subagent-${timestamp}-${messageIndex}`, ...message } = fields;
|
|
27068
27114
|
return { id, type: "subagent", ...message, timestamp };
|
|
@@ -27099,6 +27145,7 @@ function parseClaudeEvents(events, parentToolUseId) {
|
|
|
27099
27145
|
const workflowAgentMessageMap = /* @__PURE__ */ new Map();
|
|
27100
27146
|
const ambientTaskIds = /* @__PURE__ */ new Set();
|
|
27101
27147
|
const partialIndexes = /* @__PURE__ */ new Map();
|
|
27148
|
+
const streamingTools = /* @__PURE__ */ new Map();
|
|
27102
27149
|
const completedStreamIds = /* @__PURE__ */ new Set();
|
|
27103
27150
|
const supersededStreamIds = /* @__PURE__ */ new Set();
|
|
27104
27151
|
let liveStreamId = null;
|
|
@@ -27176,6 +27223,7 @@ function parseClaudeEvents(events, parentToolUseId) {
|
|
|
27176
27223
|
if (existing.agent !== void 0) messages[existing.agent] = agentMessage;
|
|
27177
27224
|
else existing.agent = messages.push(agentMessage) - 1;
|
|
27178
27225
|
}
|
|
27226
|
+
if (payload.tool) streamingTools.set(payload.streamId, { tool: payload.tool, timestamp: event.timestamp });
|
|
27179
27227
|
partialIndexes.set(payload.streamId, existing);
|
|
27180
27228
|
return;
|
|
27181
27229
|
}
|
|
@@ -27302,56 +27350,9 @@ function parseClaudeEvents(events, parentToolUseId) {
|
|
|
27302
27350
|
status: "in_progress",
|
|
27303
27351
|
nestedEvents
|
|
27304
27352
|
}));
|
|
27305
|
-
} else if (toolName
|
|
27353
|
+
} else if (COMMAND_TOOL_NAMES.has(toolName) || FILE_TOOL_NAMES.has(toolName)) {
|
|
27306
27354
|
const inputObj = typeof toolInput === "string" ? safeJsonParse(toolInput, {}) : toolInput;
|
|
27307
|
-
|
|
27308
|
-
const skillNames = skillNamesFromCommand(command);
|
|
27309
|
-
messages.push({
|
|
27310
|
-
id: `command-${event.timestamp}-${messages.length}`,
|
|
27311
|
-
type: "command",
|
|
27312
|
-
command,
|
|
27313
|
-
...skillNames.length > 0 ? { skillNames } : {},
|
|
27314
|
-
output: "",
|
|
27315
|
-
status: "in_progress",
|
|
27316
|
-
timestamp: event.timestamp
|
|
27317
|
-
});
|
|
27318
|
-
} else if (toolName === "Write" || toolName === "Edit") {
|
|
27319
|
-
const inputObj = typeof toolInput === "string" ? safeJsonParse(toolInput, {}) : toolInput;
|
|
27320
|
-
const filePath = inputObj.file_path || "";
|
|
27321
|
-
const action = toolName === "Write" ? "add" : "update";
|
|
27322
|
-
let diff;
|
|
27323
|
-
if (toolName === "Edit" && inputObj.old_string != null && inputObj.new_string != null) {
|
|
27324
|
-
const oldLines = inputObj.old_string.replace(/\n$/, "").split("\n");
|
|
27325
|
-
const newLines = inputObj.new_string.replace(/\n$/, "").split("\n");
|
|
27326
|
-
const hunk = `@@ -1,${oldLines.length} +1,${newLines.length} @@`;
|
|
27327
|
-
diff = [
|
|
27328
|
-
`--- a/${filePath}`,
|
|
27329
|
-
`+++ b/${filePath}`,
|
|
27330
|
-
hunk,
|
|
27331
|
-
...oldLines.map((l) => `-${l}`),
|
|
27332
|
-
...newLines.map((l) => `+${l}`)
|
|
27333
|
-
].join("\n");
|
|
27334
|
-
} else if (toolName === "Write" && inputObj.content != null) {
|
|
27335
|
-
const newLines = inputObj.content.replace(/\n$/, "").split("\n");
|
|
27336
|
-
const hunk = `@@ -0,0 +1,${newLines.length} @@`;
|
|
27337
|
-
diff = [
|
|
27338
|
-
`--- /dev/null`,
|
|
27339
|
-
`+++ b/${filePath}`,
|
|
27340
|
-
hunk,
|
|
27341
|
-
...newLines.map((l) => `+${l}`)
|
|
27342
|
-
].join("\n");
|
|
27343
|
-
}
|
|
27344
|
-
messages.push({
|
|
27345
|
-
id: `patch-${event.timestamp}-${messages.length}`,
|
|
27346
|
-
type: "patch",
|
|
27347
|
-
operations: [{
|
|
27348
|
-
action,
|
|
27349
|
-
path: filePath,
|
|
27350
|
-
diff
|
|
27351
|
-
}],
|
|
27352
|
-
status: "in_progress",
|
|
27353
|
-
timestamp: event.timestamp
|
|
27354
|
-
});
|
|
27355
|
+
messages.push(fileOrCommandMessage(toolName, toolUseId, inputObj, event.timestamp));
|
|
27355
27356
|
} else if (toolName === "TaskCreate" || toolName === "TaskUpdate" || toolName === "TaskList") {
|
|
27356
27357
|
taskAccumulator.processContentBlock(block);
|
|
27357
27358
|
const snapshot = taskSnapshot();
|
|
@@ -27531,6 +27532,11 @@ function parseClaudeEvents(events, parentToolUseId) {
|
|
|
27531
27532
|
};
|
|
27532
27533
|
}
|
|
27533
27534
|
});
|
|
27535
|
+
for (const [streamId, { tool, timestamp }] of streamingTools) {
|
|
27536
|
+
if (toolCallMap.has(tool.id) || supersededStreamIds.has(streamId)) continue;
|
|
27537
|
+
if (!COMMAND_TOOL_NAMES.has(tool.name) && !FILE_TOOL_NAMES.has(tool.name)) continue;
|
|
27538
|
+
messages.push(fileOrCommandMessage(tool.name, tool.id, "filePath" in tool ? { file_path: tool.filePath } : { command: tool.command }, timestamp));
|
|
27539
|
+
}
|
|
27534
27540
|
filteredEvents.forEach((event) => {
|
|
27535
27541
|
if (event.type === "claude-user") {
|
|
27536
27542
|
const content = normalizeContentBlocks(event.payload.message?.content);
|
|
@@ -28012,7 +28018,7 @@ var headlessFilesystemAgentResultSchema = external_exports.object({
|
|
|
28012
28018
|
});
|
|
28013
28019
|
|
|
28014
28020
|
// ../shared/src/cli-version.ts
|
|
28015
|
-
var CLI_VERSION = "0.2.
|
|
28021
|
+
var CLI_VERSION = "0.2.760";
|
|
28016
28022
|
|
|
28017
28023
|
// ../shared/src/version.ts
|
|
28018
28024
|
function compareVersions(v1, v2) {
|
|
@@ -28703,6 +28709,7 @@ async function readSseStream(body, onEvent, shouldContinue = () => true) {
|
|
|
28703
28709
|
var import_yaml2 = __toESM(require_dist());
|
|
28704
28710
|
|
|
28705
28711
|
// ../shared/src/workspace-identity.ts
|
|
28712
|
+
var AWS_SOURCE_IDENTITY_CLAIM = "https://aws.amazon.com/source_identity";
|
|
28706
28713
|
var WORKSPACE_TOKEN_TTL_SECONDS = 15 * 60;
|
|
28707
28714
|
var IDENTITY_PROXY_PORT = 17323;
|
|
28708
28715
|
var IDENTITY_TOKEN_PATH = "/token";
|
|
@@ -28712,7 +28719,8 @@ var WORKSPACE_TOKEN_ENV = {
|
|
|
28712
28719
|
};
|
|
28713
28720
|
var workspaceAudienceSchema = external_exports.string().min(1).max(255).regex(/^[\x21-\x7e]+$/, "Audience must be a single printable token without spaces");
|
|
28714
28721
|
var workspaceTokenRequestSchema = external_exports.object({
|
|
28715
|
-
audience: workspaceAudienceSchema.optional()
|
|
28722
|
+
audience: workspaceAudienceSchema.optional(),
|
|
28723
|
+
aws_source_identity: external_exports.boolean().optional()
|
|
28716
28724
|
});
|
|
28717
28725
|
var workspaceTokenClaimsSchema = external_exports.object({
|
|
28718
28726
|
iss: external_exports.string(),
|
|
@@ -28726,7 +28734,8 @@ var workspaceTokenClaimsSchema = external_exports.object({
|
|
|
28726
28734
|
workspace_id: external_exports.string().uuid(),
|
|
28727
28735
|
environment_id: external_exports.string().uuid(),
|
|
28728
28736
|
creator_id: external_exports.string().uuid().nullable(),
|
|
28729
|
-
creator_email: external_exports.string().nullable().default(null)
|
|
28737
|
+
creator_email: external_exports.string().nullable().default(null),
|
|
28738
|
+
[AWS_SOURCE_IDENTITY_CLAIM]: external_exports.string().uuid().optional()
|
|
28730
28739
|
}).passthrough();
|
|
28731
28740
|
var workspaceTokenResponseSchema = external_exports.object({
|
|
28732
28741
|
issuer: external_exports.string(),
|
|
@@ -29250,13 +29259,13 @@ var import_node_child_process = require("child_process");
|
|
|
29250
29259
|
var import_node_os = require("os");
|
|
29251
29260
|
var import_node_path = require("path");
|
|
29252
29261
|
var import_chalk5 = __toESM(require("chalk"));
|
|
29253
|
-
async function fetchToken(audience) {
|
|
29262
|
+
async function fetchToken(audience, awsSourceIdentity) {
|
|
29254
29263
|
let response;
|
|
29255
29264
|
try {
|
|
29256
29265
|
response = await fetch(identityTokenUrl(), {
|
|
29257
29266
|
method: "POST",
|
|
29258
29267
|
headers: { "content-type": "application/json" },
|
|
29259
|
-
body: JSON.stringify(audience
|
|
29268
|
+
body: JSON.stringify({ audience: audience || void 0, aws_source_identity: awsSourceIdentity || void 0 })
|
|
29260
29269
|
});
|
|
29261
29270
|
} catch {
|
|
29262
29271
|
return createErrorResult({ message: "Workspace identity is only available inside a running Replicas workspace." });
|
|
@@ -29311,7 +29320,7 @@ async function identityExecCommand(command, options) {
|
|
|
29311
29320
|
process.exit(result.status ?? 1);
|
|
29312
29321
|
}
|
|
29313
29322
|
async function identityAwsCredentialsCommand(options) {
|
|
29314
|
-
const key = (0, import_node_crypto.createHash)("sha256").update(JSON.stringify([options.roleArn, options.audience, options.region, options.sessionName])).digest("hex");
|
|
29323
|
+
const key = (0, import_node_crypto.createHash)("sha256").update(JSON.stringify([options.roleArn, options.audience, options.region, options.sessionName, options.sourceIdentity])).digest("hex");
|
|
29315
29324
|
const cacheFile = (0, import_node_path.join)((0, import_node_os.homedir)(), ".replicas", "aws-credentials", `${key}.json`);
|
|
29316
29325
|
try {
|
|
29317
29326
|
const cached2 = (0, import_node_fs.readFileSync)(cacheFile, "utf8");
|
|
@@ -29321,7 +29330,7 @@ async function identityAwsCredentialsCommand(options) {
|
|
|
29321
29330
|
}
|
|
29322
29331
|
} catch {
|
|
29323
29332
|
}
|
|
29324
|
-
const result = await fetchToken(options.audience);
|
|
29333
|
+
const result = await fetchToken(options.audience, options.sourceIdentity);
|
|
29325
29334
|
if (!result.ok) {
|
|
29326
29335
|
console.error(import_chalk5.default.red(result.error.message));
|
|
29327
29336
|
process.exitCode = 1;
|
|
@@ -33899,7 +33908,7 @@ if (isEnvironmentSetupWorkspace()) {
|
|
|
33899
33908
|
if (isAgentMode()) {
|
|
33900
33909
|
const identity = program.command("identity").description("Obtain short-lived workspace identity tokens (OIDC) for the services this workspace calls");
|
|
33901
33910
|
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);
|
|
33902
|
-
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);
|
|
33911
|
+
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").option("--source-identity", "Record the workspace ID as the AWS source identity (role trust policy must allow sts:SetSourceIdentity)").action(identityAwsCredentialsCommand);
|
|
33903
33912
|
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));
|
|
33904
33913
|
const service = program.command("service").description("Run long-lived services (dev servers, daemons) detached from the agent session so they survive workspace sleep/wake");
|
|
33905
33914
|
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) => {
|