@meistrari/remy-cli 1.26.0-rc.1 → 1.26.0-rc.3

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 CHANGED
@@ -50,7 +50,7 @@ Help, version, sign-in/out, direct session commands, and redirected/noninteracti
50
50
 
51
51
  ## Your everyday workflow
52
52
 
53
- The dashboard is the starting point for all interactive work. It refreshes the visible session page every 10 seconds, so new sessions and status changes appear while you keep it open. If an update fails, Remy keeps showing the last successful list and retries on the next interval.
53
+ The dashboard is the starting point for all interactive work. It refreshes the visible session page every 10 seconds, so new sessions and status changes appear while you keep it open. If an update fails, Remy keeps showing the last successful list and retries on the next interval. Each session shows its creator and where it started, such as `Slack #team-channel`, `Linear ENG-123`, or `CLI`.
54
54
 
55
55
  ### Start work
56
56
 
@@ -70,7 +70,7 @@ The new-session request and conversation composers share path completion and att
70
70
 
71
71
  Terminal follow-ups default to **Steer**, targeting the work currently in progress. Press `Ctrl+Enter` to queue a message as **Next**, which waits for current work to finish. Plain `Enter` continues to send as Steer. Failed submissions retain their mode, attachments, settings, and idempotency key when retried with `Ctrl+R`. 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.
72
72
 
73
- Use Up/Down to select a session in the dashboard, Left/Right to load the adjacent page, and `Enter` to open it. Remy shows the session header and composer immediately after session details load, while retained conversation history loads in the background. You can start drafting immediately; sending is paused until history finishes, and your draft stays intact. New activity then streams as it arrives. Press `s` to fuzzy-search all accessible sessions through the API by author, repository, branch name, pull request title/number, or session number/ID/title; `Enter` applies immediately and keeps the search active; `Esc` clears it. Typing refreshes results after a short pause. Matching ignores case and query whitespace and finds characters in order within a field (for example, `grch` matches `Grace Hopper`); numbers also accept `#`. Search combines with your other filters and stays active across pages. Session rows and compact cards show the repository and session work branch (`Branch pending` when unassigned). Press `f` to filter sessions by lifecycle status, `a` by author, or `r` by repository. These 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 a 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. Press `b` to filter by a case-insensitive part of a branch name; Enter applies it, an empty value clears it, and Esc discards edits. Repository and branch filters must match the same repository in a session. 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. `Cmd+Left`/`Cmd+Right` move to the start or end of the current line, as do `Home`/`End`, which many macOS terminals send for those keys; `Ctrl+D` deletes the character after the cursor. In the session view, `Ctrl+C` first clears a non-empty draft; press it again with an empty composer to exit. The conversation header keeps the numbered session title on its first line and repository, pull request, work state, elapsed time, connection state, and the agent's current `Harness · Model · Effort` 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.
73
+ Use Up/Down to select a session in the dashboard, Left/Right to load the adjacent page, and `Enter` to open it. Remy shows the session header and composer immediately after session details load, while retained conversation history loads in the background. You can start drafting immediately; sending is paused until history finishes, and your draft stays intact. New activity then streams as it arrives. Press `s` to fuzzy-search all accessible sessions through the API by author, repository, branch name, pull request title/number, or session number/ID/title; `Enter` applies immediately and keeps the search active; `Esc` clears it. Typing refreshes results after a short pause. Matching ignores case and query whitespace and finds characters in order within a field (for example, `grch` matches `Grace Hopper`); numbers also accept `#`. Search combines with your other filters and stays active across pages. Session rows and compact cards show the repository and session work branch (`Branch pending` when unassigned). Press `f` to filter sessions by lifecycle status, `a` by author, or `r` by repository. These 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 a 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. Press `b` to filter by a case-insensitive part of a branch name; Enter applies it, an empty value clears it, and Esc discards edits. Repository and branch filters must match the same repository in a session. 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. `Cmd+Left`/`Cmd+Right` move to the start or end of the current line, as do `Home`/`End`, which many macOS terminals send for those keys; `Ctrl+D` deletes the character after the cursor. In the session view, `Ctrl+C` first clears a non-empty draft; press it again with an empty composer to exit. The conversation header keeps the numbered session title on its first line and repository, pull request, work state, elapsed time, connection state, and the agent's current `Harness · Model · Effort` on its second line. A session connected to a Linear issue also shows that connection and its status there, such as `Connected to Linear · ENG-123 (Connected)`; the status is `Connecting` while Remy links the session to the issue and `Closed` after the session ends. The connection label links to the issue in terminals that support hyperlinks, and `/links` lists the issue URL. 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.
74
74
 
75
75
  If a connected session loses its activity stream, Remy retries for up to two minutes and resumes from the last received event. After the live stream stays connected for at least 30 seconds, the next disconnect starts a fresh retry window. Connections that drop sooner share the existing window and backoff. While a submitted message is still awaiting its outcome, retries continue beyond that window.
76
76
 
@@ -82,7 +82,7 @@ Published files and Tela Pages appear in the timeline. File artifacts include th
82
82
 
83
83
  Your messages and Remy's render as Markdown: headings, bold, italic, strikethrough, inline and fenced code, lists and task lists, quotes, tables, and links show formatted, with their syntax markers hidden. A Markdown link shows its label; a target that is not a plain HTTP or HTTPS URL stays visible as the original source text. The live assistant preview shows raw text until the finished message arrives, and a message with expanded workspace context shows its original text.
84
84
 
85
- **Open links:** Ctrl+click an HTTP or HTTPS link in the conversation, including Markdown links and expanded activity links. Ordinary clicks and drag-to-copy keep their existing behavior. Terminals may reserve that gesture or use their own modifier for hyperlinks; `/links` or `Ctrl+L` provides a keyboard alternative. Select with arrows or `j`/`k`, press `Enter` to open the browser, or `c` to copy the complete URL. Browser opening uses the machine running Remy.
85
+ **Open links:** Ctrl+click an HTTP or HTTPS link in the conversation, including Markdown links and expanded activity links. Ordinary clicks and drag-to-copy keep their existing behavior. Terminals may reserve that gesture or use their own modifier for hyperlinks; `/links` or `Ctrl+L` provides a keyboard alternative; for a session connected to a Linear issue, the issue comes first. Select with arrows or `j`/`k`, press `Enter` to open the browser, or `c` to copy the complete URL. Browser opening uses the machine running Remy.
86
86
 
87
87
  **Download files:** `/files` or `Ctrl+F` opens a session file picker, newest first, containing Remy’s published artifacts and attachments sent by everyone in that session, with author/source labels. Repeated updates to an artifact appear once, using its newest title and URL. Select with arrows or `j`/`k`; `Enter` (or `d`) downloads to `~/Downloads`, creating that directory if needed. Remy shows progress and the full saved path. Existing files are preserved: another `report.txt` becomes `report (1).txt`. Press `v` to open the selected item in Remy Viewer. Press `o` for the Web preview or `c` to copy its URL; previews use your browser sign-in. Tela Pages open their canonical URL instead of downloading. The picker also works in closed sessions. `Esc` cancels an unfinished download and returns to the conversation with your draft intact, without stopping Remy. Errors stay visible for an explicit retry, which requests fresh download authorization. Files are saved without executing or extracting them. This picker covers published files and message attachments; embedded tool-output media remains available through **View event in Web**.
88
88
 
package/dist/remy.js CHANGED
@@ -34274,7 +34274,7 @@ var sessionMessageSchema = exports_external.strictObject({
34274
34274
  metadata: jsonObjectSchema,
34275
34275
  created_at: exports_external.iso.datetime()
34276
34276
  });
34277
- var sessionConnectionSchema = exports_external.discriminatedUnion("status", [
34277
+ var slackSessionConnectionSchema = exports_external.discriminatedUnion("status", [
34278
34278
  exports_external.strictObject({
34279
34279
  provider: exports_external.literal("slack"),
34280
34280
  status: exports_external.literal("establishing"),
@@ -34302,6 +34302,16 @@ var sessionConnectionSchema = exports_external.discriminatedUnion("status", [
34302
34302
  target: exports_external.strictObject({ channel_id: exports_external.string().min(1), thread_ts: exports_external.string().min(1) })
34303
34303
  })
34304
34304
  ]);
34305
+ var linearSessionConnectionSchema = exports_external.strictObject({
34306
+ provider: exports_external.literal("linear"),
34307
+ status: exports_external.enum(["establishing", "active", "closed"]),
34308
+ label: exports_external.string().min(1),
34309
+ url: exports_external.url()
34310
+ });
34311
+ var sessionConnectionSchema = exports_external.discriminatedUnion("provider", [
34312
+ slackSessionConnectionSchema,
34313
+ linearSessionConnectionSchema
34314
+ ]);
34305
34315
  var createSessionAgentInputSchema = exports_external.strictObject({
34306
34316
  provider: agentProviderIdSchema,
34307
34317
  model: exports_external.string().min(1).optional(),
@@ -34377,7 +34387,7 @@ var sessionDetailResponseSchema = exports_external.object({
34377
34387
  }, "Session Web URL must not contain credentials.").optional(),
34378
34388
  title: exports_external.string().nullable(),
34379
34389
  status: sessionStatusSchema,
34380
- source: exports_external.object({ provider: exports_external.enum(["slack", "web", "cli", "api"]) }).passthrough().optional(),
34390
+ source: exports_external.object({ provider: exports_external.enum(["slack", "web", "cli", "api", "linear"]) }).passthrough().optional(),
34381
34391
  session_number: exports_external.number().int().positive(),
34382
34392
  agent_status: exports_external.string().min(1),
34383
34393
  pull_requests: exports_external.array(exports_external.object({
@@ -34417,7 +34427,8 @@ var sessionSourceSchema = exports_external.discriminatedUnion("provider", [
34417
34427
  }),
34418
34428
  exports_external.object({ provider: exports_external.literal("web"), label: exports_external.string().nullable(), url: exports_external.string().nullable() }),
34419
34429
  exports_external.object({ provider: exports_external.literal("api"), label: exports_external.string().nullable(), url: exports_external.string().nullable() }),
34420
- exports_external.object({ provider: exports_external.literal("cli"), label: exports_external.null(), url: exports_external.null() })
34430
+ exports_external.object({ provider: exports_external.literal("cli"), label: exports_external.null(), url: exports_external.null() }),
34431
+ exports_external.object({ provider: exports_external.literal("linear"), label: exports_external.string().nullable(), url: exports_external.string().nullable() })
34421
34432
  ]);
34422
34433
  var sessionCreatorSchema = exports_external.union([
34423
34434
  exports_external.object({ type: exports_external.literal("user"), id: exports_external.string(), status: exports_external.literal("active"), name: exports_external.string(), avatar_url: exports_external.string().nullable() }),
@@ -34650,6 +34661,8 @@ function sessionSourceLabel(source) {
34650
34661
  return `Slack ${source.label.startsWith("#") ? source.label : `#${source.label}`}`;
34651
34662
  if (source.provider === "api")
34652
34663
  return source.label ?? "API";
34664
+ if (source.provider === "linear")
34665
+ return source.label ? `Linear ${source.label}` : "Linear";
34653
34666
  return source.provider === "web" ? "Web" : "CLI";
34654
34667
  }
34655
34668
  function sessionCreatorLabel(creator) {
@@ -35039,7 +35052,7 @@ function formatSessionJson({
35039
35052
  `;
35040
35053
  }
35041
35054
  // src/version.ts
35042
- var remyCliVersion = "1.26.0-rc.1";
35055
+ var remyCliVersion = "1.26.0-rc.3";
35043
35056
 
35044
35057
  // src/self-update.ts
35045
35058
  import { spawn as spawn2 } from "child_process";
@@ -35416,7 +35429,7 @@ var sessionMessageCreatedEventSchema = exports_external.object({
35416
35429
  }).passthrough()
35417
35430
  ]),
35418
35431
  source: exports_external.object({
35419
- provider: exports_external.enum(["slack", "web", "api", "cli"]),
35432
+ provider: exports_external.enum(["slack", "web", "api", "cli", "linear"]),
35420
35433
  label: exports_external.string().nullable()
35421
35434
  }).passthrough()
35422
35435
  }).passthrough()
@@ -35849,7 +35862,8 @@ var MESSAGE_SOURCE_LABEL = {
35849
35862
  slack: "Slack",
35850
35863
  web: "Web",
35851
35864
  api: "API",
35852
- cli: "CLI"
35865
+ cli: "CLI",
35866
+ linear: "Linear"
35853
35867
  };
35854
35868
  function messageSourceLabel(provider) {
35855
35869
  return MESSAGE_SOURCE_LABEL[provider];
@@ -36709,7 +36723,20 @@ function toSessionAgentPendingSettings(pending) {
36709
36723
  return pending ? { model: pending.model, reasoningEffort: pending.reasoning_effort, messageId: pending.message_id } : null;
36710
36724
  }
36711
36725
  function toConnectionPreviews(detail) {
36712
- return detail.connections.map((connection) => ({ provider: connection.provider, status: connection.status }));
36726
+ return [...detail.connections];
36727
+ }
36728
+ var LINEAR_CONNECTION_STATUS_LABEL = {
36729
+ establishing: "Connecting",
36730
+ active: "Connected",
36731
+ closed: "Closed"
36732
+ };
36733
+ function sessionLinearConnectionSummary(state) {
36734
+ const connection = state.connectionPreviews.find((candidate) => candidate.provider === "linear");
36735
+ return connection ? {
36736
+ label: `Connected to Linear \xB7 ${connection.label}`,
36737
+ status: LINEAR_CONNECTION_STATUS_LABEL[connection.status],
36738
+ url: connection.url
36739
+ } : null;
36713
36740
  }
36714
36741
  function toSessionPullRequest(detail) {
36715
36742
  const pullRequest = detail.pull_requests[0];
@@ -44047,14 +44074,18 @@ ${segment.excerpt}`).join(`
44047
44074
  }
44048
44075
  renderer.requestRender();
44049
44076
  }, resourceChoices = function() {
44050
- if (resourceCache?.transcript === latestState.transcript && resourceCache.webUrl === latestState.webUrl && resourceCache.mode === resourceMode)
44077
+ if (resourceCache?.transcript === latestState.transcript && resourceCache.webUrl === latestState.webUrl && resourceCache.connections === latestState.connectionPreviews && resourceCache.mode === resourceMode) {
44051
44078
  return resourceCache.choices;
44079
+ }
44052
44080
  const choices = resourceMode === "files" ? sessionFileChoices(latestState) : conversationLinkChoices();
44053
- resourceCache = { transcript: latestState.transcript, webUrl: latestState.webUrl, mode: resourceMode, choices };
44081
+ resourceCache = { transcript: latestState.transcript, webUrl: latestState.webUrl, connections: latestState.connectionPreviews, mode: resourceMode, choices };
44054
44082
  return choices;
44055
44083
  }, conversationLinkChoices = function() {
44056
44084
  const content2 = linkifyText(renderTimeline({ state: latestState, activityExpanded: true }));
44057
44085
  const urls = new Map;
44086
+ const linearConnection = sessionLinearConnectionSummary(latestState);
44087
+ if (linearConnection && browserLink(linearConnection.url))
44088
+ urls.set(linearConnection.url, { key: linearConnection.url, label: linearConnection.label, description: linearConnection.url, viewerSelection: null, previewUrl: linearConnection.url, download: undefined });
44058
44089
  for (const chunk of content2.chunks) {
44059
44090
  const url3 = chunk.link?.url;
44060
44091
  if (url3 && !urls.has(url3))
@@ -45210,6 +45241,8 @@ function renderStatusBand({ state, working, elapsedMs, stopState, lifecycleReque
45210
45241
  const presentation = pendingOperation ? { label: lifecycleOperationPresentParticiple(pendingOperation), color: PALETTE.approvalQuestion } : stopping ? { label: "Stopping", color: PALETTE.approvalQuestion } : sessionViewStatePresentation({ aggregateStatus: state.aggregateStatus, isWorking: working });
45211
45242
  const elapsed = (working || stopping) && elapsedMs !== undefined && elapsedMs > 0 ? ` ${formatElapsed(elapsedMs)}` : "";
45212
45243
  const connection = state.connectionStatus === "connected" ? new StyledText11([fg12(PALETTE.statusCompleted)("\u25CF "), dim7(fg12(PALETTE.dimText)("connected"))]) : new StyledText11([fg12(PALETTE.approvalQuestion)("\u25CF reconnecting\u2026")]);
45244
+ const linearConnection = sessionLinearConnectionSummary(state);
45245
+ const linearConnectionLink = linearConnection ? browserLink(linearConnection.url) : undefined;
45213
45246
  const sessionLabel = state.sessionNumber !== undefined ? `#${state.sessionNumber}` : state.sessionId;
45214
45247
  const pullRequest = state.pullRequest;
45215
45248
  const contextStatus = renderContextStatus(state.context.snapshot);
@@ -45219,6 +45252,10 @@ function renderStatusBand({ state, working, elapsedMs, stopState, lifecycleReque
45219
45252
  ...pullRequest ? [[bold5(fg12(statusColor(pullRequest.status))(`PR#${pullRequest.number}`))]] : [],
45220
45253
  [bold5(fg12(presentation.color)(`${presentation.label}${elapsed}`))],
45221
45254
  connection.chunks,
45255
+ ...linearConnection ? [[
45256
+ linearConnectionLink ? fg12(PALETTE.bodyText)(link2(linearConnectionLink)(terminalSafeText(linearConnection.label))) : fg12(PALETTE.bodyText)(terminalSafeText(linearConnection.label)),
45257
+ dim7(fg12(PALETTE.dimText)(` (${linearConnection.status})`))
45258
+ ]] : [],
45222
45259
  ...agentSettings ? [agentSettings.chunks] : [],
45223
45260
  ...contextStatus ? [[dim7(fg12(PALETTE.dimText)(contextStatus))]] : []
45224
45261
  ];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@meistrari/remy-cli",
3
- "version": "1.26.0-rc.1",
3
+ "version": "1.26.0-rc.3",
4
4
  "description": "Remy, the Coding Agent terminal client.",
5
5
  "type": "module",
6
6
  "bin": {