replicas-cli 0.2.727 → 0.2.729
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/README.md +1 -1
- package/dist/index.cjs +51 -244
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -45,7 +45,7 @@ Connect to a workspace via SSH.
|
|
|
45
45
|
Open a workspace in VS Code via Remote SSH. Omit the argument to pick a workspace with the arrow keys and Enter, or pass a name or ID. Names with spaces work with or without quotes.
|
|
46
46
|
|
|
47
47
|
### Coding agents
|
|
48
|
-
Use `replicas claude-auth` or `replicas codex-auth` to connect subscription credentials.
|
|
48
|
+
Use `replicas claude-auth` or `replicas codex-auth` to connect subscription credentials. Cursor uses API keys configured in Coding Agents settings.
|
|
49
49
|
|
|
50
50
|
## Configuration
|
|
51
51
|
|
package/dist/index.cjs
CHANGED
|
@@ -7701,9 +7701,7 @@ var AGENT = {
|
|
|
7701
7701
|
CLAUDE: "claude",
|
|
7702
7702
|
CODEX: "codex",
|
|
7703
7703
|
CURSOR: "cursor",
|
|
7704
|
-
DEEPSEEK: "deepseek",
|
|
7705
7704
|
FX: "fx",
|
|
7706
|
-
GEMINI: "gemini",
|
|
7707
7705
|
KIMI: "kimi",
|
|
7708
7706
|
MUSE: "muse",
|
|
7709
7707
|
OPENCODE: "opencode",
|
|
@@ -7715,7 +7713,6 @@ var VALID_RELAY_SUBAGENT_PROVIDERS = VALID_AGENT_PROVIDERS;
|
|
|
7715
7713
|
var VALID_RELAY_BASE_PROVIDERS = [
|
|
7716
7714
|
AGENT.CLAUDE,
|
|
7717
7715
|
AGENT.CODEX,
|
|
7718
|
-
AGENT.DEEPSEEK,
|
|
7719
7716
|
AGENT.OPENCODE,
|
|
7720
7717
|
AGENT.PI
|
|
7721
7718
|
];
|
|
@@ -7748,21 +7745,11 @@ var AGENT_PROVIDER_OPTIONS = [
|
|
|
7748
7745
|
label: "Cursor",
|
|
7749
7746
|
description: "Use Cursor for tasks"
|
|
7750
7747
|
},
|
|
7751
|
-
{
|
|
7752
|
-
value: "deepseek",
|
|
7753
|
-
label: "DeepSeek Harness",
|
|
7754
|
-
description: "Use DeepSeek Harness for tasks"
|
|
7755
|
-
},
|
|
7756
7748
|
{
|
|
7757
7749
|
value: "fx",
|
|
7758
7750
|
label: "fx",
|
|
7759
7751
|
description: "Use fx for tasks"
|
|
7760
7752
|
},
|
|
7761
|
-
{
|
|
7762
|
-
value: "gemini",
|
|
7763
|
-
label: "Gemini CLI",
|
|
7764
|
-
description: "Use Gemini CLI for tasks"
|
|
7765
|
-
},
|
|
7766
7753
|
{
|
|
7767
7754
|
value: "kimi",
|
|
7768
7755
|
label: "Kimi Code",
|
|
@@ -7795,9 +7782,7 @@ var THINKING_LEVELS_BY_AGENT = {
|
|
|
7795
7782
|
claude: [...STANDARD_THINKING_LEVELS, "ultracode"],
|
|
7796
7783
|
codex: [...STANDARD_THINKING_LEVELS, "ultra"],
|
|
7797
7784
|
cursor: STANDARD_THINKING_LEVELS,
|
|
7798
|
-
deepseek: STANDARD_THINKING_LEVELS,
|
|
7799
7785
|
fx: STANDARD_THINKING_LEVELS,
|
|
7800
|
-
gemini: STANDARD_THINKING_LEVELS,
|
|
7801
7786
|
kimi: STANDARD_THINKING_LEVELS,
|
|
7802
7787
|
muse: VALID_THINKING_LEVELS.filter((level) => level !== "max" && level !== "ultracode"),
|
|
7803
7788
|
opencode: STANDARD_THINKING_LEVELS,
|
|
@@ -7819,12 +7804,8 @@ function getProviderDisplayName(provider, variant = "short") {
|
|
|
7819
7804
|
return "Codex";
|
|
7820
7805
|
case "cursor":
|
|
7821
7806
|
return "Cursor";
|
|
7822
|
-
case "deepseek":
|
|
7823
|
-
return variant === "long" ? "DeepSeek Harness" : "DeepSeek";
|
|
7824
7807
|
case "fx":
|
|
7825
7808
|
return "fx";
|
|
7826
|
-
case "gemini":
|
|
7827
|
-
return "Gemini";
|
|
7828
7809
|
case "kimi":
|
|
7829
7810
|
return variant === "long" ? "Kimi Code" : "Kimi";
|
|
7830
7811
|
case "muse":
|
|
@@ -7880,7 +7861,6 @@ var CREDENTIAL_TYPE = {
|
|
|
7880
7861
|
ASTER_API_KEY: "aster_api_key",
|
|
7881
7862
|
OPENROUTER_API_KEY: "openrouter_api_key",
|
|
7882
7863
|
AI_GATEWAY_API_KEY: "ai_gateway_api_key",
|
|
7883
|
-
GEMINI_API_KEY: "gemini_api_key",
|
|
7884
7864
|
MUSE_OAUTH: "muse_oauth",
|
|
7885
7865
|
MUSE_API_KEY: "muse_api_key"
|
|
7886
7866
|
};
|
|
@@ -7908,16 +7888,9 @@ var AGENT_CREDENTIAL_METHODS_IN_ORDER = {
|
|
|
7908
7888
|
[AGENT.CURSOR]: [
|
|
7909
7889
|
{ method: CREDENTIAL_METHOD.API_KEY, credentialType: CREDENTIAL_TYPE.CURSOR_API_KEY }
|
|
7910
7890
|
],
|
|
7911
|
-
[AGENT.DEEPSEEK]: [
|
|
7912
|
-
{ method: CREDENTIAL_METHOD.OPENROUTER, credentialType: CREDENTIAL_TYPE.OPENROUTER_API_KEY },
|
|
7913
|
-
{ method: CREDENTIAL_METHOD.OLLAMA, credentialType: CREDENTIAL_TYPE.OLLAMA }
|
|
7914
|
-
],
|
|
7915
7891
|
[AGENT.FX]: [
|
|
7916
7892
|
{ method: CREDENTIAL_METHOD.AI_GATEWAY, credentialType: CREDENTIAL_TYPE.AI_GATEWAY_API_KEY }
|
|
7917
7893
|
],
|
|
7918
|
-
[AGENT.GEMINI]: [
|
|
7919
|
-
{ method: CREDENTIAL_METHOD.API_KEY, credentialType: CREDENTIAL_TYPE.GEMINI_API_KEY }
|
|
7920
|
-
],
|
|
7921
7894
|
[AGENT.KIMI]: [
|
|
7922
7895
|
{ method: CREDENTIAL_METHOD.AI_GATEWAY, credentialType: CREDENTIAL_TYPE.AI_GATEWAY_API_KEY },
|
|
7923
7896
|
{ method: CREDENTIAL_METHOD.OLLAMA, credentialType: CREDENTIAL_TYPE.OLLAMA }
|
|
@@ -22540,10 +22513,15 @@ var TEAM_PLAN = PLANS.team;
|
|
|
22540
22513
|
var ENTERPRISE_PLAN = PLANS.enterprise;
|
|
22541
22514
|
|
|
22542
22515
|
// ../shared/src/analytics/types.ts
|
|
22516
|
+
var credentialAccountSchema = external_exports.object({
|
|
22517
|
+
ownerName: external_exports.string().optional(),
|
|
22518
|
+
email: external_exports.string().optional()
|
|
22519
|
+
});
|
|
22543
22520
|
var agentCredentialSnapshotSchema = external_exports.object({
|
|
22544
22521
|
method: external_exports.enum(CREDENTIAL_METHOD),
|
|
22545
22522
|
scope: external_exports.enum(CREDENTIAL_SCOPE),
|
|
22546
|
-
revision: external_exports.string().optional()
|
|
22523
|
+
revision: external_exports.string().optional(),
|
|
22524
|
+
account: credentialAccountSchema.optional()
|
|
22547
22525
|
});
|
|
22548
22526
|
function isAuthMethod(value) {
|
|
22549
22527
|
return typeof value === "string" && Object.values(CREDENTIAL_METHOD).some((method) => method === value);
|
|
@@ -22555,7 +22533,7 @@ function isCredentialScope(value) {
|
|
|
22555
22533
|
// ../shared/src/workspace-credentials.ts
|
|
22556
22534
|
var WORKSPACE_CREDENTIAL_PROVIDERS = ["claude", "codex"];
|
|
22557
22535
|
var workspaceCredentialProviderSchema = external_exports.enum(WORKSPACE_CREDENTIAL_PROVIDERS);
|
|
22558
|
-
var workspaceCredentialSelectionSchema = agentCredentialSnapshotSchema.omit({ revision: true });
|
|
22536
|
+
var workspaceCredentialSelectionSchema = agentCredentialSnapshotSchema.omit({ revision: true, account: true });
|
|
22559
22537
|
var createWorkspaceCredentialSchema = workspaceCredentialSelectionSchema.extend({
|
|
22560
22538
|
provider: external_exports.enum(VALID_CODING_AGENT_PROVIDERS)
|
|
22561
22539
|
}).refine(({ provider, method }) => agentCredentialMethods(provider).includes(method), {
|
|
@@ -22645,7 +22623,6 @@ var OX_ALPHA_MODEL = "stealth/ox-alpha";
|
|
|
22645
22623
|
var DEEPSEEK_V4_PRO_MODEL = "deepseek/deepseek-v4-pro-0813";
|
|
22646
22624
|
var DEEPSEEK_V4_FLASH_MODEL = "deepseek/deepseek-v4-flash-0731";
|
|
22647
22625
|
var DEFAULT_FX_MODEL = "zai/glm-5.2";
|
|
22648
|
-
var DEFAULT_GEMINI_MODEL = "gemini-3.8-flash";
|
|
22649
22626
|
var DEFAULT_KIMI_MODEL = "moonshotai/kimi-k2.6";
|
|
22650
22627
|
var MUSE_SPARK_1_3_MODEL = "muse-spark-1.3";
|
|
22651
22628
|
var DEFAULT_MUSE_MODEL = "muse-spark-1.2";
|
|
@@ -22666,12 +22643,6 @@ var OPENROUTER_MODELS = [
|
|
|
22666
22643
|
"xiaomi/mimo-v2.5-pro",
|
|
22667
22644
|
"meta/muse-spark-1.3"
|
|
22668
22645
|
];
|
|
22669
|
-
function prioritizeDeepseekModels(models) {
|
|
22670
|
-
return [
|
|
22671
|
-
...models.filter((model) => model.startsWith("deepseek/")),
|
|
22672
|
-
...models.filter((model) => !model.startsWith("deepseek/"))
|
|
22673
|
-
];
|
|
22674
|
-
}
|
|
22675
22646
|
function normalizeClaudeModel(model) {
|
|
22676
22647
|
if (model === "opus" || model === CLAUDE_OPUS_1M_MODEL || model === LEGACY_CLAUDE_OPUS_1M_MODEL) {
|
|
22677
22648
|
return DEFAULT_CLAUDE_MODEL;
|
|
@@ -22751,9 +22722,7 @@ var AGENT_MODELS = {
|
|
|
22751
22722
|
CLAUDE_HAIKU_4_5_MODEL,
|
|
22752
22723
|
"kimi-k2.5"
|
|
22753
22724
|
],
|
|
22754
|
-
deepseek: prioritizeDeepseekModels(DEFAULT_OPENROUTER_MODELS),
|
|
22755
22725
|
fx: [DEFAULT_FX_MODEL],
|
|
22756
|
-
gemini: [DEFAULT_GEMINI_MODEL, "gemini-3.1-pro-preview"],
|
|
22757
22726
|
kimi: [DEFAULT_KIMI_MODEL],
|
|
22758
22727
|
muse: [MUSE_SPARK_1_3_MODEL, DEFAULT_MUSE_MODEL],
|
|
22759
22728
|
opencode: [...DEFAULT_OPENROUTER_MODELS, ...ASTER_MODELS],
|
|
@@ -22811,8 +22780,6 @@ var MODEL_LABELS = {
|
|
|
22811
22780
|
"xiaomi/mimo-v2.5-pro": "MiMo V2.5 Pro via OpenRouter",
|
|
22812
22781
|
"moonshotai/kimi-k2.6": "Kimi K2.6 via OpenRouter",
|
|
22813
22782
|
"moonshotai/kimi-k3": "Kimi K3 via OpenRouter",
|
|
22814
|
-
"gemini-3-flash-preview": "Gemini 3 Flash Preview",
|
|
22815
|
-
"gemini-3.1-pro-preview": "Gemini 3.1 Pro Preview",
|
|
22816
22783
|
[MUSE_SPARK_1_3_MODEL]: "Muse Spark 1.3",
|
|
22817
22784
|
[DEFAULT_MUSE_MODEL]: "Muse Spark 1.2",
|
|
22818
22785
|
"meta/muse-spark-1.3": "Muse Spark 1.3 via OpenRouter",
|
|
@@ -22954,6 +22921,8 @@ var CHAT_INTERRUPTED_EVENT_TYPE = "replicas-interrupted";
|
|
|
22954
22921
|
var AUTH_FALLBACK_EVENT_TYPE = "auth-fallback";
|
|
22955
22922
|
function coerceAuthFallbackPayload(payload) {
|
|
22956
22923
|
const { provider, reason, exhaustedMethod, exhaustedScope, candidateMethod, candidateScope, status, detail } = payload;
|
|
22924
|
+
const exhaustedAccount = credentialAccountSchema.safeParse(payload.exhaustedAccount).data;
|
|
22925
|
+
const candidateAccount = credentialAccountSchema.safeParse(payload.candidateAccount).data;
|
|
22957
22926
|
if (typeof provider !== "string" || !isValidCodingAgentProvider(provider) || reason !== "rate_limit" && reason !== "out_of_credits" || !isAuthMethod(exhaustedMethod) || !isAuthMethod(candidateMethod) || !isCredentialScope(candidateScope) || status !== "switched" && status !== "failed") {
|
|
22958
22927
|
return null;
|
|
22959
22928
|
}
|
|
@@ -22962,8 +22931,10 @@ function coerceAuthFallbackPayload(payload) {
|
|
|
22962
22931
|
reason,
|
|
22963
22932
|
exhaustedMethod,
|
|
22964
22933
|
...isCredentialScope(exhaustedScope) ? { exhaustedScope } : {},
|
|
22934
|
+
...exhaustedAccount ? { exhaustedAccount } : {},
|
|
22965
22935
|
candidateMethod,
|
|
22966
22936
|
candidateScope,
|
|
22937
|
+
...candidateAccount ? { candidateAccount } : {},
|
|
22967
22938
|
status,
|
|
22968
22939
|
...typeof detail === "string" && detail ? { detail } : {}
|
|
22969
22940
|
};
|
|
@@ -23774,7 +23745,7 @@ gh pr review 123 --request-changes --body "Changes needed"
|
|
|
23774
23745
|
|
|
23775
23746
|
## Media in GitHub workflows
|
|
23776
23747
|
|
|
23777
|
-
Media delivery is owned by \`references/MEDIA.md\`. Read its GitHub section before adding screenshots, recordings, diagrams, or HTML reports to a pull request, issue, review comment, or commit; it covers public
|
|
23748
|
+
Media delivery is owned by \`references/MEDIA.md\`. Read its GitHub section before adding screenshots, recordings, diagrams, or HTML reports to a pull request, issue, review comment, or commit; it covers the public links every image upload prints, recording previews, organization-only HTML links, and the required **View in Replicas** link.
|
|
23778
23749
|
`;
|
|
23779
23750
|
var GITHUB_ABILITY = {
|
|
23780
23751
|
label: "GitHub",
|
|
@@ -23985,11 +23956,11 @@ If none of these apply, don't upload.
|
|
|
23985
23956
|
|
|
23986
23957
|
\`replicas media upload\` is always the first delivery action. When the current task has an external destination, every other delivery step follows only after that command succeeds. For every file:
|
|
23987
23958
|
|
|
23988
|
-
1. First, run \`replicas media upload\` with the original file. Do not begin any destination upload until the command succeeds. This creates the canonical dashboard copy and prints
|
|
23959
|
+
1. First, run \`replicas media upload\` with the original file. Do not begin any destination upload until the command succeeds. This creates the canonical dashboard copy and prints an embed plus a per-file dashboard link. Every image gets a public link, so its printed embed works in chat and on GitHub.
|
|
23989
23960
|
2. Include the printed embed line in the Replicas chat reply, followed by **View in Canvas** using the matching per-file dashboard URL. HTML uses its printed page link instead of an image embed.
|
|
23990
|
-
3. Identify every destination in the task and use its inline representation from the table below. Slack, Linear, and GitLab require an upload of the same original bytes; GitHub uses the public
|
|
23961
|
+
3. Identify every destination in the task and use its inline representation from the table below. Slack, Linear, and GitLab require an upload of the same original bytes; GitHub uses the image's printed public embed.
|
|
23991
23962
|
4. Put the **View in Replicas** dashboard link next to the destination embed as a secondary link.
|
|
23992
|
-
5. Check each destination response. If its upload or
|
|
23963
|
+
5. Check each destination response. If its upload or public link fails, say so explicitly and keep the dashboard link; never claim that a dashboard link is an inline embed.
|
|
23993
23964
|
|
|
23994
23965
|
| Destination | Required file delivery | Inline result |
|
|
23995
23966
|
|---|---|---|
|
|
@@ -23997,7 +23968,7 @@ If none of these apply, don't upload.
|
|
|
23997
23968
|
| Slack | \`files.getUploadURLExternal\` \u2192 raw-byte POST \u2192 \`files.completeUploadExternal\` | Uploaded file in the channel or thread |
|
|
23998
23969
|
| Linear | \`fileUpload\` mutation \u2192 presigned upload \u2192 issue/comment mutation | Returned \`assetUrl\` in Markdown |
|
|
23999
23970
|
| GitLab | Project \`/uploads\` endpoint with the original bytes | Returned GitLab Markdown |
|
|
24000
|
-
| GitHub |
|
|
23971
|
+
| GitHub | Printed public embed for an image or recording poster | Printed embed, linked to the recording when needed |
|
|
24001
23972
|
|
|
24002
23973
|
The dashboard link is the subtitle and jump-back path. It is never a substitute for the destination embed.
|
|
24003
23974
|
|
|
@@ -24027,8 +23998,8 @@ Names are normalized to hyphen-case (spaces become hyphens, e.g. \`Login page\`
|
|
|
24027
23998
|
|
|
24028
23999
|
For each media file, the CLI prints an embed line and a dashboard link:
|
|
24029
24000
|
|
|
24030
|
-
1.
|
|
24031
|
-
2.
|
|
24001
|
+
1. Images always print \`\`. This public, stable link works in Replicas chat, GitHub, and anywhere else Markdown images render. No flag is needed.
|
|
24002
|
+
2. Video and audio print \`Replicas chat embed: \` by default; this authenticated URL renders inline in Replicas chat **only** \u2014 see below. \`--access public\` prints a public embed instead.
|
|
24032
24003
|
3. \`View in Replicas: <deep-link>\` is a per-file dashboard URL of the form \`https://app.replicas.dev/workspaces/<workspace-id>?media=<media-id>\` that opens directly to that specific file.
|
|
24033
24004
|
|
|
24034
24005
|
Match each "View in Replicas" line to the embed line directly above it \u2014 that's the deep link for that file.
|
|
@@ -24043,13 +24014,13 @@ replicas media upload recap.html --name "Visual recap" --access organization
|
|
|
24043
24014
|
|
|
24044
24015
|
The printed \`Forge link (organization only)\` opens a dedicated page. Signed-in organization members go straight to it; signed-out members sign in and return to the page.
|
|
24045
24016
|
|
|
24046
|
-
|
|
24017
|
+
Video and audio stay private unless they must play without Replicas sign-in; then pass \`--access public\` (alias \`--share\`):
|
|
24047
24018
|
|
|
24048
24019
|
\`\`\`bash
|
|
24049
|
-
replicas media upload
|
|
24020
|
+
replicas media upload demo.mp4 --name "Checkout demo" --access public
|
|
24050
24021
|
\`\`\`
|
|
24051
24022
|
|
|
24052
|
-
|
|
24023
|
+
Public links are unguessable bearer URLs: anyone with the link can view the file until it is rotated or revoked. HTML pages only support organization access. Reuse the link printed at upload. \`replicas media share <media-id>\` issues a new link and breaks the old one everywhere it is embedded, and \`replicas media revoke <media-id>\` removes public access.
|
|
24053
24024
|
|
|
24054
24025
|
Permanently delete an upload with \`replicas media delete <media-id>\`. The backend only permits deletion when the media belongs to the current workspace; media from another workspace returns not found.
|
|
24055
24026
|
|
|
@@ -24057,14 +24028,14 @@ Permanently delete an upload with \`replicas media delete <media-id>\`. The back
|
|
|
24057
24028
|
|
|
24058
24029
|
| URL | What it is | Where it's allowed |
|
|
24059
24030
|
|---|---|---|
|
|
24060
|
-
| \`https://api.replicas.dev/v1/media/<id>\` (inside \`\`) | Authenticated API redirect
|
|
24031
|
+
| \`https://api.replicas.dev/v1/media/<id>\` (inside \`\`) | Authenticated API redirect printed for private video, audio, and HTML \u2014 requires the Replicas chat session | **Only** in the Replicas chat reply. Nowhere else. |
|
|
24061
24032
|
| \`https://replicas.dev/organizations/<organization-id>/media/<media-id>\` | Organization-only page printed by \`--access organization\` | Pull requests and other places where every viewer belongs to the Replicas organization. |
|
|
24062
|
-
| \`https://api.replicas.dev/v1/media/public/<id>/<token>\` |
|
|
24033
|
+
| \`https://api.replicas.dev/v1/media/public/<id>/<token>\` | Public bearer URL printed for every image, and for video or audio with \`--access public\` | The Replicas chat reply and GitHub embeds. |
|
|
24063
24034
|
| \`https://app.replicas.dev/workspaces/<workspace-id>?media=<media-id>\` | Authenticated dashboard deep link that opens the media file in the workspace | Everywhere external: Slack, GitHub, GitLab, Linear, PR bodies, comments, emails. |
|
|
24064
24035
|
|
|
24065
24036
|
### NEVER link the API redirect URL outside the Replicas chat reply
|
|
24066
24037
|
|
|
24067
|
-
The \`api.replicas.dev/v1/media/<id>\` URL is **not public**. It's an authenticated redirect that only resolves to a presigned download when the Replicas chat session token is present. Anywhere else (Slack, Linear, GitHub, a browser tab the user opens directly, a customer copy-pasting from chat) it returns \`{"error":"Missing authorization token"}\` and renders as a broken image.
|
|
24038
|
+
The \`api.replicas.dev/v1/media/<id>\` URL is **not public**. Image uploads never print it; if you have one for an image from an older upload, run \`replicas media share <media-id>\` to get a public link. It's an authenticated redirect that only resolves to a presigned download when the Replicas chat session token is present. Anywhere else (Slack, Linear, GitHub, a browser tab the user opens directly, a customer copy-pasting from chat) it returns \`{"error":"Missing authorization token"}\` and renders as a broken image.
|
|
24068
24039
|
|
|
24069
24040
|
This rule has no exceptions:
|
|
24070
24041
|
- \u274C Never paste it in a Slack message \u2014 upload the actual bytes via the 3-step \`files.getUploadURLExternal\` \u2192 POST bytes \u2192 \`files.completeUploadExternal\` flow instead (see below).
|
|
@@ -24098,12 +24069,12 @@ After (or alongside) the embeds, include a \`[View in Canvas](<deep-link>)\` hyp
|
|
|
24098
24069
|
|
|
24099
24070
|
After \`replicas media upload\` succeeds, external delivery has two required follow-up steps for every file:
|
|
24100
24071
|
|
|
24101
|
-
1. **Use the destination's inline representation:** upload the raw bytes to Slack, Linear, or GitLab; embed
|
|
24072
|
+
1. **Use the destination's inline representation:** upload the raw bytes to Slack, Linear, or GitLab; embed the image's printed public link on GitHub.
|
|
24102
24073
|
2. **Link the Replicas dashboard deep link** (\`?media=<id>\` form) so the user can jump straight to the file in the workspace.
|
|
24103
24074
|
|
|
24104
24075
|
A dashboard link alone is not enough. An embed without the dashboard link is not enough. Do both.
|
|
24105
24076
|
|
|
24106
|
-
Slack, Linear, and GitLab receive the original bytes through their native upload APIs. GitHub uses
|
|
24077
|
+
Slack, Linear, and GitLab receive the original bytes through their native upload APIs. GitHub uses the printed public link for screenshots and recording previews.
|
|
24107
24078
|
|
|
24108
24079
|
### Slack \u2014 embed natively via the 3-step external file upload flow
|
|
24109
24080
|
|
|
@@ -24204,19 +24175,17 @@ The same flow works for issue bodies (use \`issueCreate\` / \`issueUpdate\` with
|
|
|
24204
24175
|
|
|
24205
24176
|
Never paste the \`api.replicas.dev/v1/media/<id>\` URL into a Linear body or comment \u2014 it will render as a broken image to anyone outside your Replicas chat.
|
|
24206
24177
|
|
|
24207
|
-
### GitHub: inline images and recording previews
|
|
24208
|
-
|
|
24209
|
-
Replicas authenticates GitHub with GitHub App tokens, which native GitHub CLI attachment uploads do not support. Do not use \`gh --attach\` for media. Use a public Forge share for images in PR descriptions, issues, and comments.
|
|
24178
|
+
### GitHub: inline images and recording previews
|
|
24210
24179
|
|
|
24211
|
-
|
|
24180
|
+
Replicas authenticates GitHub with GitHub App tokens, which GitHub's attachment upload rejects, so \`gh --attach\` does not work. Use the public link every image upload prints, in public and private repositories alike, for PR descriptions, issues, and comments.
|
|
24212
24181
|
|
|
24213
|
-
1. Upload the image
|
|
24182
|
+
1. Upload the image:
|
|
24214
24183
|
|
|
24215
24184
|
\`\`\`bash
|
|
24216
|
-
replicas media upload /tmp/screenshot.png --name "PR screenshot"
|
|
24185
|
+
replicas media upload /tmp/screenshot.png --name "PR screenshot"
|
|
24217
24186
|
\`\`\`
|
|
24218
24187
|
|
|
24219
|
-
2. Copy the printed \`\`
|
|
24188
|
+
2. Copy the printed \`\` line verbatim into the body file, followed by the matching **View in Replicas** link. Never use a local file path, a \`/v1/media/<id>\` URL, a Linear \`assetUrl\`, or an expiring storage URL.
|
|
24220
24189
|
3. Create or update the PR using the body file:
|
|
24221
24190
|
|
|
24222
24191
|
\`\`\`bash
|
|
@@ -24225,13 +24194,13 @@ gh pr edit 456 --body-file /tmp/pr-body.md
|
|
|
24225
24194
|
gh pr comment 456 --body-file /tmp/comment.md
|
|
24226
24195
|
\`\`\`
|
|
24227
24196
|
|
|
24228
|
-
GitHub does not
|
|
24197
|
+
Videos stay private, and GitHub does not play external videos inline. Upload the MP4 normally, generate a poster with \`ffmpeg -i /tmp/demo.mp4 -frames:v 1 /tmp/demo-poster.png\`, upload the poster like any image, and link its printed embed to the recording's **View in Replicas** URL:
|
|
24229
24198
|
|
|
24230
24199
|
\`\`\`markdown
|
|
24231
24200
|
[](<recording-dashboard-url>)
|
|
24232
24201
|
\`\`\`
|
|
24233
24202
|
|
|
24234
|
-
Public
|
|
24203
|
+
Public links are unauthenticated bearer capabilities. Revoke with \`replicas media revoke <media-id>\` **only** when the user asks or the media should intentionally stop rendering; never as routine post-task cleanup, since revoking breaks every embed already posted on the PR.
|
|
24235
24204
|
|
|
24236
24205
|
For a self-contained HTML report, upload it with \`--access organization\` and put the printed \`Forge link\` Markdown in the PR body or comment. GitHub cannot render the page inline, so use the normal link rather than image syntax. HTML pages cannot be shared publicly.
|
|
24237
24206
|
|
|
@@ -24241,7 +24210,7 @@ Do **not** commit screenshots to the repo, use placeholder URLs, expose the auth
|
|
|
24241
24210
|
|
|
24242
24211
|
GitLab supports native project Markdown uploads. For a GitLab destination, always upload the media to Replicas first, then POST the same original file to the repository's \`/projects/:id/uploads\` API using the workspace GitLab credential. Insert the returned \`markdown\` value into the merge request body or comment and include the Replicas dashboard link. Image uploads render inline; MP4, MOV, and WebM uploads render as inline video players.
|
|
24243
24212
|
|
|
24244
|
-
Do not use a Replicas public
|
|
24213
|
+
Do not use a Replicas public link for GitLab when the native project upload succeeds; native uploads preserve project access controls.
|
|
24245
24214
|
|
|
24246
24215
|
## Recording defaults
|
|
24247
24216
|
|
|
@@ -24283,7 +24252,7 @@ replicas media upload chart-a.svg chart-b.svg --name "Latency chart" --name "Err
|
|
|
24283
24252
|
- \`--kind <image|video|audio|html>\` \u2014 override auto-detection
|
|
24284
24253
|
- \`--name <name>\`: required display name shown in the dashboard, one per file in order
|
|
24285
24254
|
- \`--session-id <id>\` \u2014 associate the upload with a specific session
|
|
24286
|
-
- \`--access organization|public\`: create an organization-only link
|
|
24255
|
+
- \`--access organization|public\`: for video, audio, and HTML, create an organization-only link or a public bearer URL (video and audio only). Images are always public
|
|
24287
24256
|
- \`--share\`: alias for \`--access public\`; not supported for HTML
|
|
24288
24257
|
`;
|
|
24289
24258
|
var MEDIA_ABILITY = {
|
|
@@ -25819,165 +25788,6 @@ function parseCursorEvents(events) {
|
|
|
25819
25788
|
return messages;
|
|
25820
25789
|
}
|
|
25821
25790
|
|
|
25822
|
-
// ../shared/src/display-message/parsers/deepseek-parser.ts
|
|
25823
|
-
function parseArguments(value) {
|
|
25824
|
-
if (typeof value !== "string") return void 0;
|
|
25825
|
-
const parsed = safeJsonParse(value, value);
|
|
25826
|
-
return isRecord(parsed) ? parsed : stringifyDisplayValue(parsed);
|
|
25827
|
-
}
|
|
25828
|
-
function getDeepseekAssistantMessageText(event, blockType) {
|
|
25829
|
-
if (!isRecord(event) || event.type !== "assistant/message" || !isRecord(event.data) || !isRecord(event.data.message) || !Array.isArray(event.data.message.content)) return "";
|
|
25830
|
-
return event.data.message.content.flatMap((block) => isRecord(block) && block.type === blockType && typeof block.text === "string" ? [block.text] : []).join("");
|
|
25831
|
-
}
|
|
25832
|
-
function parseDeepseekEvents(events) {
|
|
25833
|
-
const messages = [];
|
|
25834
|
-
for (const source of events) {
|
|
25835
|
-
if (source.type === "event_msg" && source.payload.type === "user_message") {
|
|
25836
|
-
if (typeof source.payload.message === "string" && source.payload.message.trim()) {
|
|
25837
|
-
const messageId = source.payload[USER_MESSAGE_ID_PAYLOAD_KEY];
|
|
25838
|
-
messages.push({
|
|
25839
|
-
id: typeof messageId === "string" ? messageId : `deepseek-user-${source.timestamp}`,
|
|
25840
|
-
type: "user",
|
|
25841
|
-
content: source.payload.message,
|
|
25842
|
-
timestamp: source.timestamp
|
|
25843
|
-
});
|
|
25844
|
-
}
|
|
25845
|
-
continue;
|
|
25846
|
-
}
|
|
25847
|
-
if (source.type === "deepseek-error") {
|
|
25848
|
-
messages.push({
|
|
25849
|
-
id: `deepseek-error-${source.timestamp}`,
|
|
25850
|
-
type: "error",
|
|
25851
|
-
message: typeof source.payload.message === "string" ? source.payload.message : "DeepSeek Harness failed",
|
|
25852
|
-
timestamp: source.timestamp
|
|
25853
|
-
});
|
|
25854
|
-
continue;
|
|
25855
|
-
}
|
|
25856
|
-
if (source.type === "deepseek-input-request") {
|
|
25857
|
-
const requestId = typeof source.payload.requestId === "string" ? source.payload.requestId : `deepseek-input-${source.timestamp}`;
|
|
25858
|
-
if (source.payload.kind === "approval") {
|
|
25859
|
-
upsertDisplayMessage(messages, createCallDisplayMessage({
|
|
25860
|
-
id: requestId,
|
|
25861
|
-
server: "deepseek",
|
|
25862
|
-
tool: typeof source.payload.toolName === "string" ? source.payload.toolName : "approval",
|
|
25863
|
-
input: typeof source.payload.reason === "string" ? source.payload.reason : void 0,
|
|
25864
|
-
status: "in_progress",
|
|
25865
|
-
timestamp: source.timestamp,
|
|
25866
|
-
inputRequest: {
|
|
25867
|
-
requestId,
|
|
25868
|
-
status: "pending",
|
|
25869
|
-
options: [
|
|
25870
|
-
{ id: "deny", label: "Deny", variant: "secondary" },
|
|
25871
|
-
{ id: "allow", label: "Allow once", variant: "primary" }
|
|
25872
|
-
]
|
|
25873
|
-
}
|
|
25874
|
-
}));
|
|
25875
|
-
} else {
|
|
25876
|
-
const questions = Array.isArray(source.payload.questions) ? source.payload.questions : [];
|
|
25877
|
-
upsertDisplayMessage(messages, createCallDisplayMessage({
|
|
25878
|
-
id: requestId,
|
|
25879
|
-
server: "deepseek",
|
|
25880
|
-
tool: "ask_user",
|
|
25881
|
-
status: "in_progress",
|
|
25882
|
-
timestamp: source.timestamp,
|
|
25883
|
-
inputRequest: {
|
|
25884
|
-
requestId,
|
|
25885
|
-
status: "pending",
|
|
25886
|
-
questions: questions.flatMap((question) => {
|
|
25887
|
-
if (!isRecord(question) || typeof question.id !== "string" || typeof question.question !== "string") return [];
|
|
25888
|
-
const options = Array.isArray(question.options) ? question.options : [];
|
|
25889
|
-
return [{
|
|
25890
|
-
id: question.id,
|
|
25891
|
-
prompt: question.question,
|
|
25892
|
-
multiSelect: question.multiSelect === true,
|
|
25893
|
-
options: options.flatMap((option) => isRecord(option) && typeof option.label === "string" ? [{ id: `${question.id}:${option.label}`, label: option.label, ...typeof option.description === "string" ? { description: option.description } : {} }] : [])
|
|
25894
|
-
}];
|
|
25895
|
-
})
|
|
25896
|
-
}
|
|
25897
|
-
}));
|
|
25898
|
-
}
|
|
25899
|
-
continue;
|
|
25900
|
-
}
|
|
25901
|
-
if (source.type === "deepseek-input-resolved") {
|
|
25902
|
-
const requestId = typeof source.payload.requestId === "string" ? source.payload.requestId : "";
|
|
25903
|
-
const existing = messages.find((message) => message.type === "tool_call" && message.inputRequest?.requestId === requestId);
|
|
25904
|
-
if (existing?.type === "tool_call" && existing.inputRequest) {
|
|
25905
|
-
existing.inputRequest.status = source.payload.status === "aborted" ? "aborted" : "resolved";
|
|
25906
|
-
existing.status = source.payload.status === "aborted" ? "failed" : "completed";
|
|
25907
|
-
}
|
|
25908
|
-
continue;
|
|
25909
|
-
}
|
|
25910
|
-
if (source.type === "deepseek-jobs" && Array.isArray(source.payload.jobs)) {
|
|
25911
|
-
for (const job of source.payload.jobs) {
|
|
25912
|
-
if (!isRecord(job) || typeof job.id !== "string") continue;
|
|
25913
|
-
const existing = messages.find((message) => message.type === "background_task" && message.taskId === job.id);
|
|
25914
|
-
const status = normalizeBackgroundTaskStatus(job.status);
|
|
25915
|
-
const next = {
|
|
25916
|
-
id: existing?.id ?? `deepseek-job-${job.id}`,
|
|
25917
|
-
type: "background_task",
|
|
25918
|
-
taskId: job.id,
|
|
25919
|
-
status,
|
|
25920
|
-
description: typeof job.label === "string" ? job.label : void 0,
|
|
25921
|
-
taskType: typeof job.kind === "string" ? job.kind : void 0,
|
|
25922
|
-
error: status === "failed" && typeof job.detail === "string" ? job.detail : void 0,
|
|
25923
|
-
timestamp: existing?.timestamp ?? source.timestamp
|
|
25924
|
-
};
|
|
25925
|
-
if (existing?.type === "background_task") Object.assign(existing, next);
|
|
25926
|
-
else messages.push(next);
|
|
25927
|
-
}
|
|
25928
|
-
continue;
|
|
25929
|
-
}
|
|
25930
|
-
if (source.type !== "deepseek-session-event" || !isRecord(source.payload.event)) continue;
|
|
25931
|
-
const event = source.payload.event;
|
|
25932
|
-
const data = isRecord(event.data) ? event.data : {};
|
|
25933
|
-
const seq = typeof event.seq === "number" ? event.seq : source.timestamp;
|
|
25934
|
-
if (event.type === "assistant/message") {
|
|
25935
|
-
const content = getDeepseekAssistantMessageText(event, "text");
|
|
25936
|
-
const reasoning = getDeepseekAssistantMessageText(event, "reasoning");
|
|
25937
|
-
if (reasoning.trim()) messages.push({ id: `deepseek-reasoning-${seq}`, type: "reasoning", content: reasoning, status: "completed", timestamp: source.timestamp });
|
|
25938
|
-
if (content.trim()) messages.push({ id: `deepseek-assistant-${seq}`, type: "agent", content, timestamp: source.timestamp });
|
|
25939
|
-
continue;
|
|
25940
|
-
}
|
|
25941
|
-
if (event.type === "tool/call") {
|
|
25942
|
-
const callId = typeof data.callId === "string" ? data.callId : String(seq);
|
|
25943
|
-
upsertDisplayMessage(messages, createCallDisplayMessage({
|
|
25944
|
-
id: `deepseek-tool-${callId}`,
|
|
25945
|
-
server: "deepseek",
|
|
25946
|
-
tool: typeof data.name === "string" ? data.name : "tool",
|
|
25947
|
-
input: parseArguments(data.arguments),
|
|
25948
|
-
status: "in_progress",
|
|
25949
|
-
timestamp: source.timestamp
|
|
25950
|
-
}));
|
|
25951
|
-
continue;
|
|
25952
|
-
}
|
|
25953
|
-
if (event.type === "tool/result") {
|
|
25954
|
-
const message = isRecord(data.message) ? data.message : {};
|
|
25955
|
-
const messageSource = isRecord(message.source) ? message.source : {};
|
|
25956
|
-
const result = Array.isArray(message.content) && isRecord(message.content[0]) ? message.content[0] : {};
|
|
25957
|
-
const callId = typeof messageSource.callId === "string" ? messageSource.callId : typeof data.callId === "string" ? data.callId : String(seq);
|
|
25958
|
-
const existing = messages.find((message2) => message2.id === `deepseek-tool-${callId}` && message2.type === "tool_call");
|
|
25959
|
-
if (existing?.type === "tool_call") {
|
|
25960
|
-
existing.output = stringifyDisplayValue(result.content ?? data.result);
|
|
25961
|
-
existing.status = result.isError === true || data.isError === true ? "failed" : "completed";
|
|
25962
|
-
}
|
|
25963
|
-
continue;
|
|
25964
|
-
}
|
|
25965
|
-
if (event.type === "todo/write" && Array.isArray(data.items)) {
|
|
25966
|
-
messages.push({
|
|
25967
|
-
id: `deepseek-todo-${seq}`,
|
|
25968
|
-
type: "todo_list",
|
|
25969
|
-
items: data.items.flatMap((item) => {
|
|
25970
|
-
if (!isRecord(item) || typeof item.content !== "string") return [];
|
|
25971
|
-
const itemStatus = item.status === "in_progress" || item.status === "completed" ? item.status : "pending";
|
|
25972
|
-
return [{ text: item.content, completed: itemStatus === "completed", itemStatus }];
|
|
25973
|
-
}),
|
|
25974
|
-
timestamp: source.timestamp
|
|
25975
|
-
});
|
|
25976
|
-
}
|
|
25977
|
-
}
|
|
25978
|
-
return messages;
|
|
25979
|
-
}
|
|
25980
|
-
|
|
25981
25791
|
// ../shared/src/display-message/parsers/acp-parser.ts
|
|
25982
25792
|
var FX_CONTEXT_DIAGNOSTIC = /^\[context\] skill catalog omitted .*?(?:\r?\n|$)/;
|
|
25983
25793
|
function getAcpTextChunk(update, kind) {
|
|
@@ -27172,18 +26982,12 @@ function parseAgentEvents(events, agentType) {
|
|
|
27172
26982
|
if (agentType === "cursor") {
|
|
27173
26983
|
return parseCursorEvents(events);
|
|
27174
26984
|
}
|
|
27175
|
-
if (agentType === "deepseek") {
|
|
27176
|
-
return parseDeepseekEvents(events);
|
|
27177
|
-
}
|
|
27178
26985
|
if (agentType === "fx") {
|
|
27179
26986
|
return parseFxEvents(events);
|
|
27180
26987
|
}
|
|
27181
26988
|
if (agentType === "kimi") {
|
|
27182
26989
|
return parseAcpEvents(events, "kimi");
|
|
27183
26990
|
}
|
|
27184
|
-
if (agentType === "gemini") {
|
|
27185
|
-
return parseAcpEvents(events, "gemini");
|
|
27186
|
-
}
|
|
27187
26991
|
if (agentType === "muse") {
|
|
27188
26992
|
return parseMuseEvents(events);
|
|
27189
26993
|
}
|
|
@@ -27457,7 +27261,7 @@ var headlessFilesystemAgentResultSchema = external_exports.object({
|
|
|
27457
27261
|
});
|
|
27458
27262
|
|
|
27459
27263
|
// ../shared/src/cli-version.ts
|
|
27460
|
-
var CLI_VERSION = "0.2.
|
|
27264
|
+
var CLI_VERSION = "0.2.729";
|
|
27461
27265
|
|
|
27462
27266
|
// ../shared/src/version.ts
|
|
27463
27267
|
function compareVersions(v1, v2) {
|
|
@@ -31536,38 +31340,41 @@ async function mediaUploadCommand(filePaths, options) {
|
|
|
31536
31340
|
if (publicAccess && kinds.some((kind) => !isPublicMediaKind(kind))) {
|
|
31537
31341
|
throw new Error("HTML pages only support organization access. Use --access organization.");
|
|
31538
31342
|
}
|
|
31343
|
+
const shared = kinds.map((kind) => publicAccess || kind === MEDIA_KIND.IMAGE);
|
|
31539
31344
|
const results = await Promise.allSettled(
|
|
31540
31345
|
filePaths.map((filePath, i) => uploadOne(filePath, names[i], kinds[i], options))
|
|
31541
31346
|
);
|
|
31542
|
-
const shareResults =
|
|
31347
|
+
const shareResults = await Promise.allSettled(
|
|
31543
31348
|
results.map(
|
|
31544
|
-
(result) => result.status === "fulfilled" ? shareMedia(result.value.media.id) : Promise.resolve(null)
|
|
31349
|
+
(result, i) => result.status === "fulfilled" && shared[i] ? shareMedia(result.value.media.id) : Promise.resolve(null)
|
|
31545
31350
|
)
|
|
31546
|
-
)
|
|
31351
|
+
);
|
|
31547
31352
|
const config3 = readAgentConfig();
|
|
31548
31353
|
const failures = [];
|
|
31549
31354
|
for (let i = 0; i < results.length; i++) {
|
|
31550
31355
|
const result = results[i];
|
|
31551
31356
|
if (result.status === "fulfilled") {
|
|
31552
31357
|
const { fileName, media } = result.value;
|
|
31553
|
-
const shareResult =
|
|
31358
|
+
const shareResult = shareResults[i];
|
|
31554
31359
|
const publicUrl = shareResult?.status === "fulfilled" ? shareResult.value ?? void 0 : void 0;
|
|
31555
|
-
if (
|
|
31360
|
+
if (shared[i]) {
|
|
31556
31361
|
if (!publicUrl) {
|
|
31557
|
-
const
|
|
31362
|
+
const reason = shareResult?.status === "rejected" ? shareResult.reason : new Error("Missing public share URL");
|
|
31558
31363
|
failures.push({
|
|
31559
31364
|
filePath: filePaths[i],
|
|
31560
31365
|
operation: "share",
|
|
31561
|
-
error:
|
|
31366
|
+
error: new Error(
|
|
31367
|
+
`${reason instanceof Error ? reason.message : String(reason)}. Uploaded as ${media.id}; retry with \`replicas media share ${media.id}\``
|
|
31368
|
+
)
|
|
31562
31369
|
});
|
|
31563
31370
|
}
|
|
31564
31371
|
}
|
|
31565
31372
|
if (media.kind === MEDIA_KIND.HTML) {
|
|
31566
31373
|
console.log(`HTML page: [${fileName}](${MONOLITH_URL}/v1/media/${media.id})`);
|
|
31567
|
-
} else if (!
|
|
31374
|
+
} else if (!shared[i] || publicUrl) {
|
|
31568
31375
|
console.log(formatMediaEmbed(fileName, media.id, publicUrl));
|
|
31569
31376
|
}
|
|
31570
|
-
if (options.access === "organization") {
|
|
31377
|
+
if (options.access === "organization" && !shared[i]) {
|
|
31571
31378
|
console.log(
|
|
31572
31379
|
`Forge link (organization only): [View ${options.name?.[i] ?? fileName}](${getOrganizationMediaUrl(media.organization_id, media.id)})`
|
|
31573
31380
|
);
|
|
@@ -31608,7 +31415,7 @@ async function mediaListCommand(options) {
|
|
|
31608
31415
|
const query = qs.toString() ? `?${qs.toString()}` : "";
|
|
31609
31416
|
const { media } = await agentFetch(`/v1/engine/media${query}`);
|
|
31610
31417
|
for (const m of media) {
|
|
31611
|
-
console.log(`${
|
|
31418
|
+
console.log(`${m.id} ${m.kind} ${m.display_name ?? ""} ${m.size} ${m.created_at}`);
|
|
31612
31419
|
}
|
|
31613
31420
|
}
|
|
31614
31421
|
|
|
@@ -33181,7 +32988,7 @@ if (isAgentMode()) {
|
|
|
33181
32988
|
"Required human-facing display name shown in the dashboard. Pass one --name per file, in order.",
|
|
33182
32989
|
(value, previous) => [...previous, value],
|
|
33183
32990
|
[]
|
|
33184
|
-
).option("--access <access>", "Link access: organization (sign-in required) or public (
|
|
32991
|
+
).option("--access <access>", "Link access for video, audio, and HTML: organization (sign-in required) or public (video and audio only). Images always get a public link").option("--share", "Alias for --access public; not supported for HTML").action(async (files, options) => {
|
|
33185
32992
|
try {
|
|
33186
32993
|
await mediaUploadCommand(files, options);
|
|
33187
32994
|
} catch (error51) {
|
|
@@ -33193,7 +33000,7 @@ if (isAgentMode()) {
|
|
|
33193
33000
|
process.exit(1);
|
|
33194
33001
|
}
|
|
33195
33002
|
});
|
|
33196
|
-
media.command("share <mediaId>").description("
|
|
33003
|
+
media.command("share <mediaId>").description("Rotate an image's public forge URL, or create one for video or audio media").action(async (mediaId) => {
|
|
33197
33004
|
try {
|
|
33198
33005
|
await mediaShareCommand(mediaId);
|
|
33199
33006
|
} catch (error51) {
|