replicas-cli 0.2.504 → 0.2.506

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.mjs +156 -73
  2. package/package.json +3 -2
package/dist/index.mjs CHANGED
@@ -7743,6 +7743,71 @@ function getCodingAgentDisplayNames() {
7743
7743
  return VALID_CODING_AGENT_PROVIDERS.map((provider) => getProviderDisplayName(provider)).join(", ");
7744
7744
  }
7745
7745
 
7746
+ // ../shared/src/credentials/types.ts
7747
+ var CREDENTIAL_SCOPE = {
7748
+ USER: "user",
7749
+ ORG: "org"
7750
+ };
7751
+ var CREDENTIAL_SCOPES = Object.values(CREDENTIAL_SCOPE);
7752
+ var CREDENTIAL_SCOPE_PRIORITY = [CREDENTIAL_SCOPE.USER, CREDENTIAL_SCOPE.ORG];
7753
+
7754
+ // ../shared/src/credentials/agents.ts
7755
+ var CREDENTIAL_METHOD = {
7756
+ OAUTH: "oauth",
7757
+ API_KEY: "api_key",
7758
+ FOUNDRY: "foundry",
7759
+ BEDROCK: "bedrock",
7760
+ OPENCODE_GO: "opencode-go",
7761
+ ASTER: "aster",
7762
+ OPENROUTER: "openrouter"
7763
+ };
7764
+ var CREDENTIAL_TYPE = {
7765
+ CLAUDE_OAUTH: "claude",
7766
+ ANTHROPIC_API_KEY: "claude_anthropic_api_key",
7767
+ CLAUDE_FOUNDRY: "claude_foundry",
7768
+ CLAUDE_BEDROCK: "claude_bedrock",
7769
+ CODEX_OAUTH: "codex",
7770
+ OPENAI_API_KEY: "openai_api_key",
7771
+ CODEX_FOUNDRY: "codex_foundry",
7772
+ CURSOR_API_KEY: "cursor_api_key",
7773
+ OPENCODE_GO_API_KEY: "opencode_go_api_key",
7774
+ ASTER_API_KEY: "aster_api_key",
7775
+ OPENROUTER_API_KEY: "openrouter_api_key"
7776
+ };
7777
+ var AGENT_CREDENTIAL_METHODS_IN_ORDER = {
7778
+ [AGENT.CLAUDE]: [
7779
+ { method: CREDENTIAL_METHOD.OAUTH, credentialType: CREDENTIAL_TYPE.CLAUDE_OAUTH },
7780
+ { method: CREDENTIAL_METHOD.API_KEY, credentialType: CREDENTIAL_TYPE.ANTHROPIC_API_KEY },
7781
+ { method: CREDENTIAL_METHOD.FOUNDRY, credentialType: CREDENTIAL_TYPE.CLAUDE_FOUNDRY },
7782
+ { method: CREDENTIAL_METHOD.BEDROCK, credentialType: CREDENTIAL_TYPE.CLAUDE_BEDROCK }
7783
+ ],
7784
+ [AGENT.CODEX]: [
7785
+ { method: CREDENTIAL_METHOD.OAUTH, credentialType: CREDENTIAL_TYPE.CODEX_OAUTH },
7786
+ { method: CREDENTIAL_METHOD.API_KEY, credentialType: CREDENTIAL_TYPE.OPENAI_API_KEY },
7787
+ { method: CREDENTIAL_METHOD.FOUNDRY, credentialType: CREDENTIAL_TYPE.CODEX_FOUNDRY }
7788
+ ],
7789
+ [AGENT.CURSOR]: [
7790
+ { method: CREDENTIAL_METHOD.API_KEY, credentialType: CREDENTIAL_TYPE.CURSOR_API_KEY }
7791
+ ],
7792
+ [AGENT.OPENCODE]: [
7793
+ { method: CREDENTIAL_METHOD.OPENCODE_GO, credentialType: CREDENTIAL_TYPE.OPENCODE_GO_API_KEY },
7794
+ { method: CREDENTIAL_METHOD.ASTER, credentialType: CREDENTIAL_TYPE.ASTER_API_KEY },
7795
+ { method: CREDENTIAL_METHOD.OPENROUTER, credentialType: CREDENTIAL_TYPE.OPENROUTER_API_KEY }
7796
+ ],
7797
+ [AGENT.PI]: [
7798
+ { method: CREDENTIAL_METHOD.ASTER, credentialType: CREDENTIAL_TYPE.ASTER_API_KEY },
7799
+ { method: CREDENTIAL_METHOD.OPENROUTER, credentialType: CREDENTIAL_TYPE.OPENROUTER_API_KEY }
7800
+ ]
7801
+ };
7802
+
7803
+ // ../shared/src/analytics/types.ts
7804
+ function isAuthMethod(value) {
7805
+ return typeof value === "string" && Object.values(CREDENTIAL_METHOD).some((method) => method === value);
7806
+ }
7807
+ function isCredentialScope(value) {
7808
+ return typeof value === "string" && CREDENTIAL_SCOPES.some((scope) => scope === value);
7809
+ }
7810
+
7746
7811
  // ../shared/src/event.ts
7747
7812
  var CLAUDE_PARTIAL_MESSAGE_EVENT_TYPE = "claude-partial-message";
7748
7813
  function coerceClaudePartialMessagePayload(payload) {
@@ -7771,6 +7836,23 @@ var CODEX_ASP_TRANSCRIPT_UPDATED_EVENT_TYPE = "codex-asp-transcript-updated";
7771
7836
  var CODEX_QUOTA_STATUS_EVENT_TYPE = "codex-quota-status";
7772
7837
  var CHAT_INTERRUPTED_EVENT_TYPE = "replicas-interrupted";
7773
7838
  var CHAT_GOAL_EVENT_TYPE = "chat-goal";
7839
+ var AUTH_FALLBACK_EVENT_TYPE = "auth-fallback";
7840
+ function coerceAuthFallbackPayload(payload) {
7841
+ const { provider, reason, exhaustedMethod, exhaustedScope, candidateMethod, candidateScope, status, detail } = payload;
7842
+ if (typeof provider !== "string" || !isValidCodingAgentProvider(provider) || reason !== "rate_limit" && reason !== "out_of_credits" || !isAuthMethod(exhaustedMethod) || !isAuthMethod(candidateMethod) || !isCredentialScope(candidateScope) || status !== "switched" && status !== "failed") {
7843
+ return null;
7844
+ }
7845
+ return {
7846
+ provider,
7847
+ reason,
7848
+ exhaustedMethod,
7849
+ ...isCredentialScope(exhaustedScope) ? { exhaustedScope } : {},
7850
+ candidateMethod,
7851
+ candidateScope,
7852
+ status,
7853
+ ...typeof detail === "string" && detail ? { detail } : {}
7854
+ };
7855
+ }
7774
7856
  var CHAT_GOAL_STATUSES = [
7775
7857
  "active",
7776
7858
  "paused",
@@ -7810,63 +7892,6 @@ function coerceChatGoalPayload(payload) {
7810
7892
  };
7811
7893
  }
7812
7894
 
7813
- // ../shared/src/credentials/types.ts
7814
- var CREDENTIAL_SCOPE = {
7815
- USER: "user",
7816
- ORG: "org"
7817
- };
7818
- var CREDENTIAL_SCOPES = Object.values(CREDENTIAL_SCOPE);
7819
- var CREDENTIAL_SCOPE_PRIORITY = [CREDENTIAL_SCOPE.USER, CREDENTIAL_SCOPE.ORG];
7820
-
7821
- // ../shared/src/credentials/agents.ts
7822
- var CREDENTIAL_METHOD = {
7823
- OAUTH: "oauth",
7824
- API_KEY: "api_key",
7825
- FOUNDRY: "foundry",
7826
- BEDROCK: "bedrock",
7827
- OPENCODE_GO: "opencode-go",
7828
- ASTER: "aster",
7829
- OPENROUTER: "openrouter"
7830
- };
7831
- var CREDENTIAL_TYPE = {
7832
- CLAUDE_OAUTH: "claude",
7833
- ANTHROPIC_API_KEY: "claude_anthropic_api_key",
7834
- CLAUDE_FOUNDRY: "claude_foundry",
7835
- CLAUDE_BEDROCK: "claude_bedrock",
7836
- CODEX_OAUTH: "codex",
7837
- OPENAI_API_KEY: "openai_api_key",
7838
- CODEX_FOUNDRY: "codex_foundry",
7839
- CURSOR_API_KEY: "cursor_api_key",
7840
- OPENCODE_GO_API_KEY: "opencode_go_api_key",
7841
- ASTER_API_KEY: "aster_api_key",
7842
- OPENROUTER_API_KEY: "openrouter_api_key"
7843
- };
7844
- var AGENT_CREDENTIAL_METHODS_IN_ORDER = {
7845
- [AGENT.CLAUDE]: [
7846
- { method: CREDENTIAL_METHOD.OAUTH, credentialType: CREDENTIAL_TYPE.CLAUDE_OAUTH },
7847
- { method: CREDENTIAL_METHOD.API_KEY, credentialType: CREDENTIAL_TYPE.ANTHROPIC_API_KEY },
7848
- { method: CREDENTIAL_METHOD.FOUNDRY, credentialType: CREDENTIAL_TYPE.CLAUDE_FOUNDRY },
7849
- { method: CREDENTIAL_METHOD.BEDROCK, credentialType: CREDENTIAL_TYPE.CLAUDE_BEDROCK }
7850
- ],
7851
- [AGENT.CODEX]: [
7852
- { method: CREDENTIAL_METHOD.OAUTH, credentialType: CREDENTIAL_TYPE.CODEX_OAUTH },
7853
- { method: CREDENTIAL_METHOD.API_KEY, credentialType: CREDENTIAL_TYPE.OPENAI_API_KEY },
7854
- { method: CREDENTIAL_METHOD.FOUNDRY, credentialType: CREDENTIAL_TYPE.CODEX_FOUNDRY }
7855
- ],
7856
- [AGENT.CURSOR]: [
7857
- { method: CREDENTIAL_METHOD.API_KEY, credentialType: CREDENTIAL_TYPE.CURSOR_API_KEY }
7858
- ],
7859
- [AGENT.OPENCODE]: [
7860
- { method: CREDENTIAL_METHOD.OPENCODE_GO, credentialType: CREDENTIAL_TYPE.OPENCODE_GO_API_KEY },
7861
- { method: CREDENTIAL_METHOD.ASTER, credentialType: CREDENTIAL_TYPE.ASTER_API_KEY },
7862
- { method: CREDENTIAL_METHOD.OPENROUTER, credentialType: CREDENTIAL_TYPE.OPENROUTER_API_KEY }
7863
- ],
7864
- [AGENT.PI]: [
7865
- { method: CREDENTIAL_METHOD.ASTER, credentialType: CREDENTIAL_TYPE.ASTER_API_KEY },
7866
- { method: CREDENTIAL_METHOD.OPENROUTER, credentialType: CREDENTIAL_TYPE.OPENROUTER_API_KEY }
7867
- ]
7868
- };
7869
-
7870
7895
  // ../shared/src/aster.ts
7871
7896
  var ASTER_MODELS = [
7872
7897
  "kimi-k3",
@@ -9631,6 +9656,27 @@ const message = await replicas.slack.call<{ channel: string; ts: string }>('chat
9631
9656
  await replicas.slack.attachThread({ channel: message.channel, threadTs: message.ts });
9632
9657
  \`\`\`
9633
9658
 
9659
+ A link in the message text stays plain text, so when the message carries a pull request or merge request link, pass \`blocks\` alongside \`text\` to render a button for it. Keep \`text\` set to the same message \u2014 Slack uses it for notifications and fallback.
9660
+
9661
+ \`\`\`ts
9662
+ await replicas.slack.call('chat.postMessage', {
9663
+ channel: 'C0123ABC',
9664
+ thread_ts: '1234567890.123456',
9665
+ text: summary,
9666
+ blocks: [
9667
+ { type: 'section', text: { type: 'mrkdwn', text: summary } },
9668
+ {
9669
+ type: 'actions',
9670
+ elements: [
9671
+ { type: 'button', text: { type: 'plain_text', text: 'View PR' }, url: prUrl, action_id: 'view_pr' },
9672
+ ],
9673
+ },
9674
+ ],
9675
+ });
9676
+ \`\`\`
9677
+
9678
+ Use "View MR" for GitLab. With several links, give each button a unique \`action_id\` and name its repository in the label ("View PR \xB7 web").
9679
+
9634
9680
  Attach every new top-level conversation so future replies route to this workspace. For a reply in another thread, attach its root \`thread_ts\`, not the reply timestamp. Do not attach the originating thread again.
9635
9681
 
9636
9682
  ## Search and batch
@@ -9697,8 +9743,10 @@ var DEFAULT_USER_PREFERENCES = {
9697
9743
  pr_user_attribution: false,
9698
9744
  auto_draft_prs: false,
9699
9745
  open_prs_in_graphite: false,
9746
+ open_links_in_desktop_app: false,
9700
9747
  default_fast_mode: false,
9701
- agent_defaults: { ...EMPTY_AGENT_DEFAULT_SETTINGS }
9748
+ agent_defaults: { ...EMPTY_AGENT_DEFAULT_SETTINGS },
9749
+ credential_priority: null
9702
9750
  };
9703
9751
  function defaultReplicasAgentAbilities() {
9704
9752
  const abilities = {};
@@ -9763,7 +9811,7 @@ function formatTurnElapsed(ms) {
9763
9811
  }
9764
9812
 
9765
9813
  // ../shared/src/cli-version.ts
9766
- var CLI_VERSION = "0.2.504";
9814
+ var CLI_VERSION = "0.2.506";
9767
9815
 
9768
9816
  // ../shared/src/version.ts
9769
9817
  function compareVersions(v1, v2) {
@@ -25590,7 +25638,7 @@ function normalizeContentBlocks(content) {
25590
25638
  if (typeof content === "string") {
25591
25639
  return content ? [{ type: "text", text: content }] : [];
25592
25640
  }
25593
- return content ?? [];
25641
+ return Array.isArray(content) ? content.filter((block) => isRecord(block) && typeof block.type === "string") : [];
25594
25642
  }
25595
25643
  function parseStringField(value) {
25596
25644
  if (typeof value !== "string") return null;
@@ -26513,21 +26561,24 @@ function parseDisplayMessages(events, agentType, codexAspTranscript, options = {
26513
26561
  const shouldFilter = options.filter ?? true;
26514
26562
  const parsedEvents = agentType === "claude" || agentType === "relay" ? parseClaudeEvents(events, options.parentToolUseId) : parseAgentEvents(events, agentType);
26515
26563
  const legacyMessages = shouldFilter ? filterDisplayMessages(parsedEvents, agentType) : parsedEvents;
26564
+ const finalize2 = (messages) => shouldFilter ? applyAuthFallbackNotices(applyInterruptions(messages, events), events) : messages;
26516
26565
  if (agentType !== "codex" || !codexAspTranscript) {
26517
- return shouldFilter ? applyInterruptions(legacyMessages, events) : legacyMessages;
26566
+ return finalize2(legacyMessages);
26518
26567
  }
26519
26568
  const nativeCodexMessages = shouldFilter ? filterDisplayMessages(parseCodexAspTranscript(codexAspTranscript), agentType) : parseCodexAspTranscript(codexAspTranscript);
26520
- const merged = mergeCodexAspDisplayMessages(nativeCodexMessages, legacyMessages);
26521
- return shouldFilter ? applyInterruptions(merged, events) : merged;
26569
+ return finalize2(mergeCodexAspDisplayMessages(nativeCodexMessages, legacyMessages));
26570
+ }
26571
+ function insertByTimestamp(messages, message) {
26572
+ const messageMs = parseTimestampMs(message.timestamp);
26573
+ let index = messages.length;
26574
+ while (index > 0 && parseTimestampMs(messages[index - 1].timestamp) > messageMs) index--;
26575
+ messages.splice(index, 0, message);
26522
26576
  }
26523
26577
  function applyInterruptions(messages, events) {
26524
26578
  const result = [...messages];
26525
26579
  for (const event of events) {
26526
26580
  if (event.type !== CHAT_INTERRUPTED_EVENT_TYPE) continue;
26527
- const eventMs = parseTimestampMs(event.timestamp);
26528
- let index = result.length;
26529
- while (index > 0 && parseTimestampMs(result[index - 1].timestamp) > eventMs) index--;
26530
- result.splice(index, 0, {
26581
+ insertByTimestamp(result, {
26531
26582
  id: `interruption-${event.timestamp}`,
26532
26583
  type: "interruption",
26533
26584
  timestamp: event.timestamp
@@ -26559,6 +26610,24 @@ function applyInterruptions(messages, events) {
26559
26610
  }
26560
26611
  return finalized;
26561
26612
  }
26613
+ function applyAuthFallbackNotices(messages, events) {
26614
+ const notices = [];
26615
+ events.forEach((event, index) => {
26616
+ if (event.type !== AUTH_FALLBACK_EVENT_TYPE) return;
26617
+ const payload = coerceAuthFallbackPayload(event.payload);
26618
+ if (!payload) return;
26619
+ notices.push({
26620
+ ...payload,
26621
+ id: `auth-fallback-${event.timestamp}-${index}`,
26622
+ type: "auth_fallback",
26623
+ timestamp: event.timestamp
26624
+ });
26625
+ });
26626
+ if (notices.length === 0) return messages;
26627
+ const result = [...messages];
26628
+ for (const notice of notices) insertByTimestamp(result, notice);
26629
+ return result;
26630
+ }
26562
26631
  function isCodexInitializationPrompt(message) {
26563
26632
  return message.type === "user" && removeReplicasInstructions(message.content).trim() === "Hello";
26564
26633
  }
@@ -32407,16 +32476,25 @@ function GitHubPRReviewMessage({ data }) {
32407
32476
  data.commentBody && /* @__PURE__ */ jsx5(MessageBody, { children: data.commentBody })
32408
32477
  ] });
32409
32478
  }
32410
- function GitHubPRGeneralMessage({ data }) {
32479
+ function HostReviewThreadMessage({
32480
+ source,
32481
+ label,
32482
+ identifier,
32483
+ commentUser,
32484
+ commentBody
32485
+ }) {
32411
32486
  return /* @__PURE__ */ jsxs5("box", { flexDirection: "column", gap: 0, children: [
32412
32487
  /* @__PURE__ */ jsxs5("box", { flexDirection: "row", gap: 1, children: [
32413
- /* @__PURE__ */ jsx5(SourceBadge, { source: "github_pr_existing_general" }),
32414
- /* @__PURE__ */ jsx5(MetadataPill, { label: "PR", value: `#${data.prNumber}` }),
32415
- data.commentUser && /* @__PURE__ */ jsx5(MetadataPill, { label: "From", value: `@${data.commentUser}` })
32488
+ /* @__PURE__ */ jsx5(SourceBadge, { source }),
32489
+ /* @__PURE__ */ jsx5(MetadataPill, { label, value: identifier }),
32490
+ commentUser && /* @__PURE__ */ jsx5(MetadataPill, { label: "From", value: `@${commentUser}` })
32416
32491
  ] }),
32417
- /* @__PURE__ */ jsx5(MessageBody, { children: data.commentBody })
32492
+ /* @__PURE__ */ jsx5(MessageBody, { children: commentBody })
32418
32493
  ] });
32419
32494
  }
32495
+ function MergedMessage({ data }) {
32496
+ return /* @__PURE__ */ jsx5("box", { flexDirection: "column", gap: 1, children: data.messages.map((message, index) => message.source === "raw" ? /* @__PURE__ */ jsx5(MessageBody, { children: message.content }, index) : /* @__PURE__ */ jsx5(StructuredUserMessage, { parsed: message }, index)) });
32497
+ }
32420
32498
  function SlackTaskMessage({ data }) {
32421
32499
  const hasDistinctContext = data.threadContext && data.threadContext !== `@${data.latestMessageUser}: ${data.latestMessageText}`;
32422
32500
  return /* @__PURE__ */ jsxs5("box", { flexDirection: "column", gap: 0, children: [
@@ -32470,7 +32548,9 @@ function StructuredUserMessage({ parsed }) {
32470
32548
  case "github_pr_existing_pr_review":
32471
32549
  return /* @__PURE__ */ jsx5(GitHubPRReviewMessage, { data: parsed });
32472
32550
  case "github_pr_existing_general":
32473
- return /* @__PURE__ */ jsx5(GitHubPRGeneralMessage, { data: parsed });
32551
+ return /* @__PURE__ */ jsx5(HostReviewThreadMessage, { source: parsed.source, label: "PR", identifier: `#${parsed.prNumber}`, commentUser: parsed.commentUser, commentBody: parsed.commentBody });
32552
+ case "gitlab_mr_existing_general":
32553
+ return /* @__PURE__ */ jsx5(HostReviewThreadMessage, { source: parsed.source, label: "MR", identifier: `!${parsed.mergeRequestIid}`, commentUser: parsed.commentUser, commentBody: parsed.commentBody });
32474
32554
  case "slack_task":
32475
32555
  return /* @__PURE__ */ jsx5(SlackTaskMessage, { data: parsed });
32476
32556
  case "inline_diff_comments":
@@ -32480,6 +32560,8 @@ function StructuredUserMessage({ parsed }) {
32480
32560
  return /* @__PURE__ */ jsx5("text", { fg: "#cccccc", selectable: true, children: parsed.source === "plan_quote" ? parsed.blocks.map((b) => `> ${b.quotedText}
32481
32561
  ${b.replyText}`).join("\n\n") : `Automation: ${parsed.automationName} (${parsed.triggerType})
32482
32562
  ${parsed.userPrompt}` });
32563
+ case "merged":
32564
+ return /* @__PURE__ */ jsx5(MergedMessage, { data: parsed });
32483
32565
  default: {
32484
32566
  const _exhaustive = parsed;
32485
32567
  throw new Error(`Unhandled prompt source: ${_exhaustive.source}`);
@@ -33028,6 +33110,7 @@ var AUTH_METHOD_LABELS = {
33028
33110
  oauth: "OAuth",
33029
33111
  api_key: "API Key",
33030
33112
  bedrock: "Bedrock",
33113
+ foundry: "Foundry",
33031
33114
  none: null
33032
33115
  };
33033
33116
  function StatusDot({ status }) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "replicas-cli",
3
- "version": "0.2.504",
3
+ "version": "0.2.506",
4
4
  "description": "CLI for managing Replicas workspaces - SSH into cloud dev environments with automatic port forwarding",
5
5
  "main": "dist/index.mjs",
6
6
  "bin": {
@@ -10,7 +10,8 @@
10
10
  "dist"
11
11
  ],
12
12
  "scripts": {
13
- "build": "tsup",
13
+ "build": "bun run typecheck && tsup",
14
+ "typecheck": "tsc --noEmit",
14
15
  "dev": "bun run src/index.ts",
15
16
  "dev-pack": "bun run build && node scripts/pack-dev-tarball.mjs",
16
17
  "start": "bun dist/index.mjs",