replicas-cli 0.2.598 → 0.2.600

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.
Files changed (2) hide show
  1. package/dist/index.cjs +268 -37
  2. package/package.json +1 -1
package/dist/index.cjs CHANGED
@@ -7646,6 +7646,7 @@ var AGENT = {
7646
7646
  DEEPSEEK: "deepseek",
7647
7647
  FX: "fx",
7648
7648
  KIMI: "kimi",
7649
+ MUSE: "muse",
7649
7650
  OPENCODE: "opencode",
7650
7651
  PI: "pi",
7651
7652
  RELAY: "relay"
@@ -7692,6 +7693,11 @@ var AGENT_PROVIDER_OPTIONS = [
7692
7693
  label: "Kimi Code",
7693
7694
  description: "Use Kimi Code for tasks"
7694
7695
  },
7696
+ {
7697
+ value: "muse",
7698
+ label: "Muse Code",
7699
+ description: "Use Muse Code for tasks"
7700
+ },
7695
7701
  {
7696
7702
  value: "opencode",
7697
7703
  label: "Opencode",
@@ -7717,6 +7723,7 @@ var THINKING_LEVELS_BY_AGENT = {
7717
7723
  deepseek: STANDARD_THINKING_LEVELS,
7718
7724
  fx: STANDARD_THINKING_LEVELS,
7719
7725
  kimi: STANDARD_THINKING_LEVELS,
7726
+ muse: VALID_THINKING_LEVELS.filter((level) => level !== "max" && level !== "ultracode"),
7720
7727
  opencode: STANDARD_THINKING_LEVELS,
7721
7728
  pi: STANDARD_THINKING_LEVELS,
7722
7729
  relay: [...STANDARD_THINKING_LEVELS, "ultracode"]
@@ -7742,6 +7749,8 @@ function getProviderDisplayName(provider, variant = "short") {
7742
7749
  return "fx";
7743
7750
  case "kimi":
7744
7751
  return variant === "long" ? "Kimi Code" : "Kimi";
7752
+ case "muse":
7753
+ return variant === "long" ? "Muse Code" : "Muse";
7745
7754
  case "opencode":
7746
7755
  return "Opencode";
7747
7756
  case "pi":
@@ -7773,7 +7782,8 @@ var CREDENTIAL_METHOD = {
7773
7782
  OPENCODE_GO: "opencode-go",
7774
7783
  ASTER: "aster",
7775
7784
  OPENROUTER: "openrouter",
7776
- AI_GATEWAY: "ai-gateway"
7785
+ AI_GATEWAY: "ai-gateway",
7786
+ MUSE_OAUTH: "muse-oauth"
7777
7787
  };
7778
7788
  var CREDENTIAL_TYPE = {
7779
7789
  CLAUDE_OAUTH: "claude",
@@ -7787,7 +7797,8 @@ var CREDENTIAL_TYPE = {
7787
7797
  OPENCODE_GO_API_KEY: "opencode_go_api_key",
7788
7798
  ASTER_API_KEY: "aster_api_key",
7789
7799
  OPENROUTER_API_KEY: "openrouter_api_key",
7790
- AI_GATEWAY_API_KEY: "ai_gateway_api_key"
7800
+ AI_GATEWAY_API_KEY: "ai_gateway_api_key",
7801
+ MUSE_OAUTH: "muse_oauth"
7791
7802
  };
7792
7803
  var INFERENCE_PROVIDER_LABELS = {
7793
7804
  [CREDENTIAL_METHOD.OPENCODE_GO]: "OpenCode Go",
@@ -7818,6 +7829,9 @@ var AGENT_CREDENTIAL_METHODS_IN_ORDER = {
7818
7829
  [AGENT.KIMI]: [
7819
7830
  { method: CREDENTIAL_METHOD.AI_GATEWAY, credentialType: CREDENTIAL_TYPE.AI_GATEWAY_API_KEY }
7820
7831
  ],
7832
+ [AGENT.MUSE]: [
7833
+ { method: CREDENTIAL_METHOD.MUSE_OAUTH, credentialType: CREDENTIAL_TYPE.MUSE_OAUTH }
7834
+ ],
7821
7835
  [AGENT.OPENCODE]: [
7822
7836
  { method: CREDENTIAL_METHOD.OPENCODE_GO, credentialType: CREDENTIAL_TYPE.OPENCODE_GO_API_KEY },
7823
7837
  { method: CREDENTIAL_METHOD.ASTER, credentialType: CREDENTIAL_TYPE.ASTER_API_KEY },
@@ -22438,6 +22452,7 @@ var DEEPSEEK_V4_PRO_MODEL = "deepseek/deepseek-v4-pro-0813";
22438
22452
  var DEEPSEEK_V4_FLASH_MODEL = "deepseek/deepseek-v4-flash-0731";
22439
22453
  var DEFAULT_FX_MODEL = "zai/glm-5.2";
22440
22454
  var DEFAULT_KIMI_MODEL = "moonshotai/kimi-k2.6";
22455
+ var DEFAULT_MUSE_MODEL = "muse-spark-1.2";
22441
22456
  var OPENROUTER_MODELS = [
22442
22457
  DEFAULT_OPENCODE_MODEL,
22443
22458
  GLM_5_3_FLASH_MODEL,
@@ -22533,6 +22548,7 @@ var AGENT_MODELS = {
22533
22548
  deepseek: prioritizeDeepseekModels(OPENROUTER_MODELS),
22534
22549
  fx: [DEFAULT_FX_MODEL],
22535
22550
  kimi: [DEFAULT_KIMI_MODEL],
22551
+ muse: [DEFAULT_MUSE_MODEL],
22536
22552
  opencode: [...OPENROUTER_MODELS, ...ASTER_MODELS],
22537
22553
  pi: [...OPENROUTER_MODELS, ...ASTER_MODELS],
22538
22554
  relay: [CLAUDE_FABLE_5_1_MODEL, CLAUDE_FABLE_5_MODEL, CLAUDE_OPUS_5_MODEL, CLAUDE_OPUS_4_8_MODEL, CLAUDE_SONNET_5_MODEL]
@@ -22576,6 +22592,7 @@ var MODEL_LABELS = {
22576
22592
  "minimax/minimax-m3": "MiniMax M3 via OpenRouter",
22577
22593
  "xiaomi/mimo-v2.5-pro": "MiMo V2.5 Pro via OpenRouter",
22578
22594
  "moonshotai/kimi-k2.6": "Kimi K2.6 via OpenRouter",
22595
+ [DEFAULT_MUSE_MODEL]: "Muse Spark 1.2",
22579
22596
  "google/gemini-3.8-flash": "Gemini 3.8 Flash via OpenRouter",
22580
22597
  ...ASTER_MODEL_LABELS,
22581
22598
  "gpt-5.4": "GPT-5.4",
@@ -24299,13 +24316,14 @@ var SENTRY_ABILITY = {
24299
24316
 
24300
24317
  // ../shared/src/default-skills/replicas-agent/abilities/slack.ts
24301
24318
  var SECTION11 = `### Slack
24302
- Send messages, read threads, search conversations, and upload files through the workspace-scoped TypeScript SDK.
24319
+ Send messages, read threads, search conversations, and transfer files through the workspace-scoped TypeScript SDK.
24303
24320
 
24304
24321
  **Reference:** \`references/SLACK.md\`
24305
24322
 
24306
24323
  Use this when:
24307
24324
  - You need to send a message to a Slack channel or thread
24308
24325
  - You need to read or search Slack conversations
24326
+ - You need to download a file attached to a Slack message
24309
24327
  - You encounter a Slack message link and need its full thread`;
24310
24328
  var REFERENCE11 = `# Slack Integration
24311
24329
 
@@ -24332,6 +24350,15 @@ const thread = await replicas.slack.call('conversations.replies', {
24332
24350
  });
24333
24351
  \`\`\`
24334
24352
 
24353
+ ## Download a file
24354
+
24355
+ Pass a Slack file object's \`url_private_download\` to the authenticated download helper. Provider credentials stay behind the workspace gateway.
24356
+
24357
+ \`\`\`ts
24358
+ const response = await replicas.slack.download(file.url_private_download);
24359
+ await Bun.write('/tmp/recording.mov', response);
24360
+ \`\`\`
24361
+
24335
24362
  ## Send and attach a message
24336
24363
 
24337
24364
  \`\`\`ts
@@ -24380,7 +24407,7 @@ Supported methods cover conversations, messages, search, users, reactions, and S
24380
24407
  `;
24381
24408
  var SLACK_ABILITY = {
24382
24409
  label: "Slack",
24383
- description: "Send messages, read threads, and search through @replicas/sdk.",
24410
+ description: "Send messages, read threads, search, and transfer files through @replicas/sdk.",
24384
24411
  bullet: "- Interacting with Slack (sending messages, reading threads, etc.)",
24385
24412
  section: SECTION11,
24386
24413
  referenceFile: { name: "SLACK.md", content: REFERENCE11 }
@@ -24556,7 +24583,7 @@ function isTransientErrorText(text, options = {}) {
24556
24583
  }
24557
24584
 
24558
24585
  // ../shared/src/cli-version.ts
24559
- var CLI_VERSION = "0.2.598";
24586
+ var CLI_VERSION = "0.2.600";
24560
24587
 
24561
24588
  // ../shared/src/version.ts
24562
24589
  function compareVersions(v1, v2) {
@@ -25264,6 +25291,38 @@ function upsertDisplayMessage(messages, message) {
25264
25291
  if (index === -1) messages.push(message);
25265
25292
  else messages[index] = message;
25266
25293
  }
25294
+ function applyToolInputEvent(event, messages, provider, state, questionFilter) {
25295
+ if (event.type === "replicas-tool-input-request" && typeof event.payload.toolUseId === "string" && typeof event.payload.requestId === "string" && (Array.isArray(event.payload.options) || Array.isArray(event.payload.questions))) {
25296
+ const resolved = state.resolutions.get(event.payload.toolUseId);
25297
+ const inputRequest = {
25298
+ requestId: event.payload.requestId,
25299
+ status: resolved?.selectionId === "aborted" || resolved?.selectionId === "declined" ? "aborted" : resolved ? "resolved" : "pending",
25300
+ ...Array.isArray(event.payload.options) ? { options: event.payload.options } : {},
25301
+ ...Array.isArray(event.payload.questions) ? { questions: questionFilter ? event.payload.questions.filter(questionFilter) : event.payload.questions } : {},
25302
+ ...resolved ? { selectionId: resolved.selectionId } : {},
25303
+ ...resolved?.selectionSummary ? { selectionSummary: resolved.selectionSummary } : {}
25304
+ };
25305
+ state.requests.set(event.payload.toolUseId, inputRequest);
25306
+ const message = messages.find((candidate) => candidate.type === "tool_call" && candidate.id === `${provider}-tool-${event.payload.toolUseId}`);
25307
+ if (message) message.inputRequest = inputRequest;
25308
+ return true;
25309
+ }
25310
+ if (event.type === "replicas-tool-input-resolved" && typeof event.payload.toolUseId === "string" && typeof event.payload.selectionId === "string") {
25311
+ const resolved = {
25312
+ selectionId: event.payload.selectionId,
25313
+ ...typeof event.payload.selectionSummary === "string" ? { selectionSummary: event.payload.selectionSummary } : {}
25314
+ };
25315
+ state.resolutions.set(event.payload.toolUseId, resolved);
25316
+ const inputRequest = state.requests.get(event.payload.toolUseId);
25317
+ if (inputRequest) {
25318
+ inputRequest.status = resolved.selectionId === "aborted" || resolved.selectionId === "declined" ? "aborted" : "resolved";
25319
+ inputRequest.selectionId = resolved.selectionId;
25320
+ if (resolved.selectionSummary) inputRequest.selectionSummary = resolved.selectionSummary;
25321
+ }
25322
+ return true;
25323
+ }
25324
+ return false;
25325
+ }
25267
25326
  function parseSkillName(tool, input) {
25268
25327
  if (typeof tool !== "string") return null;
25269
25328
  const normalizedTool = tool.toLowerCase();
@@ -25983,7 +26042,7 @@ function isProviderEvent(event, provider, suffix) {
25983
26042
  function parseAcpEvents(events, provider) {
25984
26043
  const messages = [];
25985
26044
  const activeChunks = {};
25986
- const resolvedInputs = /* @__PURE__ */ new Map();
26045
+ const inputState = { requests: /* @__PURE__ */ new Map(), resolutions: /* @__PURE__ */ new Map() };
25987
26046
  let chunkSequence = 0;
25988
26047
  for (const event of events) {
25989
26048
  const userContent = getUserMessage(event);
@@ -26017,37 +26076,7 @@ function parseAcpEvents(events, provider) {
26017
26076
  activeChunks.agent_thought_chunk = void 0;
26018
26077
  continue;
26019
26078
  }
26020
- if (event.type === "replicas-tool-input-request" && typeof event.payload.toolUseId === "string" && typeof event.payload.requestId === "string") {
26021
- const message = messages.find((candidate) => candidate.type === "tool_call" && candidate.id === `${provider}-tool-${event.payload.toolUseId}`);
26022
- if (message && (Array.isArray(event.payload.options) || Array.isArray(event.payload.questions))) {
26023
- const resolved = resolvedInputs.get(event.payload.toolUseId);
26024
- message.inputRequest = {
26025
- requestId: event.payload.requestId,
26026
- status: resolved?.selectionId === "aborted" ? "aborted" : resolved ? "resolved" : "pending",
26027
- ...Array.isArray(event.payload.options) ? { options: event.payload.options } : {},
26028
- ...Array.isArray(event.payload.questions) ? { questions: event.payload.questions } : {},
26029
- ...resolved ? { selectionId: resolved.selectionId } : {},
26030
- ...resolved?.selectionSummary ? { selectionSummary: resolved.selectionSummary } : {}
26031
- };
26032
- }
26033
- continue;
26034
- }
26035
- if (event.type === "replicas-tool-input-resolved" && typeof event.payload.toolUseId === "string" && typeof event.payload.selectionId === "string") {
26036
- const resolved = {
26037
- selectionId: event.payload.selectionId,
26038
- ...typeof event.payload.selectionSummary === "string" ? { selectionSummary: event.payload.selectionSummary } : {}
26039
- };
26040
- resolvedInputs.set(event.payload.toolUseId, resolved);
26041
- const message = messages.find((candidate) => candidate.type === "tool_call" && candidate.id === `${provider}-tool-${event.payload.toolUseId}`);
26042
- if (message?.inputRequest) {
26043
- message.inputRequest = {
26044
- ...message.inputRequest,
26045
- status: resolved.selectionId === "aborted" ? "aborted" : "resolved",
26046
- ...resolved
26047
- };
26048
- }
26049
- continue;
26050
- }
26079
+ if (applyToolInputEvent(event, messages, provider, inputState)) continue;
26051
26080
  if (!isProviderEvent(event, provider, "session-update") || !isRecord(event.payload.update)) continue;
26052
26081
  const update = event.payload.update;
26053
26082
  const kind = update.sessionUpdate;
@@ -26275,6 +26304,108 @@ function parseOpencodeEvents(events) {
26275
26304
  return messages;
26276
26305
  }
26277
26306
 
26307
+ // ../shared/src/display-message/parsers/muse-parser.ts
26308
+ function isToolInputQuestion(value) {
26309
+ return isRecord(value) && typeof value.id === "string" && typeof value.prompt === "string" && typeof value.multiSelect === "boolean" && Array.isArray(value.options) && value.options.every((option) => isRecord(option) && typeof option.id === "string" && typeof option.label === "string");
26310
+ }
26311
+ function parseMuseEvents(events) {
26312
+ const messages = [];
26313
+ const deltas = /* @__PURE__ */ new Map();
26314
+ const inputState = { requests: /* @__PURE__ */ new Map(), resolutions: /* @__PURE__ */ new Map() };
26315
+ for (const event of events) {
26316
+ const userContent = getUserMessage(event);
26317
+ if (userContent !== null) {
26318
+ if (userContent.trim()) messages.push({
26319
+ id: getUserMessageId(event) ?? `muse-user-${event.timestamp}`,
26320
+ type: "user",
26321
+ content: userContent,
26322
+ timestamp: event.timestamp
26323
+ });
26324
+ continue;
26325
+ }
26326
+ if (event.type === "muse-error") {
26327
+ messages.push({
26328
+ id: `muse-error-${event.timestamp}`,
26329
+ type: "error",
26330
+ message: typeof event.payload.message === "string" ? event.payload.message : "Muse failed",
26331
+ timestamp: event.timestamp
26332
+ });
26333
+ continue;
26334
+ }
26335
+ if (event.type === "muse-turn-completed" && isRecord(event.payload.error)) {
26336
+ messages.push({
26337
+ id: `muse-turn-error-${typeof event.payload.turnId === "string" ? event.payload.turnId : event.timestamp}`,
26338
+ type: "error",
26339
+ message: typeof event.payload.error.message === "string" ? event.payload.error.message : "Muse turn failed",
26340
+ timestamp: event.timestamp
26341
+ });
26342
+ continue;
26343
+ }
26344
+ if (applyToolInputEvent(event, messages, "muse", inputState, isToolInputQuestion)) continue;
26345
+ if (event.type === "muse-item-delta" && typeof event.payload.itemId === "string" && typeof event.payload.delta === "string") {
26346
+ const field2 = typeof event.payload.field === "string" ? event.payload.field : "text";
26347
+ const key = `${event.payload.itemId}:${field2}`;
26348
+ const content = `${deltas.get(key) ?? ""}${event.payload.delta}`;
26349
+ deltas.set(key, content);
26350
+ if (field2 === "text") upsertDisplayMessage(messages, {
26351
+ id: `muse-agent-${event.payload.itemId}`,
26352
+ type: "agent",
26353
+ content,
26354
+ timestamp: event.timestamp
26355
+ });
26356
+ if (field2.startsWith("summary")) upsertDisplayMessage(messages, {
26357
+ id: `muse-reasoning-${event.payload.itemId}`,
26358
+ type: "reasoning",
26359
+ content,
26360
+ status: "in_progress",
26361
+ timestamp: event.timestamp
26362
+ });
26363
+ continue;
26364
+ }
26365
+ if (!["muse-item-started", "muse-item-updated", "muse-item-completed"].includes(event.type) || !isRecord(event.payload.item)) continue;
26366
+ const item = event.payload.item;
26367
+ if (typeof item.itemId !== "string" || typeof item.kind !== "string") continue;
26368
+ const terminal = item.status !== "inProgress";
26369
+ if (item.kind === "agentMessage" && typeof item.text === "string" && item.text) {
26370
+ upsertDisplayMessage(messages, {
26371
+ id: `muse-agent-${item.itemId}`,
26372
+ type: "agent",
26373
+ content: item.text,
26374
+ timestamp: typeof item.recordedAt === "string" ? item.recordedAt : event.timestamp
26375
+ });
26376
+ } else if (item.kind === "reasoning") {
26377
+ const content = Array.isArray(item.summary) ? item.summary.filter((part) => typeof part === "string").join("\n") : typeof item.text === "string" ? item.text : "";
26378
+ if (content) upsertDisplayMessage(messages, {
26379
+ id: `muse-reasoning-${item.itemId}`,
26380
+ type: "reasoning",
26381
+ content,
26382
+ status: terminal ? "completed" : "in_progress",
26383
+ timestamp: typeof item.recordedAt === "string" ? item.recordedAt : event.timestamp
26384
+ });
26385
+ } else if (item.kind === "toolCall") {
26386
+ let input = item.args;
26387
+ if (typeof item.args === "string") {
26388
+ try {
26389
+ input = JSON.parse(item.args);
26390
+ } catch {
26391
+ }
26392
+ }
26393
+ const message = createCallDisplayMessage({
26394
+ id: `muse-tool-${item.itemId}`,
26395
+ server: "muse",
26396
+ tool: typeof item.tool === "string" ? item.tool : "tool",
26397
+ input: isRecord(input) ? input : typeof input === "string" ? input : void 0,
26398
+ output: typeof item.visibleOutput === "string" ? item.visibleOutput : item.failureReason === void 0 ? void 0 : stringifyDisplayValue(item.failureReason),
26399
+ status: item.status === "failed" || item.status === "rejected" ? "failed" : terminal ? "completed" : "in_progress",
26400
+ timestamp: typeof item.recordedAt === "string" ? item.recordedAt : event.timestamp
26401
+ });
26402
+ if (message.type === "tool_call") message.inputRequest = inputState.requests.get(item.itemId);
26403
+ upsertDisplayMessage(messages, message);
26404
+ }
26405
+ }
26406
+ return messages;
26407
+ }
26408
+
26278
26409
  // ../shared/src/display-message/parsers/pi-parser.ts
26279
26410
  function nestedPayload(event) {
26280
26411
  return isRecord(event.payload.assistantMessageEvent) ? event.payload.assistantMessageEvent : event.payload;
@@ -27331,6 +27462,9 @@ function parseAgentEvents(events, agentType) {
27331
27462
  if (agentType === "kimi") {
27332
27463
  return parseAcpEvents(events, "kimi");
27333
27464
  }
27465
+ if (agentType === "muse") {
27466
+ return parseMuseEvents(events);
27467
+ }
27334
27468
  if (agentType === "opencode") {
27335
27469
  return parseOpencodeEvents(events);
27336
27470
  }
@@ -28942,6 +29076,92 @@ async function claudeAuthCommand(options = {}) {
28942
29076
  });
28943
29077
  }
28944
29078
 
29079
+ // src/lib/muse-oauth.ts
29080
+ var CLIENT_ID = "1031625952748946";
29081
+ var AUTH_URL = "https://auth.meta.com";
29082
+ var API_KEY_URL = "https://api.meta.ai/muse-code/key";
29083
+ async function post(path6, body) {
29084
+ return fetch(`${AUTH_URL}${path6}`, {
29085
+ method: "POST",
29086
+ headers: { "Content-Type": "application/x-www-form-urlencoded" },
29087
+ body
29088
+ });
29089
+ }
29090
+ async function mintMuseApiKey(identityToken, fetchImpl = fetch) {
29091
+ const response = await fetchImpl(API_KEY_URL, {
29092
+ method: "POST",
29093
+ headers: {
29094
+ Accept: "application/json",
29095
+ Authorization: `Bearer ${identityToken}`,
29096
+ "Content-Type": "application/json",
29097
+ "x-api-version": "1.0.0"
29098
+ },
29099
+ body: "{}"
29100
+ });
29101
+ const body = await response.json();
29102
+ if (!response.ok) {
29103
+ const detail = isRecord(body) && typeof body.message === "string" ? `: ${body.message}` : "";
29104
+ throw new Error(`Muse API-key setup failed (${response.status})${detail}`);
29105
+ }
29106
+ if (!isRecord(body) || typeof body.api_key !== "string" || !body.api_key) {
29107
+ const setup = isRecord(body) && typeof body.action_url === "string" ? ` Complete setup at ${body.action_url}.` : "";
29108
+ throw new Error(`Muse did not issue an API key.${setup}`);
29109
+ }
29110
+ return body.api_key;
29111
+ }
29112
+ async function runMuseOAuthFlow(totalSteps) {
29113
+ const authorization = await post("/oidc/device/authorization/", new URLSearchParams({ client_id: CLIENT_ID }));
29114
+ if (!authorization.ok) throw new Error(`Muse sign-in could not start (${authorization.status}).`);
29115
+ const device = await authorization.json();
29116
+ if (!isRecord(device) || typeof device.device_code !== "string" || typeof device.user_code !== "string" || typeof device.verification_uri !== "string") {
29117
+ throw new Error("Muse returned an invalid device authorization response.");
29118
+ }
29119
+ const approvalUrl = typeof device.verification_uri_complete === "string" ? device.verification_uri_complete : device.verification_uri;
29120
+ renderAuthFlowStep(1, totalSteps, "Approve access with your Meta account");
29121
+ renderAuthFlowDetail(`code: ${device.user_code}`);
29122
+ await openForApproval(new URL(approvalUrl).hostname, approvalUrl);
29123
+ renderAuthFlowDetail("waiting for sign-in\u2026");
29124
+ const deadline = Date.now() + (typeof device.expires_in === "number" ? device.expires_in : 900) * 1e3;
29125
+ let intervalMs = Math.max(1, typeof device.interval === "number" ? device.interval : 5) * 1e3;
29126
+ while (Date.now() < deadline) {
29127
+ await new Promise((resolve2) => setTimeout(resolve2, intervalMs));
29128
+ const response = await post("/oidc/device/token/", new URLSearchParams({
29129
+ grant_type: "urn:ietf:params:oauth:grant-type:device_code",
29130
+ device_code: device.device_code,
29131
+ client_id: CLIENT_ID
29132
+ }));
29133
+ const token = await response.json();
29134
+ if (!isRecord(token)) throw new Error("Muse returned an invalid token response.");
29135
+ if (response.ok && typeof token.access_token === "string") {
29136
+ return {
29137
+ accessToken: await mintMuseApiKey(token.access_token)
29138
+ };
29139
+ }
29140
+ if (token.error === "slow_down") {
29141
+ intervalMs += 5e3;
29142
+ continue;
29143
+ }
29144
+ if (token.error !== "authorization_pending") {
29145
+ throw new Error(token.error === "access_denied" ? "Muse sign-in was denied." : `Muse sign-in failed: ${token.error ?? response.status}`);
29146
+ }
29147
+ }
29148
+ throw new Error("Muse sign-in expired before it was approved.");
29149
+ }
29150
+
29151
+ // src/commands/muse-auth.ts
29152
+ async function museAuthCommand(options = {}) {
29153
+ await runCredentialAuthFlow(options, {
29154
+ providerLabel: "Muse",
29155
+ credentialLabel: "Muse Code",
29156
+ connectorLabel: "OAuth",
29157
+ oauthSteps: 1,
29158
+ orgEndpoint: "/v1/muse/credentials",
29159
+ userEndpoint: "/v1/muse/user/credentials",
29160
+ runOAuth: runMuseOAuthFlow,
29161
+ toRequestBody: (tokens) => ({ access_token: tokens.accessToken })
29162
+ });
29163
+ }
29164
+
28945
29165
  // src/commands/init.ts
28946
29166
  var import_chalk13 = __toESM(require("chalk"));
28947
29167
  var import_fs3 = __toESM(require("fs"));
@@ -31507,6 +31727,7 @@ var organizationOptionalCommands = /* @__PURE__ */ new Set([
31507
31727
  "computer",
31508
31728
  "claude-auth",
31509
31729
  "codex-auth",
31730
+ "muse-auth",
31510
31731
  "config",
31511
31732
  "init",
31512
31733
  "login",
@@ -31600,6 +31821,16 @@ program.command("logout").description("Clear stored credentials").action(() => {
31600
31821
  process.exit(1);
31601
31822
  }
31602
31823
  });
31824
+ program.command("muse-auth").description("Connect your Muse Code subscription to Replicas (personal by default)").option("-u, --user", "Store credentials for your personal account (default)").option("-o, --org", "Share credentials with the whole organization (admins only)").option("-y, --yes", "Skip the destination confirmation prompt").action(async (options) => {
31825
+ try {
31826
+ await museAuthCommand(options);
31827
+ } catch (error51) {
31828
+ if (error51 instanceof Error) console.error(import_chalk23.default.red(`
31829
+ \u2717 ${error51.message}
31830
+ `));
31831
+ process.exit(1);
31832
+ }
31833
+ });
31603
31834
  program.command("whoami").description("Display current authenticated user").action(async () => {
31604
31835
  try {
31605
31836
  await whoamiCommand();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "replicas-cli",
3
- "version": "0.2.598",
3
+ "version": "0.2.600",
4
4
  "description": "CLI for managing Replicas workspaces - SSH into cloud dev environments with automatic port forwarding",
5
5
  "main": "dist/index.cjs",
6
6
  "bin": {