replicas-cli 0.2.469 → 0.2.471

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 +81 -37
  2. package/package.json +1 -1
package/dist/index.mjs CHANGED
@@ -9325,7 +9325,7 @@ LENGTH=$(stat -c%s "$FILE" 2>/dev/null || stat -f%z "$FILE")
9325
9325
 
9326
9326
  # 1. Reserve an upload URL + file ID.
9327
9327
  RESERVE=$(curl -s -G "https://slack.com/api/files.getUploadURLExternal" \\
9328
- -H "Authorization: Bearer $SLACK_BOT_TOKEN" \\
9328
+ -H "Authorization: Bearer $REPLICAS_SLACK_BOT_TOKEN" \\
9329
9329
  --data-urlencode "filename=$FILENAME" \\
9330
9330
  --data-urlencode "length=$LENGTH")
9331
9331
  UPLOAD_URL=$(echo "$RESERVE" | jq -r '.upload_url')
@@ -9340,7 +9340,7 @@ curl -s -X POST "$UPLOAD_URL" \\
9340
9340
 
9341
9341
  # 3. Complete the upload, sharing it into the channel/thread with the dashboard link.
9342
9342
  curl -s -X POST "https://slack.com/api/files.completeUploadExternal" \\
9343
- -H "Authorization: Bearer $SLACK_BOT_TOKEN" \\
9343
+ -H "Authorization: Bearer $REPLICAS_SLACK_BOT_TOKEN" \\
9344
9344
  -H "Content-Type: application/json; charset=utf-8" \\
9345
9345
  -d "{
9346
9346
  \\"files\\": [{\\"id\\": \\"$FILE_ID\\", \\"title\\": \\"Screenshot\\"}],
@@ -9851,10 +9851,10 @@ This guide covers how to interact with Slack from within your Replicas workspace
9851
9851
 
9852
9852
  ## Prerequisites
9853
9853
 
9854
- Check if the \`SLACK_BOT_TOKEN\` environment variable is set:
9854
+ Check if the \`REPLICAS_SLACK_BOT_TOKEN\` environment variable is set:
9855
9855
 
9856
9856
  \`\`\`bash
9857
- echo "\${SLACK_BOT_TOKEN:+set}"
9857
+ echo "\${REPLICAS_SLACK_BOT_TOKEN:+set}"
9858
9858
  \`\`\`
9859
9859
 
9860
9860
  - If **set**: Your workspace has Slack access. You can use the Slack Web API as described below.
@@ -9862,7 +9862,7 @@ echo "\${SLACK_BOT_TOKEN:+set}"
9862
9862
 
9863
9863
  ## Using the Slack API
9864
9864
 
9865
- All requests use the \`$SLACK_BOT_TOKEN\` for authentication via the Slack Web API.
9865
+ All requests use the \`$REPLICAS_SLACK_BOT_TOKEN\` for authentication via the Slack Web API.
9866
9866
 
9867
9867
  ### Fetching a Thread from a Slack Link
9868
9868
 
@@ -9873,14 +9873,14 @@ If you encounter a Slack message link (e.g. \`https://team.slack.com/archives/C0
9873
9873
 
9874
9874
  \`\`\`bash
9875
9875
  curl -s "https://slack.com/api/conversations.replies?channel=CHANNEL_ID&ts=THREAD_TS" \\
9876
- -H "Authorization: Bearer $SLACK_BOT_TOKEN"
9876
+ -H "Authorization: Bearer $REPLICAS_SLACK_BOT_TOKEN"
9877
9877
  \`\`\`
9878
9878
 
9879
9879
  ### Sending a Message
9880
9880
 
9881
9881
  \`\`\`bash
9882
9882
  curl -s -X POST "https://slack.com/api/chat.postMessage" \\
9883
- -H "Authorization: Bearer $SLACK_BOT_TOKEN" \\
9883
+ -H "Authorization: Bearer $REPLICAS_SLACK_BOT_TOKEN" \\
9884
9884
  -H "Content-Type: application/json" \\
9885
9885
  -d '{
9886
9886
  "channel": "CHANNEL_ID",
@@ -9919,7 +9919,7 @@ The channel and thread flags default to \`SLACK_CHANNEL_ID\` and \`SLACK_THREAD_
9919
9919
 
9920
9920
  \`\`\`bash
9921
9921
  curl -s "https://slack.com/api/search.messages?query=YOUR_SEARCH_QUERY" \\
9922
- -H "Authorization: Bearer $SLACK_BOT_TOKEN"
9922
+ -H "Authorization: Bearer $REPLICAS_SLACK_BOT_TOKEN"
9923
9923
  \`\`\`
9924
9924
 
9925
9925
  ### Uploading Files
@@ -9933,7 +9933,7 @@ LENGTH=$(stat -c%s "$FILE" 2>/dev/null || stat -f%z "$FILE")
9933
9933
 
9934
9934
  # 1. Reserve an upload URL + file ID.
9935
9935
  RESERVE=$(curl -s -G "https://slack.com/api/files.getUploadURLExternal" \\
9936
- -H "Authorization: Bearer $SLACK_BOT_TOKEN" \\
9936
+ -H "Authorization: Bearer $REPLICAS_SLACK_BOT_TOKEN" \\
9937
9937
  --data-urlencode "filename=$FILENAME" \\
9938
9938
  --data-urlencode "length=$LENGTH")
9939
9939
  UPLOAD_URL=$(echo "$RESERVE" | jq -r '.upload_url')
@@ -9948,7 +9948,7 @@ curl -s -X POST "$UPLOAD_URL" \\
9948
9948
 
9949
9949
  # 3. Complete the upload and share into a channel (and optionally a thread).
9950
9950
  curl -s -X POST "https://slack.com/api/files.completeUploadExternal" \\
9951
- -H "Authorization: Bearer $SLACK_BOT_TOKEN" \\
9951
+ -H "Authorization: Bearer $REPLICAS_SLACK_BOT_TOKEN" \\
9952
9952
  -H "Content-Type: application/json; charset=utf-8" \\
9953
9953
  -d "{
9954
9954
  \\"files\\": [{\\"id\\": \\"$FILE_ID\\", \\"title\\": \\"File title\\"}],
@@ -10084,7 +10084,7 @@ function formatTurnElapsed(ms) {
10084
10084
  }
10085
10085
 
10086
10086
  // ../shared/src/cli-version.ts
10087
- var CLI_VERSION = "0.2.469";
10087
+ var CLI_VERSION = "0.2.471";
10088
10088
 
10089
10089
  // ../shared/src/version.ts
10090
10090
  function compareVersions(v1, v2) {
@@ -25683,8 +25683,9 @@ function parseOpencodeEvents(events) {
25683
25683
  if (event.type === "event_msg" && event.payload.type === "user_message") {
25684
25684
  const message = event.payload.message;
25685
25685
  if (typeof message === "string" && message.trim()) {
25686
+ const messageId = event.payload[USER_MESSAGE_ID_PAYLOAD_KEY];
25686
25687
  messages.push({
25687
- id: `opencode-user-${event.timestamp}-${messages.length}`,
25688
+ id: typeof messageId === "string" ? messageId : `opencode-user-${event.timestamp}`,
25688
25689
  type: "user",
25689
25690
  content: message,
25690
25691
  timestamp: event.timestamp
@@ -25696,7 +25697,7 @@ function parseOpencodeEvents(events) {
25696
25697
  const error51 = assistantError(event.payload.info);
25697
25698
  if (error51) {
25698
25699
  messages.push({
25699
- id: `opencode-error-${event.timestamp}-${messages.length}`,
25700
+ id: `opencode-${event.type}-${event.timestamp}`,
25700
25701
  type: "error",
25701
25702
  message: error51,
25702
25703
  timestamp: event.timestamp
@@ -25707,7 +25708,7 @@ function parseOpencodeEvents(events) {
25707
25708
  if (event.type === "opencode-error") {
25708
25709
  const message = typeof event.payload.message === "string" ? event.payload.message : "Opencode run failed";
25709
25710
  messages.push({
25710
- id: `opencode-error-${event.timestamp}-${messages.length}`,
25711
+ id: `opencode-${event.type}-${event.timestamp}`,
25711
25712
  type: "error",
25712
25713
  message,
25713
25714
  timestamp: event.timestamp
@@ -25718,7 +25719,7 @@ function parseOpencodeEvents(events) {
25718
25719
  const tool = typeof event.payload.tool === "string" ? event.payload.tool : "tool";
25719
25720
  const input = event.payload.input ?? event.payload.arguments;
25720
25721
  const callId = typeof event.payload.callID === "string" ? event.payload.callID : null;
25721
- const id2 = callId ? `opencode-${callId}` : `opencode-${event.timestamp}-${messages.length}`;
25722
+ const id2 = callId ? `opencode-${callId}` : `opencode-${event.type}-${event.timestamp}`;
25722
25723
  upsertDisplayMessage(messages, createCallDisplayMessage({
25723
25724
  id: id2,
25724
25725
  server: "opencode",
@@ -25731,7 +25732,7 @@ function parseOpencodeEvents(events) {
25731
25732
  }
25732
25733
  const part = partFromEvent(event);
25733
25734
  if (!part) continue;
25734
- let id = `opencode-${event.timestamp}-${messages.length}`;
25735
+ let id = `opencode-${event.type}-${event.timestamp}`;
25735
25736
  if (typeof part.callID === "string") id = `opencode-${part.callID}`;
25736
25737
  else if (typeof part.id === "string") id = `opencode-${part.id}`;
25737
25738
  const time3 = isRecord(part.time) ? part.time : null;
@@ -26673,38 +26674,81 @@ function stableString(value) {
26673
26674
  return String(value);
26674
26675
  }
26675
26676
  }
26676
- function duplicateMessage(a, b) {
26677
- if (a.id === b.id) return true;
26678
- if (a.type !== b.type || !nearTimestamp(a.timestamp, b.timestamp)) {
26679
- return false;
26677
+ function duplicateKey(message) {
26678
+ if (message.type === "user" || message.type === "agent" || message.type === "reasoning") {
26679
+ return JSON.stringify([message.type, message.content]);
26680
26680
  }
26681
- if (a.type === "user" && b.type === "user") return a.content === b.content;
26682
- if (a.type === "agent" && b.type === "agent") return a.content === b.content;
26683
- if (a.type === "reasoning" && b.type === "reasoning") return a.content === b.content;
26684
- if (a.type === "command" && b.type === "command") return a.command === b.command;
26685
- if (a.type === "web_search" && b.type === "web_search") return a.query === b.query;
26686
- if (a.type === "subagent" && b.type === "subagent") {
26687
- return a.description === b.description && a.prompt === b.prompt && a.subagentType === b.subagentType && a.model === b.model;
26681
+ if (message.type === "command") return JSON.stringify([message.type, message.command]);
26682
+ if (message.type === "web_search") return JSON.stringify([message.type, message.query]);
26683
+ if (message.type === "subagent") {
26684
+ return JSON.stringify([
26685
+ message.type,
26686
+ message.description,
26687
+ message.prompt,
26688
+ message.subagentType,
26689
+ message.model
26690
+ ]);
26688
26691
  }
26689
- if (a.type === "todo_list" && b.type === "todo_list") {
26690
- return stableString(a.items) === stableString(b.items);
26692
+ if (message.type === "todo_list") {
26693
+ return JSON.stringify([message.type, stableString(message.items)]);
26691
26694
  }
26692
- if (a.type === "patch" && b.type === "patch") {
26693
- return stableString(a.operations) === stableString(b.operations);
26695
+ if (message.type === "patch") {
26696
+ return JSON.stringify([message.type, stableString(message.operations)]);
26694
26697
  }
26695
- if (a.type === "tool_call" && b.type === "tool_call") {
26696
- return a.server === b.server && a.tool === b.tool && stableString(a.input) === stableString(b.input);
26698
+ if (message.type === "tool_call") {
26699
+ return JSON.stringify([
26700
+ message.type,
26701
+ message.server,
26702
+ message.tool,
26703
+ stableString(message.input)
26704
+ ]);
26697
26705
  }
26698
- return false;
26706
+ return null;
26707
+ }
26708
+ function duplicateBucketKey(message, bucketOffset = 0) {
26709
+ const key = duplicateKey(message);
26710
+ if (key === null) return null;
26711
+ const bucket = Math.floor(parseTimestampMs(message.timestamp) / DUPLICATE_WINDOW_MS) + bucketOffset;
26712
+ return JSON.stringify([bucket, key]);
26699
26713
  }
26700
26714
  function mergeCodexAspDisplayMessages(primary, supplemental) {
26701
26715
  const merged = [...primary];
26716
+ const firstIndexById = /* @__PURE__ */ new Map();
26717
+ const indexesByDuplicateBucket = /* @__PURE__ */ new Map();
26718
+ const indexMessage = (message, index) => {
26719
+ if (!firstIndexById.has(message.id)) firstIndexById.set(message.id, index);
26720
+ const key = duplicateBucketKey(message);
26721
+ if (key === null) return;
26722
+ const indexes = indexesByDuplicateBucket.get(key) ?? /* @__PURE__ */ new Set();
26723
+ indexes.add(index);
26724
+ indexesByDuplicateBucket.set(key, indexes);
26725
+ };
26726
+ const unindexMessage = (message, index) => {
26727
+ const key = duplicateBucketKey(message);
26728
+ if (key === null) return;
26729
+ const indexes = indexesByDuplicateBucket.get(key);
26730
+ indexes?.delete(index);
26731
+ if (indexes?.size === 0) indexesByDuplicateBucket.delete(key);
26732
+ };
26733
+ merged.forEach(indexMessage);
26702
26734
  for (const message of supplemental) {
26703
- const duplicateIndex = merged.findIndex((existing) => duplicateMessage(existing, message));
26704
- if (duplicateIndex === -1) {
26705
- merged.push(message);
26735
+ let duplicateIndex = firstIndexById.get(message.id);
26736
+ if (duplicateIndex === void 0) {
26737
+ for (let bucketOffset = -1; bucketOffset <= 1; bucketOffset += 1) {
26738
+ const key = duplicateBucketKey(message, bucketOffset);
26739
+ for (const index of (key === null ? void 0 : indexesByDuplicateBucket.get(key)) ?? []) {
26740
+ if (nearTimestamp(merged[index].timestamp, message.timestamp) && (duplicateIndex === void 0 || index < duplicateIndex)) {
26741
+ duplicateIndex = index;
26742
+ }
26743
+ }
26744
+ }
26745
+ }
26746
+ if (duplicateIndex === void 0) {
26747
+ indexMessage(message, merged.push(message) - 1);
26706
26748
  } else if (message.type === "user") {
26749
+ unindexMessage(merged[duplicateIndex], duplicateIndex);
26707
26750
  merged[duplicateIndex] = { ...merged[duplicateIndex], timestamp: message.timestamp };
26751
+ indexMessage(merged[duplicateIndex], duplicateIndex);
26708
26752
  }
26709
26753
  }
26710
26754
  return merged.map((message, index) => ({ message, index })).sort((a, b) => parseTimestampMs(a.message.timestamp) - parseTimestampMs(b.message.timestamp) || a.index - b.index).map(({ message }) => message);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "replicas-cli",
3
- "version": "0.2.469",
3
+ "version": "0.2.471",
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": {