replicas-cli 0.3.104 → 0.3.106

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 +39 -38
  2. package/package.json +1 -1
package/dist/index.cjs CHANGED
@@ -24527,7 +24527,7 @@ Every Replicas workspace is a remote Linux VM. Repositories are cloned under \`~
24527
24527
 
24528
24528
  Hooks run with \`bash -lc\` from \`~/workspaces\` (the parent of every repository checkout), so start scripts with \`cd ~/workspaces/<repo-name>\`. A repository may also ship its own \`replicas.json\` / \`replicas.yaml\` with \`startHook\`, \`warmHook\`, and \`systemPrompt\`; repository hooks run after the environment hooks. Prefer proposing environment hooks unless the repository already manages its own.
24529
24529
 
24530
- The organization's base environment applies to every environment built on it; never propose putting repository-specific setup there.
24530
+ Forks inherit everything their parent sets; never propose putting repository-specific setup in an environment other environments fork from.
24531
24531
 
24532
24532
  ## Progress and the setup run
24533
24533
 
@@ -24735,7 +24735,6 @@ After \`propose\` succeeds, mark the \`propose\` step completed and send one mes
24735
24735
  - <two to four findings about the codebase that shaped the configuration, written for a person>
24736
24736
 
24737
24737
  ![<Project> walkthrough](<chat embed URL printed by replicas media upload>)
24738
- [View in Canvas](<View in Replicas URL>)
24739
24738
 
24740
24739
  **Proposed configuration**
24741
24740
  Review the start hook, warm hook, system prompt, variables, and automations in the Environment panel on the right. Edit anything inline, then select **Save configuration**. Ask me here if you want changes and I will revise the proposal.
@@ -25185,6 +25184,12 @@ var REFERENCE8 = `# Media (Screenshots, GIFs, Recordings, Audio, HTML)
25185
25184
 
25186
25185
  This is the single source of truth for delivering screenshots, GIFs, screen recordings, generated diagrams, audio clips, and self-contained HTML pages through Replicas and external surfaces (Slack, Linear, GitHub, GitLab).
25187
25186
 
25187
+ ## Always
25188
+
25189
+ - Every picture, GIF, recording, or HTML page you mention in your reply to the user shows up in that reply: paste its printed \`![\u2026](\u2026)\` or \`HTML page\` line on its own line. Do this even when you also posted it to a PR, Slack, Linear, or GitLab, and even when the task came from one of them.
25190
+ - Never send the user somewhere else to see it ("see the Canvas", "check the media tab"). Uploads also appear in the Canvas's media folder, so they stay there for later.
25191
+ - Keep the whole \`replicas media upload\` output. Don't pipe it through \`tail\`, \`grep\`, or \`head\`; you need every line it prints.
25192
+
25188
25193
  ## Prerequisites
25189
25194
 
25190
25195
  The \`replicas\` CLI is pre-installed and authenticated in your workspace. No additional setup is needed.
@@ -25253,7 +25258,7 @@ If none of these apply, don't upload.
25253
25258
  \`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:
25254
25259
 
25255
25260
  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.
25256
- 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.
25261
+ 2. Include the printed embed line in the Replicas chat reply. HTML uses its printed page link instead of an image embed.
25257
25262
  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.
25258
25263
  4. Put the **View in Replicas** dashboard link next to the destination embed as a secondary link.
25259
25264
  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.
@@ -25294,21 +25299,13 @@ Names are normalized to hyphen-case (spaces become hyphens, e.g. \`Login page\`
25294
25299
 
25295
25300
  For each media file, the CLI prints an embed line and a dashboard link:
25296
25301
 
25297
- 1. Images always print \`![filename](<public-url>)\`. This public, stable link works in Replicas chat, GitHub, and anywhere else Markdown images render. No flag is needed.
25298
- 2. Video and audio print \`Replicas chat embed: ![filename](<api-url>)\` by default; this authenticated URL renders inline in Replicas chat **only** \u2014 see below. \`--access public\` prints a public embed instead.
25302
+ 1. Images always print \`![<name>](<public-url>)\`, using the \`--name\` you passed. This public, stable link works in Replicas chat, GitHub, and anywhere else Markdown images render. No flag is needed.
25303
+ 2. Video and audio print \`Replicas chat embed: ![<name>](<api-url>)\` by default; this authenticated URL renders inline in Replicas chat **only** \u2014 see below. \`--access public\` prints a public link instead, \`[<name>](<public-url>)\`, which plays in Replicas chat and opens the video anywhere else. Never put a video inside \`![\u2026](\u2026)\` or a \`<video>\` tag on GitHub: it shows as a broken image or disappears. Videos also print the PR line to paste once you have a GIF, already linked to the video.
25299
25304
  3. \`View in Replicas: <deep-link>\` is a per-file dashboard URL of the form \`https://app.replicas.dev/workspaces/<workspace-id>?mode=media&media=<media-id>\` that opens directly to that specific file.
25300
25305
 
25301
25306
  Match each "View in Replicas" line to the embed line directly above it \u2014 that's the deep link for that file.
25302
25307
 
25303
- HTML uploads print an \`HTML page\` Markdown link instead of an image embed.
25304
-
25305
- For an HTML page that should stay inside the Replicas organization, create an authenticated link:
25306
-
25307
- \`\`\`bash
25308
- replicas media upload recap.html --name "Visual recap" --access organization
25309
- \`\`\`
25310
-
25311
- 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.
25308
+ HTML uploads print an \`HTML page\` Markdown link instead of an image embed. It previews the page inside Replicas chat only. They also print a \`Forge link (organization only)\` to use everywhere else: it opens a dedicated page, where signed-in organization members go straight to the report and signed-out members sign in first.
25312
25309
 
25313
25310
  Video and audio stay private unless they must play without Replicas sign-in; then pass \`--access public\` (alias \`--share\`):
25314
25311
 
@@ -25325,7 +25322,7 @@ Permanently delete an upload with \`replicas media delete <media-id>\`. The back
25325
25322
  | URL | What it is | Where it's allowed |
25326
25323
  |---|---|---|
25327
25324
  | \`https://api.replicas.dev/v1/media/<id>\` (inside \`![\u2026](\u2026)\`) | Authenticated API redirect printed for private video, audio, and HTML \u2014 requires the Replicas chat session | **Only** in the Replicas chat reply. Nowhere else. |
25328
- | \`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. |
25325
+ | \`https://app.replicas.dev/organizations/<organization-id>/media/<media-id>\` | Organization-only page (\`Forge link\`) printed for every HTML upload, and for video or audio with \`--access organization\` | Pull requests and other places where every viewer belongs to the Replicas organization. |
25329
25326
  | \`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. |
25330
25327
  | \`https://app.replicas.dev/workspaces/<workspace-id>?mode=media&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. |
25331
25328
 
@@ -25343,7 +25340,7 @@ This rule has no exceptions:
25343
25340
 
25344
25341
  ### ALWAYS link a Replicas web URL \u2014 never the authenticated API URL \u2014 when referencing media externally
25345
25342
 
25346
- For an organization-only HTML page, use the \`Forge link\` printed by \`--access organization\`. For other authenticated media references, use the dashboard form:
25343
+ For an HTML page, use its printed \`Forge link\`. For other authenticated media references, use the dashboard form:
25347
25344
 
25348
25345
  \`\`\`
25349
25346
  https://app.replicas.dev/workspaces/<workspace-id>?mode=media&media=<media-id>
@@ -25361,8 +25358,6 @@ Include each markdown embed line **verbatim** where you want that file to render
25361
25358
 
25362
25359
  Never reply with only dashboard links (for example a "Links:" list of \`?mode=media&media=\` URLs) in place of the embeds: a dashboard link renders as plain text, so the user sees nothing inline. This applies even when the task came from Slack, Linear, GitHub, or GitLab; the chat reply still gets the embeds.
25363
25360
 
25364
- After (or alongside) the embeds, include a \`[View in Canvas](<deep-link>)\` hyperlink for each file using the per-file dashboard URL printed by the CLI as **View in Replicas**. Keep that URL unchanged so it opens the specific media item in the workspace's Canvas. External messages still label this dashboard link **View in Replicas**.
25365
-
25366
25361
  ## On external platforms: embed the file AND link the dashboard
25367
25362
 
25368
25363
  After \`replicas media upload\` succeeds, external delivery has two required follow-up steps for every file:
@@ -25494,7 +25489,7 @@ gh pr edit 456 --body-file /tmp/pr-body.md
25494
25489
  gh pr comment 456 --body-file /tmp/comment.md
25495
25490
  \`\`\`
25496
25491
 
25497
- GitHub does not play external videos inline, so show motion with a GIF (see *Make a GIF from a recording* above); its printed embed animates inline like any image. Videos stay private. When the full recording is also worth watching, upload the MP4 too and link the GIF to the recording's **View in Replicas** URL. When a still is enough, use a poster instead (\`ffmpeg -i /tmp/demo.mp4 -frames:v 1 /tmp/demo-poster.png\`), uploaded like any image:
25492
+ GitHub does not play external videos inline, so show motion with a GIF (see *Make a GIF from a recording* above); its printed embed animates inline like any image. Videos stay private. When the full recording is also worth watching, upload the MP4 too and paste the PR line it prints, with your GIF's link filled in. The GIF links to the recording's **View in Replicas** URL, or to its public link when you passed \`--access public\`. When a still is enough, use a poster instead (\`ffmpeg -i /tmp/demo.mp4 -frames:v 1 /tmp/demo-poster.png\`), uploaded like any image:
25498
25493
 
25499
25494
  \`\`\`markdown
25500
25495
  [![Checkout flow](<public-gif-or-poster-url>)](<recording-dashboard-url>)
@@ -25502,7 +25497,7 @@ GitHub does not play external videos inline, so show motion with a GIF (see *Mak
25502
25497
 
25503
25498
  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.
25504
25499
 
25505
- 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.
25500
+ For a self-contained HTML report, upload it 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.
25506
25501
 
25507
25502
  Do **not** commit screenshots to the repo, use placeholder URLs, expose the authenticated \`/v1/media/<id>\` URL, or automate GitHub's undocumented browser upload flow.
25508
25503
 
@@ -25554,7 +25549,7 @@ replicas media upload chart-a.svg chart-b.svg --name "Latency chart" --name "Err
25554
25549
  - \`--kind <image|video|audio|html>\` \u2014 override auto-detection
25555
25550
  - \`--name <name>\`: required display name shown in the dashboard, one per file in order
25556
25551
  - \`--session-id <id>\` \u2014 associate the upload with a specific session
25557
- - \`--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
25552
+ - \`--access organization|public\`: for video and audio, print an organization-only link or create a public bearer URL. Images are always public, and HTML always gets an organization-only link
25558
25553
  - \`--share\`: alias for \`--access public\`; not supported for HTML
25559
25554
  `;
25560
25555
  var MEDIA_ABILITY = {
@@ -25997,7 +25992,7 @@ replicas environment delete <id-or-name> [--force]
25997
25992
  \`\`\`
25998
25993
 
25999
25994
  Notes:
26000
- - Environments resolve by **name or UUID**. \`replicas environment list\` marks the org's base environment, which every other environment builds on.
25995
+ - Environments resolve by **name or UUID**. A fork inherits its parent's setup and can override or hide any of it.
26001
25996
  - An env needs a repo to back a workspace with code. If you \`create\` without \`--repository\`, the CLI prompts; in non-interactive contexts pass \`-r\`.
26002
25997
 
26003
25998
  ### Environment variables
@@ -28765,7 +28760,7 @@ var headlessAgentRequestSchema = external_exports.object({
28765
28760
  });
28766
28761
 
28767
28762
  // ../shared/src/cli-version.ts
28768
- var CLI_VERSION = "0.3.104";
28763
+ var CLI_VERSION = "0.3.106";
28769
28764
 
28770
28765
  // ../shared/src/version.ts
28771
28766
  function compareVersions(v1, v2) {
@@ -31617,8 +31612,8 @@ async function resolveEnvironmentId(input) {
31617
31612
  }
31618
31613
  return resolved.id;
31619
31614
  }
31620
- function printEnvironment(env, isBase = false) {
31621
- console.log(import_chalk20.default.white(` ${env.name}${isBase ? import_chalk20.default.gray(" (base)") : ""}`));
31615
+ function printEnvironment(env) {
31616
+ console.log(import_chalk20.default.white(` ${env.name}`));
31622
31617
  console.log(import_chalk20.default.gray(` ID: ${env.id}`));
31623
31618
  if (env.description) {
31624
31619
  console.log(import_chalk20.default.gray(` Description: ${env.description}`));
@@ -31636,7 +31631,7 @@ function printEnvironment(env, isBase = false) {
31636
31631
  async function environmentListCommand() {
31637
31632
  ensureOrgApiAuthenticated();
31638
31633
  const response = await orgAuthenticatedFetch("/v1/environments");
31639
- output(response, ({ environments, base_environment_id }) => {
31634
+ output(response, ({ environments }) => {
31640
31635
  if (environments.length === 0) {
31641
31636
  console.log(import_chalk20.default.yellow("\nNo environments found.\n"));
31642
31637
  return;
@@ -31644,7 +31639,7 @@ async function environmentListCommand() {
31644
31639
  console.log(import_chalk20.default.green(`
31645
31640
  Environments (${environments.length}):
31646
31641
  `));
31647
- for (const env of environments) printEnvironment(env, env.id === base_environment_id);
31642
+ for (const env of environments) printEnvironment(env);
31648
31643
  });
31649
31644
  }
31650
31645
  async function environmentGetCommand(idOrName) {
@@ -32297,7 +32292,7 @@ async function replicaCreateCommand(name, options) {
32297
32292
  let replicaName = name;
32298
32293
  let message2 = options.message;
32299
32294
  const environmentInput = options.environment?.trim();
32300
- let selectedEnvironmentId = environmentInput === "global" ? envResponse.base_environment_id ?? void 0 : environmentInput && await resolveEnvironmentId(environmentInput);
32295
+ let selectedEnvironmentId = environmentInput === "global" ? (await orgAuthenticatedFetch("/v1/environments/global")).environment.id : environmentInput && await resolveEnvironmentId(environmentInput);
32301
32296
  let codingAgent = parseReplicaAgent(options.agent);
32302
32297
  if (replicaName && /\s/.test(replicaName)) {
32303
32298
  throw new Error("Replica name cannot contain spaces.");
@@ -32328,7 +32323,7 @@ async function replicaCreateCommand(name, options) {
32328
32323
  choices: environments.map((env) => ({
32329
32324
  title: env.name,
32330
32325
  value: env.id,
32331
- description: env.id === envResponse.base_environment_id ? "base" : `${env.repository_ids?.length ?? 0} repositories`
32326
+ description: `${env.repository_ids?.length ?? 0} repositories`
32332
32327
  }))
32333
32328
  });
32334
32329
  const answer = response2.environment;
@@ -33975,10 +33970,11 @@ var MEDIA_ACCESS_VALUES = ["organization", "public"];
33975
33970
  function publicMediaUrl(mediaId, token) {
33976
33971
  return `${MONOLITH_URL}/v1/media/public/${mediaId}/${token}`;
33977
33972
  }
33978
- var MEDIA_DELIVERY_HINT = "Next: paste each ![\u2026](\u2026) or HTML page line above verbatim into your Replicas chat reply so it renders inline; View in Replicas links are secondary and never replace it. Slack, Linear, and GitLab also need a native upload of the file bytes; see the replicas-agent skill's references/MEDIA.md.";
33979
- function formatMediaEmbed(fileName, mediaId, publicUrl) {
33980
- if (publicUrl) return `![${fileName}](${publicUrl})`;
33981
- return `Replicas chat embed: ![${fileName}](${MONOLITH_URL}/v1/media/${mediaId})`;
33973
+ var MEDIA_DELIVERY_HINT = "Next: paste each media line above (`![\u2026](\u2026)`, `[\u2026](\u2026)`, or `HTML page`) verbatim into your Replicas chat reply so it renders inline; View in Replicas links are secondary and never replace it. Slack, Linear, and GitLab also need a native upload of the file bytes; see the replicas-agent skill's references/MEDIA.md.";
33974
+ var markdownLabel = (name) => name.replace(/[[\]]/g, "");
33975
+ function formatMediaEmbed(name, media2, publicUrl) {
33976
+ if (publicUrl) return `${media2.kind === MEDIA_KIND.IMAGE ? "!" : ""}[${markdownLabel(name)}](${publicUrl})`;
33977
+ return `Replicas chat embed: ![${markdownLabel(name)}](${MONOLITH_URL}/v1/media/${media2.id})`;
33982
33978
  }
33983
33979
  async function shareMedia(mediaId) {
33984
33980
  const { token } = await agentFetch(`/v1/engine/media/${mediaId}/share`, {
@@ -34034,7 +34030,7 @@ async function uploadOne(filePath, displayName, kind, options) {
34034
34030
  method: "POST",
34035
34031
  body: form
34036
34032
  });
34037
- return { fileName, media: media2 };
34033
+ return media2;
34038
34034
  }
34039
34035
  async function mediaUploadCommand(filePaths, options) {
34040
34036
  if (filePaths.length === 0) {
@@ -34072,7 +34068,7 @@ async function mediaUploadCommand(filePaths, options) {
34072
34068
  );
34073
34069
  const shareResults = await Promise.allSettled(
34074
34070
  results.map(
34075
- (result, i) => result.status === "fulfilled" && shared[i] ? shareMedia(result.value.media.id) : Promise.resolve(null)
34071
+ (result, i) => result.status === "fulfilled" && shared[i] ? shareMedia(result.value.id) : Promise.resolve(null)
34076
34072
  )
34077
34073
  );
34078
34074
  const config3 = readAgentConfig();
@@ -34081,7 +34077,7 @@ async function mediaUploadCommand(filePaths, options) {
34081
34077
  for (let i = 0; i < results.length; i++) {
34082
34078
  const result = results[i];
34083
34079
  if (result.status === "fulfilled") {
34084
- const { fileName, media: media2 } = result.value;
34080
+ const media2 = result.value;
34085
34081
  const shareResult = shareResults[i];
34086
34082
  const publicUrl = shareResult?.status === "fulfilled" ? shareResult.value ?? void 0 : void 0;
34087
34083
  if (shared[i]) {
@@ -34101,8 +34097,9 @@ async function mediaUploadCommand(filePaths, options) {
34101
34097
  name: names[i],
34102
34098
  media: media2,
34103
34099
  public_url: publicUrl,
34104
- embed: media2.kind === MEDIA_KIND.HTML ? `HTML page: [${fileName}](${MONOLITH_URL}/v1/media/${media2.id})` : !shared[i] || publicUrl ? formatMediaEmbed(fileName, media2.id, publicUrl) : void 0,
34105
- organization_url: options.access === "organization" && !shared[i] ? getOrganizationMediaUrl(media2.organization_id, media2.id) : void 0,
34100
+ embed: media2.kind === MEDIA_KIND.HTML ? `HTML page: [${markdownLabel(names[i])}](${MONOLITH_URL}/v1/media/${media2.id})` : !shared[i] || publicUrl ? formatMediaEmbed(names[i], media2, publicUrl) : void 0,
34101
+ // The HTML page link above only works inside Replicas chat, so HTML always gets a link that works elsewhere.
34102
+ organization_url: media2.kind === MEDIA_KIND.HTML || options.access === "organization" && !shared[i] ? getOrganizationMediaUrl(media2.organization_id, media2.id) : void 0,
34106
34103
  dashboard_url: config3?.workspace_id ? getWorkspaceDashboardUrl(config3.workspace_id, { mode: "media", mediaId: media2.id }) : void 0
34107
34104
  });
34108
34105
  } else {
@@ -34117,6 +34114,10 @@ async function mediaUploadCommand(filePaths, options) {
34117
34114
  console.log(`Forge link (organization only): [View ${upload.name}](${upload.organization_url})`);
34118
34115
  }
34119
34116
  if (upload.dashboard_url) console.log(`View in Replicas: ${upload.dashboard_url}`);
34117
+ if (upload.media.kind === MEDIA_KIND.VIDEO) {
34118
+ const videoLink = upload.public_url ?? upload.dashboard_url;
34119
+ console.log(`GitHub can't play videos. For a PR, make a GIF with \`replicas media gif ${upload.file}\`, upload it, and paste it linked to this video: [![${markdownLabel(upload.name)}](<GIF link>)](${videoLink})`);
34120
+ }
34120
34121
  }
34121
34122
  if (uploads.some((upload) => upload.embed)) console.log(`
34122
34123
  ${MEDIA_DELIVERY_HINT}`);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "replicas-cli",
3
- "version": "0.3.104",
3
+ "version": "0.3.106",
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": {