@meistrari/remy-cli 1.14.0 → 1.15.0

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 (3) hide show
  1. package/README.md +4 -2
  2. package/dist/remy.js +123 -33
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -36,13 +36,13 @@ The dashboard is the starting point for all interactive work. It refreshes the v
36
36
 
37
37
  ### Start work
38
38
 
39
- Press `n` in the dashboard. The new-session flow asks what you want done, selects a GitHub installation when needed, suggests repositories based on your request, and lets you review those suggestions. If the request links an open pull request in a selected repository, Remy checks the current pull request state before accepting branch confirmation and adds a third branch step: continue from that pull request's current branch or create a new session branch. Before creating the session, choose the agent model and reasoning effort. The wizard starts with `gpt-6-astra` and `medium` reasoning by default. Remy then opens the session and streams its activity.
39
+ Press `n` in the dashboard. The new-session flow asks what you want done, selects a GitHub installation when needed, suggests repositories based on your request, and lets you review those suggestions. Remy analyzes the request for existing work: a Remy session ID or number, a PR URL or number (`PR 267`, `#267`, or `owner/repo#267`), or an exact or approximate branch name. It verifies matches against the selected repositories and offers up to five branches per repository. In the branch step, use arrows to move, Space to select, and Enter to select the current option and review your choices. Each repository can continue one branch or start a new session branch. A lookup failure stays on a retry screen; press `r` to retry, `n` to explicitly choose new branches, or Esc to edit the request. Before creating the session, choose the agent model and reasoning effort. The wizard starts with `gpt-6-astra` and `medium` reasoning by default. Remy then opens the session and streams its activity.
40
40
 
41
41
  Use `Tab` while writing the request to complete a local file or directory path. Remy attaches selected paths when you confirm the request. Each file may be at most 20 MiB. A directory may contain at most 20 MiB across its regular files before compression; Remy uploads it as a temporary `<directory>.tar.gz` archive with the selected directory preserved as its root, so the remote agent can extract and use its files. Remy rejects oversized attachments with guidance to choose a smaller file or directory, and rejects directory attachments that contain symbolic links or other non-regular entries. On macOS, `Ctrl+V` adds a PNG from the system clipboard to the request; Remy attaches it on confirmation. Remy uploads attachments before creating the session and shows their filenames beneath your message.
42
42
 
43
43
  ### Resume or follow up
44
44
 
45
- Every terminal follow-up is appended as an explicit **Steer**, so it targets the work currently in progress. Queuing a message for a later turn (**Next**) is Web-only for now.
45
+ Every terminal follow-up is appended as an explicit **Steer**, so it targets the work currently in progress. Queuing a message for a later turn (**Next**) is Web-only for now. Remy can replay sessions containing queued-message dispatch, withdrawal, and failure events. Messages withdrawn or failed before reaching Remy show an activity notice; an active submission ends as cancelled or failed instead of waiting for a turn that never started.
46
46
 
47
47
  Use Up/Down to select a session in the dashboard, Left/Right to load the adjacent page, and `Enter` to open it. Remy loads the complete retained conversation before showing the session view, then streams new activity as it arrives. Press `s` to search the loaded page by session ID, title, or number; `Enter` keeps the search active and `Esc` clears it. Press `f` to filter sessions by lifecycle status or `a` to filter by author. Both pickers use checkboxes: Up/Down or `j`/`k` moves, `Space` toggles, Right/`l` checks, Left/`h` clears, `G` and `gg` jump to the last and first option, and `Enter` applies every checked value. An empty picker means all values. Press `s` inside either picker to fuzzy-search its options; `Enter` keeps the matching list and `Esc` cancels the search. Press `Esc` outside search to discard staged checkbox changes. Filters apply to the complete remote result set and reset pagination to its first page. After the dashboard list or repository-review list has focus, Vim keys work too: `j`/`k` move, `h`/`l` go to the previous/next dashboard page (or clear/mark a repository), `G` goes to the last row, and `gg` goes to the first row. Press `Shift+L` in the dashboard to start a logout confirmation. In any message composer, plain `Enter` and `Shift+Enter` submit; `Option+Enter` on macOS (`Alt+Enter` elsewhere) inserts a newline. `Ctrl+J` also inserts a newline for terminals that do not report the Option/Alt modifier. The conversation header keeps the numbered session title on its first line and repository, pull request, work state, elapsed time, and connection state on its second line. The header also keeps the last provider-reported context observation across reconnects, such as `Context 50% left · 62,000 used`; when the provider does not report a context window, it shows only used tokens. This is an observation, not a live occupancy guarantee or billing total.
48
48
 
@@ -91,6 +91,8 @@ remy new --repository owner/repository "Add a health check endpoint"
91
91
 
92
92
  Repeat `--repository` to select more repositories from the same GitHub installation. If you do not select a repository, supply `--installation <github-installation-id>`. Repeat `--attach <path>` to upload files or directories; the 20 MiB per-attachment limit is measured directly for a file and across all regular files before compressing a directory. Remy sends each accepted directory as a gzip-compressed tar archive. Direct creation uses `medium` reasoning unless `--reasoning-effort` overrides it; omit `--model` to use the server's `gpt-6-astra` default. `remy new` creates the session from the prompt and flags, then opens it when the terminal is interactive.
93
93
 
94
+ The branch-suggestion flow belongs to the interactive new-session wizard (`remy`, then `n`). Direct `remy new` creation does not analyze continuation references.
95
+
94
96
  ### Open a known session
95
97
 
96
98
  ```bash
package/dist/remy.js CHANGED
@@ -31690,6 +31690,12 @@ var branchSuggestionsResponseSchema = exports_external2.strictObject({
31690
31690
  url: exports_external2.url()
31691
31691
  })
31692
31692
  }),
31693
+ exports_external2.strictObject({
31694
+ repository_id: exports_external2.string().min(1),
31695
+ suggestion_kind: exports_external2.literal("continue_existing_branch"),
31696
+ branch_name: exports_external2.string().min(1),
31697
+ pull_request: exports_external2.null()
31698
+ }),
31693
31699
  exports_external2.strictObject({
31694
31700
  repository_id: exports_external2.string().min(1),
31695
31701
  suggestion_kind: exports_external2.literal("create_session_branch"),
@@ -31791,6 +31797,7 @@ async function suggestRemoteBranches({
31791
31797
  method: "POST",
31792
31798
  headers: { "content-type": "application/json" },
31793
31799
  body: JSON.stringify({
31800
+ suggestion_mode: "prompt",
31794
31801
  github_installation_id: parsedInput.installationId,
31795
31802
  prompt: parsedInput.prompt,
31796
31803
  repository_ids: parsedInput.repositoryIds
@@ -31810,6 +31817,11 @@ async function suggestRemoteBranches({
31810
31817
  repositoryId: repository.repository_id,
31811
31818
  branchName: repository.branch_name,
31812
31819
  pullRequest: repository.pull_request
31820
+ } : repository.suggestion_kind === "continue_existing_branch" ? {
31821
+ suggestionKind: "continueExistingBranch",
31822
+ repositoryId: repository.repository_id,
31823
+ branchName: repository.branch_name,
31824
+ pullRequest: null
31813
31825
  } : {
31814
31826
  suggestionKind: "createSessionBranch",
31815
31827
  repositoryId: repository.repository_id,
@@ -34069,6 +34081,10 @@ var sessionMessageTurnAssociatedEventSchema = exports_external2.object({
34069
34081
  type: exports_external2.literal("session.message.turn-associated"),
34070
34082
  payload: exports_external2.object({ messageId: exports_external2.string().min(1), commandId: exports_external2.string().min(1), turnId: exports_external2.string().min(1) }).passthrough()
34071
34083
  }).passthrough();
34084
+ var sessionMessageDispatchEventSchema = exports_external2.object({
34085
+ type: exports_external2.enum(["session.message.dispatched", "session.message.withdrawn", "session.message.failed"]),
34086
+ payload: exports_external2.object({ messageId: exports_external2.string().min(1), commandId: exports_external2.string().min(1) }).passthrough()
34087
+ }).passthrough();
34072
34088
  var sessionWorkspaceGitInitializedEventSchema = exports_external2.object({
34073
34089
  type: exports_external2.literal("session.workspace.git.initialized"),
34074
34090
  payload: exports_external2.object({
@@ -34205,6 +34221,8 @@ function sessionTurnOutcome({ state, sessionMessageId }) {
34205
34221
  const turn = state.messageTurns[sessionMessageId];
34206
34222
  if (!turn)
34207
34223
  return { status: "unassociated" };
34224
+ if (turn.turnId === null)
34225
+ return { status: "ended", turnId: null, outcome: turn.outcome };
34208
34226
  if (turn.outcome)
34209
34227
  return { status: "ended", turnId: turn.turnId, outcome: turn.outcome };
34210
34228
  return { status: "pending", turnId: turn.turnId };
@@ -34228,10 +34246,11 @@ function projectRetainedEvent({
34228
34246
  }) {
34229
34247
  const messageCreated = sessionMessageCreatedEventSchema.safeParse(event);
34230
34248
  const turnAssociated = sessionMessageTurnAssociatedEventSchema.safeParse(event);
34249
+ const messageDispatch = sessionMessageDispatchEventSchema.safeParse(event);
34231
34250
  const workspaceGitInitialized = sessionWorkspaceGitInitializedEventSchema.safeParse(event);
34232
34251
  const workspaceGitRevision = sessionWorkspaceGitRevisionEventSchema.safeParse(event);
34233
34252
  const turnEnded = agentTurnEndedEventSchema.safeParse(event);
34234
- let projected = messageCreated.success ? projectSessionMessageCreated({ state, event: messageCreated.data, occurredAt }) : turnAssociated.success ? projectSessionMessageTurnAssociated({ state, event: turnAssociated.data }) : workspaceGitInitialized.success ? projectSessionWorkspaceGitInitialized({ state, event: workspaceGitInitialized.data, occurredAt, retainedEventId }) : workspaceGitRevision.success ? projectSessionWorkspaceGitRevision({ state, event: workspaceGitRevision.data, occurredAt, retainedEventId }) : turnEnded.success ? projectAgentTurnEnded({ state, event: turnEnded.data, occurredAt, retainedEventId }) : projectDurableAgentEvent({ state, event, occurredAt, retainedEventId });
34253
+ let projected = messageCreated.success ? projectSessionMessageCreated({ state, event: messageCreated.data, occurredAt }) : turnAssociated.success ? projectSessionMessageTurnAssociated({ state, event: turnAssociated.data }) : messageDispatch.success ? projectSessionMessageDispatch({ state, event: messageDispatch.data, occurredAt, retainedEventId }) : workspaceGitInitialized.success ? projectSessionWorkspaceGitInitialized({ state, event: workspaceGitInitialized.data, occurredAt, retainedEventId }) : workspaceGitRevision.success ? projectSessionWorkspaceGitRevision({ state, event: workspaceGitRevision.data, occurredAt, retainedEventId }) : turnEnded.success ? projectAgentTurnEnded({ state, event: turnEnded.data, occurredAt, retainedEventId }) : projectDurableAgentEvent({ state, event, occurredAt, retainedEventId });
34235
34254
  projected = recordAgentLineageEvent({ state: projected, event, retainedEventId });
34236
34255
  if (artifact) {
34237
34256
  const publication = artifact.kind === "file" ? { artifactId: artifact.artifact_id, kind: artifact.kind, title: artifact.filename } : { artifactId: artifact.artifact_id, kind: artifact.kind, title: artifact.title, url: artifact.url };
@@ -34319,6 +34338,24 @@ function projectSessionMessageTurnAssociated({ state, event }) {
34319
34338
  };
34320
34339
  return { ...state, messageTurns: { ...state.messageTurns, [event.payload.messageId]: nextTurn } };
34321
34340
  }
34341
+ function projectSessionMessageDispatch({ state, event, occurredAt, retainedEventId }) {
34342
+ if (event.type === "session.message.dispatched")
34343
+ return state;
34344
+ const withdrawn = event.type === "session.message.withdrawn";
34345
+ const outcome = withdrawn ? "cancelled" : "failed";
34346
+ return appendActivity({
34347
+ state: {
34348
+ ...state,
34349
+ messageTurns: {
34350
+ ...state.messageTurns,
34351
+ [event.payload.messageId]: { commandId: event.payload.commandId, turnId: null, outcome }
34352
+ }
34353
+ },
34354
+ occurredAt,
34355
+ retainedEventId,
34356
+ card: withdrawn ? { kind: "lifecycle", weight: "signal", title: "Message withdrawn", summary: "Message was withdrawn before reaching Remy." } : { kind: "failure", weight: "signal", title: "Message failed", summary: "Message failed before reaching Remy." }
34357
+ });
34358
+ }
34322
34359
  function projectSessionWorkspaceGitInitialized({ state, event, occurredAt, retainedEventId }) {
34323
34360
  return appendActivity({
34324
34361
  state,
@@ -36910,6 +36947,19 @@ async function createNewSessionWizard({
36910
36947
  overrides.delete(repositoryId);
36911
36948
  else
36912
36949
  overrides.set(repositoryId, isSelected);
36950
+ }, branchOverridesForSelection = function() {
36951
+ return [...selectedBranches].map(([repositoryId, branchName]) => ({ repositoryId, branchName }));
36952
+ }, branchOptions = function() {
36953
+ return [...selectedRepositoryIds()].flatMap((repositoryId) => {
36954
+ const existing = branchSuggestions.filter((suggestion) => suggestion.repositoryId === repositoryId && suggestion.suggestionKind !== "createSessionBranch");
36955
+ return [...existing, { suggestionKind: "createSessionBranch", repositoryId, branchName: null, pullRequest: null }];
36956
+ });
36957
+ }, selectBranchOption = function() {
36958
+ const option = branchOptions()[branchOptionIndex];
36959
+ if (option.branchName === null)
36960
+ selectedBranches.delete(option.repositoryId);
36961
+ else
36962
+ selectedBranches.set(option.repositoryId, option.branchName);
36913
36963
  }, renderRepositoryLoadingSkeleton = function() {
36914
36964
  return new StyledText5([
36915
36965
  dim4(fg6(PALETTE.dimText)(`\u283F \u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588
@@ -36922,7 +36972,7 @@ async function createNewSessionWizard({
36922
36972
  const orient = (body) => joinStyled([renderStepIndicator({
36923
36973
  step,
36924
36974
  hasInstallationChoice: installationIds.length > 1,
36925
- hasBranchChoice: step === "loadingBranches" || branchSuggestions.some((suggestion) => suggestion.suggestionKind !== "createSessionBranch")
36975
+ hasBranchChoice: step === "loadingBranches" || step === "branchError" || branchSuggestions.some((suggestion) => suggestion.suggestionKind !== "createSessionBranch")
36926
36976
  }), body], `
36927
36977
  `);
36928
36978
  if (composerVisible && !composerMounted) {
@@ -36998,31 +37048,39 @@ async function createNewSessionWizard({
36998
37048
  } else if (step === "loadingBranches") {
36999
37049
  content.content = orient(joinStyled([
37000
37050
  new StyledText5([stepHeader("Choose branches")]),
37001
- new StyledText5([fg6(PALETTE.progress)(`${suggestionSpinnerFrames[suggestionSpinnerFrame]} Remy is checking for related open pull requests\u2026`)]),
37051
+ new StyledText5([fg6(PALETTE.progress)(`${suggestionSpinnerFrames[suggestionSpinnerFrame]} Remy is analyzing session, PR, and branch references\u2026`)]),
37002
37052
  new StyledText5([dim4(fg6(PALETTE.dimText)("This can take a few seconds."))]),
37003
37053
  stringToStyledText4("esc back")
37004
37054
  ], `
37005
37055
 
37056
+ `));
37057
+ } else if (step === "branchError") {
37058
+ content.content = orient(joinStyled([
37059
+ new StyledText5([stepHeader("Branch lookup failed")]),
37060
+ stringToStyledText4(status),
37061
+ stringToStyledText4("r retry \xB7 n explicitly choose new branches \xB7 esc back")
37062
+ ], `
37063
+
37006
37064
  `));
37007
37065
  } else if (step === "branches") {
37008
- const existing = branchSuggestions.filter((suggestion) => suggestion.suggestionKind !== "createSessionBranch");
37009
- const parts = [new StyledText5([stepHeader("Choose branches")])];
37010
- if (existing.length > 0) {
37011
- parts.push(stringToStyledText4("Remy found related open pull-request work:"));
37012
- for (const suggestion of existing) {
37013
- const repository = installationRepositories().find((candidate) => candidate.id === suggestion.repositoryId);
37014
- parts.push(stringToStyledText4(`${repository?.fullName ?? suggestion.repositoryId} \u2014 ${suggestion.branchName}${suggestion.pullRequest ? ` (PR #${suggestion.pullRequest.number}: ${suggestion.pullRequest.title})` : ""}`));
37015
- }
37016
- parts.push(new StyledText5(renderSelectableRow({ label: "Continue from the suggested branch", isCursor: branchChoice === "existing" })));
37017
- parts.push(new StyledText5(renderSelectableRow({ label: "Create a new session branch", isCursor: branchChoice === "new" })));
37018
- parts.push(stringToStyledText4("\u2191\u2193 choose \xB7 \u23CE continue \xB7 esc back"));
37019
- } else {
37020
- parts.push(stringToStyledText4("Remy recommends creating a new session branch."));
37021
- parts.push(new StyledText5([dim4(fg6(PALETTE.dimText)(status || "No related open pull request was identified from your request."))]));
37022
- parts.push(stringToStyledText4("\u23CE continue \xB7 esc back"));
37066
+ const options = branchOptions();
37067
+ const visibleCount = Math.max(2, renderer.height - 12);
37068
+ const start = Math.max(0, Math.min(branchOptionIndex - Math.floor(visibleCount / 2), options.length - visibleCount));
37069
+ const parts = [
37070
+ new StyledText5([stepHeader("Choose branches")]),
37071
+ stringToStyledText4("Continue from the suggested branch, or choose new work for each repository:")
37072
+ ];
37073
+ for (const [index, option] of options.slice(start, start + visibleCount).entries()) {
37074
+ const repository = installationRepositories().find((repository2) => repository2.id === option.repositoryId);
37075
+ const selected = (selectedBranches.get(option.repositoryId) ?? null) === option.branchName;
37076
+ const label = option.branchName === null ? "Create a new session branch" : `${option.branchName}${option.pullRequest ? ` (PR #${option.pullRequest.number}: ${option.pullRequest.title})` : ""}`;
37077
+ parts.push(new StyledText5(renderSelectableRow({
37078
+ label: `${selected ? "\u25CF" : "\u25CB"} ${repository?.fullName ?? option.repositoryId} \u2014 ${label}`,
37079
+ isCursor: start + index === branchOptionIndex
37080
+ })));
37023
37081
  }
37082
+ parts.push(stringToStyledText4(`\u2191\u2193 move \xB7 space select \xB7 \u23CE select & review \xB7 esc back (${branchOptionIndex + 1}/${options.length})`));
37024
37083
  content.content = orient(joinStyled(parts, `
37025
-
37026
37084
  `));
37027
37085
  } else if (repositoryListVisible) {
37028
37086
  const selectionOverrides = searchSelections ?? manualSelections;
@@ -37067,13 +37125,13 @@ async function createNewSessionWizard({
37067
37125
  editor.placeholder = "e.g. worker, migration, dashboard";
37068
37126
  } else {
37069
37127
  const selected = installationRepositories().filter((repository) => selectedRepositoryIds().has(repository.id));
37070
- const branchOverrides = branchChoice === "existing" ? branchSuggestions.filter((suggestion) => suggestion.suggestionKind !== "createSessionBranch") : [];
37128
+ const branchOverrides = branchOverridesForSelection();
37071
37129
  const meta5 = new StyledText5([
37072
37130
  fg6(PALETTE.bodyText)(`Installation: ${selectedInstallationId() ?? "(missing)"}
37073
37131
  `),
37074
37132
  fg6(PALETTE.bodyText)(`Repositories: ${selected.map((repository) => repository.fullName).join(", ") || "(none)"}
37075
37133
  `),
37076
- fg6(PALETTE.bodyText)(`Branches: ${branchOverrides.length > 0 ? branchOverrides.map((override) => override.branchName).join(", ") : "new session branches"}
37134
+ fg6(PALETTE.bodyText)(`Branches: ${branchOverrides.length > 0 ? selected.map((repository) => `${repository.fullName}: ${selectedBranches.get(repository.id) ?? "new session branch"}`).join(", ") : "new session branches"}
37077
37135
  `),
37078
37136
  fg6(PALETTE.bodyText)(`Model: ${newSessionModelLabel(model)} \xB7 ${newSessionReasoningEffortLabel(reasoningEffort)} reasoning`),
37079
37137
  dim4(fg6(PALETTE.dimText)(" \u25B8 m model \xB7 \u2190\u2192 reasoning"))
@@ -37086,7 +37144,7 @@ async function createNewSessionWizard({
37086
37144
  ];
37087
37145
  if (attachmentText.chunks.length > 0)
37088
37146
  parts.push(attachmentText);
37089
- parts.push(new StyledText5([dim4(fg6(PALETTE.dimText)(branchOverrides.length > 0 ? "Remy will continue on the selected existing branch and update its pull request; you land in the session view." : "Remy will clone the selected repositories, work on new session branches, and open a pull request for each repository; you land in the session view."))]));
37147
+ parts.push(new StyledText5([dim4(fg6(PALETTE.dimText)(branchOverrides.length > 0 ? "Remy will continue on the selected branches and create new branches for other repositories; you land in the session view." : "Remy will clone the selected repositories, work on new session branches, and open a pull request for each repository; you land in the session view."))]));
37090
37148
  parts.push(stringToStyledText4(branchSuggestions.some((suggestion) => suggestion.suggestionKind !== "createSessionBranch") ? "\u23CE create \xB7 e edit prompt \xB7 r repositories \xB7 b branches \xB7 esc back" : "\u23CE create \xB7 e edit prompt \xB7 r repositories \xB7 esc back"));
37091
37149
  if (status)
37092
37150
  parts.push(stringToStyledText4(status));
@@ -37219,7 +37277,7 @@ async function createNewSessionWizard({
37219
37277
  returnToPromptFromRepositoryLoading();
37220
37278
  return;
37221
37279
  }
37222
- if (step === "loadingBranches" || step === "branches") {
37280
+ if (step === "loadingBranches" || step === "branches" || step === "branchError") {
37223
37281
  branchRequestGeneration += 1;
37224
37282
  step = "repositories";
37225
37283
  render();
@@ -37329,6 +37387,17 @@ async function createNewSessionWizard({
37329
37387
  return;
37330
37388
  }
37331
37389
  }
37390
+ if (step === "branchError" && (key.name === "r" || key.name === "n")) {
37391
+ key.preventDefault();
37392
+ if (key.name === "r") {
37393
+ startBranchReview();
37394
+ } else {
37395
+ status = "";
37396
+ step = "confirmation";
37397
+ render();
37398
+ }
37399
+ return;
37400
+ }
37332
37401
  if (step === "repositorySearch")
37333
37402
  return;
37334
37403
  if (step === "loadingSuggestions" && key.name === "s") {
@@ -37348,15 +37417,23 @@ async function createNewSessionWizard({
37348
37417
  return;
37349
37418
  }
37350
37419
  }
37420
+ if (step === "branches" && key.name === "space") {
37421
+ key.preventDefault();
37422
+ selectBranchOption();
37423
+ render();
37424
+ return;
37425
+ }
37351
37426
  if (step === "branches" && branchSuggestions.some((suggestion) => suggestion.suggestionKind !== "createSessionBranch") && (key.name === "up" || key.name === "down" || key.name === "left" || key.name === "right")) {
37352
37427
  key.preventDefault();
37353
- branchChoice = branchChoice === "existing" ? "new" : "existing";
37428
+ const options = branchOptions();
37429
+ const direction = key.name === "up" || key.name === "left" ? -1 : 1;
37430
+ branchOptionIndex = (branchOptionIndex + direction + options.length) % options.length;
37354
37431
  render();
37355
37432
  return;
37356
37433
  }
37357
37434
  if (!composerMounted && (key.name === "return" || key.name === "enter")) {
37358
37435
  key.preventDefault();
37359
- if (step === "loadingBranches")
37436
+ if (step === "loadingBranches" || step === "branchError")
37360
37437
  return;
37361
37438
  submitEditor();
37362
37439
  return;
@@ -37475,7 +37552,8 @@ async function createNewSessionWizard({
37475
37552
  branchName: override.branchName,
37476
37553
  pullRequest: null
37477
37554
  })) ?? [];
37478
- let branchChoice = initialDraft?.repositoryBranchOverrides?.length ? "existing" : "new";
37555
+ const selectedBranches = new Map(initialDraft?.repositoryBranchOverrides?.map((override) => [override.repositoryId, override.branchName]));
37556
+ let branchOptionIndex = 0;
37479
37557
  let status = initialError ?? "";
37480
37558
  let attachmentFeedback;
37481
37559
  let pendingPastedImageWrites = 0;
@@ -37550,9 +37628,16 @@ async function createNewSessionWizard({
37550
37628
  if (!installationId)
37551
37629
  return;
37552
37630
  const repositoryIds = [...selectedRepositoryIds()];
37631
+ if (repositoryIds.length === 0) {
37632
+ branchSuggestions = [];
37633
+ selectedBranches.clear();
37634
+ step = "confirmation";
37635
+ render();
37636
+ return;
37637
+ }
37553
37638
  const requestGeneration = ++branchRequestGeneration;
37554
37639
  branchSuggestions = [];
37555
- branchChoice = "new";
37640
+ selectedBranches.clear();
37556
37641
  step = "loadingBranches";
37557
37642
  status = "";
37558
37643
  render();
@@ -37562,15 +37647,19 @@ async function createNewSessionWizard({
37562
37647
  return;
37563
37648
  branchSuggestions = suggestions;
37564
37649
  const hasExistingBranch = branchSuggestions.some((suggestion) => suggestion.suggestionKind !== "createSessionBranch");
37565
- branchChoice = hasExistingBranch ? "existing" : "new";
37650
+ for (const suggestion of branchSuggestions) {
37651
+ if (suggestion.suggestionKind !== "createSessionBranch" && !selectedBranches.has(suggestion.repositoryId))
37652
+ selectedBranches.set(suggestion.repositoryId, suggestion.branchName);
37653
+ }
37654
+ branchOptionIndex = 0;
37566
37655
  step = hasExistingBranch ? "branches" : "confirmation";
37567
37656
  } catch (error93) {
37568
37657
  if (destroyed || requestGeneration !== branchRequestGeneration || step !== "loadingBranches")
37569
37658
  return;
37570
37659
  branchSuggestions = [];
37571
- branchChoice = "new";
37660
+ selectedBranches.clear();
37572
37661
  status = error93 instanceof Error ? error93.message : String(error93);
37573
- step = "confirmation";
37662
+ step = "branchError";
37574
37663
  }
37575
37664
  render();
37576
37665
  }
@@ -37643,7 +37732,7 @@ async function createNewSessionWizard({
37643
37732
  fail(new Error("Selected repositories must belong to the chosen GitHub installation."));
37644
37733
  return;
37645
37734
  }
37646
- const repositoryBranchOverrides = branchChoice === "existing" ? branchSuggestions.flatMap((suggestion) => suggestion.suggestionKind === "createSessionBranch" ? [] : [{ repositoryId: suggestion.repositoryId, branchName: suggestion.branchName }]) : [];
37735
+ const repositoryBranchOverrides = branchOverridesForSelection();
37647
37736
  const confirmation = Symbol("confirmation");
37648
37737
  const confirmedAttachments = [...attachments];
37649
37738
  const confirmedPrompt = prompt;
@@ -37730,6 +37819,7 @@ async function createNewSessionWizard({
37730
37819
  return;
37731
37820
  }
37732
37821
  if (step === "branches") {
37822
+ selectBranchOption();
37733
37823
  step = "confirmation";
37734
37824
  render();
37735
37825
  return;
@@ -37845,7 +37935,7 @@ function wizardStepKey(step) {
37845
37935
  return "describe";
37846
37936
  if (step === "installation")
37847
37937
  return "installation";
37848
- if (step === "loadingBranches" || step === "branches")
37938
+ if (step === "loadingBranches" || step === "branches" || step === "branchError")
37849
37939
  return "branches";
37850
37940
  if (step === "confirmation")
37851
37941
  return "confirm";
@@ -39405,7 +39495,7 @@ var compactMarkRows = 9;
39405
39495
  var compactMinWidth = 48;
39406
39496
  var compactMinHeight = 20;
39407
39497
  var markBrightnessGain = 4.2;
39408
- var remyCliVersion = "1.14.0";
39498
+ var remyCliVersion = "1.15.0";
39409
39499
  async function showRemySplash({
39410
39500
  createRenderer = createRemyRenderer,
39411
39501
  durationMs = splashDurationMs,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@meistrari/remy-cli",
3
- "version": "1.14.0",
3
+ "version": "1.15.0",
4
4
  "description": "Remy, the Coding Agent terminal client.",
5
5
  "type": "module",
6
6
  "bin": {