@meistrari/remy-cli 1.14.1 → 1.16.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 +6 -1
  2. package/dist/remy.js +245 -74
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -36,7 +36,7 @@ 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
 
@@ -54,6 +54,8 @@ Published files and Tela Pages appear in the timeline. File artifacts include th
54
54
 
55
55
  When Remy creates a plan, the session shows its checklist in the timeline and keeps `Plan <done>/<total>` with the current item pinned above the composer. Updates change the same checklist instead of producing repeated rows, and an unfinished plan remains visible after reconnecting or between turns. The collapsed timeline shows up to five plan items; press `Ctrl+O` for the complete checklist and activity detail.
56
56
 
57
+ Enter `/compact` to admit a durable main-thread context compaction control without sending a human message. Remy reports request admission immediately and shows the eventual completed, no-op, failed, or unknown provider result in retained activity. Compaction waits for a safe point and does not interrupt active work or jump ahead of an earlier Next message.
58
+
57
59
  Drag to select visible text in any Remy view; Remy copies it to the local clipboard and emits OSC 52 for terminal or remote-session clipboard support, then clears the selection highlight. Published file artifacts show their filename and muted, full web preview URL; open the URL in a browser to select that artifact in its session. Tela Page rows retain their canonical Page URL. Remy does not fetch or print artifact bytes. When the conversation has focus, press `Tab` to return to the composer.
58
60
 
59
61
  | Control | Result |
@@ -61,6 +63,7 @@ Drag to select visible text in any Remy view; Remy copies it to the local clipbo
61
63
  | `Esc` | Interrupt the active turn; the session stays open. |
62
64
  | `/complete` | Complete an open session after its active turn stops. |
63
65
  | `/cancel` | Cancel the current session, including an active turn. |
66
+ | `/compact` | Admit a main-thread context compaction request without sending a message; the provider result appears in retained activity. |
64
67
  | `/sessions` | Return to the dashboard. |
65
68
  | `/new` | Start another new-session flow. |
66
69
  | `/logout` | Sign out of Remy after confirmation. |
@@ -91,6 +94,8 @@ remy new --repository owner/repository "Add a health check endpoint"
91
94
 
92
95
  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
96
 
97
+ The branch-suggestion flow belongs to the interactive new-session wizard (`remy`, then `n`). Direct `remy new` creation does not analyze continuation references.
98
+
94
99
  ### Open a known session
95
100
 
96
101
  ```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,
@@ -32202,6 +32214,10 @@ var interruptAgentCommandSchema = runningCommandBaseSchema.extend({
32202
32214
  turnId: zod_default2.string().min(1).optional(),
32203
32215
  reason: zod_default2.string().min(1).optional()
32204
32216
  }).strict();
32217
+ var compactContextAgentCommandSchema = runningCommandBaseSchema.extend({
32218
+ type: zod_default2.literal("agent.compact-context"),
32219
+ commandId: commandIdSchema
32220
+ }).strict();
32205
32221
  var stopAgentCommandSchema = runningCommandBaseSchema.extend({
32206
32222
  type: zod_default2.literal("agent.stop"),
32207
32223
  reason: zod_default2.string().min(1).optional()
@@ -32215,6 +32231,7 @@ var respondUserInputAgentCommandSchema = runningCommandBaseSchema.extend({
32215
32231
  var agentCommandSchema = zod_default2.union([
32216
32232
  sendPromptCommandSchema,
32217
32233
  interruptAgentCommandSchema,
32234
+ compactContextAgentCommandSchema,
32218
32235
  stopAgentCommandSchema,
32219
32236
  respondUserInputAgentCommandSchema
32220
32237
  ]);
@@ -32408,6 +32425,12 @@ var agentTurnEndStatusSchema = zod_default2.enum(["completed", "failed", "cancel
32408
32425
  var agentSubagentStatusSchema = zod_default2.enum(["completed", "failed", "cancelled"]);
32409
32426
  var agentContextCompactionTriggerSchema = zod_default2.enum(["manual", "auto", "unknown"]);
32410
32427
  var agentContextCompactionStatusSchema = zod_default2.enum(["completed", "failed"]);
32428
+ var agentContextCompactionRequestResultSchema = zod_default2.discriminatedUnion("status", [
32429
+ zod_default2.object({ status: zod_default2.literal("completed") }).strict(),
32430
+ zod_default2.object({ status: zod_default2.literal("no_op"), reason: zod_default2.string() }).strict(),
32431
+ zod_default2.object({ status: zod_default2.literal("failed"), error: agentErrorSchema }).strict(),
32432
+ zod_default2.object({ status: zod_default2.literal("unknown") }).strict()
32433
+ ]);
32411
32434
  var agentErrorSourceSchema = zod_default2.enum(["provider", "runtime", "transport", "unknown"]);
32412
32435
  var agentSkillScopeSchema = zod_default2.enum(["user", "repository", "system", "admin"]);
32413
32436
  var agentSkillSchema = zod_default2.object({
@@ -32660,6 +32683,13 @@ var contextCompactionCompletedAgentEventSchema = agentTurnEventBaseSchema.extend
32660
32683
  error: agentErrorSchema.optional()
32661
32684
  }).strict()
32662
32685
  }).strict();
32686
+ var contextCompactionRequestCompletedAgentEventSchema = agentEventBaseSchema.extend({
32687
+ type: zod_default2.literal("context.compaction.request.completed"),
32688
+ payload: zod_default2.object({
32689
+ commandId: zod_default2.string().min(1),
32690
+ result: agentContextCompactionRequestResultSchema
32691
+ }).strict()
32692
+ }).strict();
32663
32693
  var userInputRequestedAgentEventSchema = agentTurnEventBaseSchema.extend({
32664
32694
  type: zod_default2.literal("user-input.requested"),
32665
32695
  payload: zod_default2.object({
@@ -32712,6 +32742,7 @@ var agentEventSchema = zod_default2.discriminatedUnion("type", [
32712
32742
  contextUpdatedAgentEventSchema,
32713
32743
  contextCompactionStartedAgentEventSchema,
32714
32744
  contextCompactionCompletedAgentEventSchema,
32745
+ contextCompactionRequestCompletedAgentEventSchema,
32715
32746
  userInputRequestedAgentEventSchema,
32716
32747
  userInputResolvedAgentEventSchema,
32717
32748
  errorAgentEventSchema
@@ -32900,6 +32931,13 @@ var interruptSessionResponseSchema = exports_external2.strictObject({
32900
32931
  type: exports_external2.literal("agent.interrupt")
32901
32932
  })
32902
32933
  });
32934
+ var compactSessionContextResponseSchema = exports_external2.strictObject({
32935
+ command: exports_external2.strictObject({
32936
+ id: exports_external2.string(),
32937
+ sequence: exports_external2.number().int().positive(),
32938
+ type: exports_external2.literal("agent.compact-context")
32939
+ })
32940
+ });
32903
32941
  var withdrawSessionMessageResponseSchema = exports_external2.strictObject({
32904
32942
  command: exports_external2.strictObject({
32905
32943
  id: exports_external2.string(),
@@ -33070,6 +33108,24 @@ async function interruptSession({
33070
33108
  throw new CodingAgentProtocolError("Session interrupt response did not match the public API contract.", { cause: parsed.error });
33071
33109
  return parsed.data.command;
33072
33110
  }
33111
+ async function compactSessionContext({
33112
+ client,
33113
+ sessionId,
33114
+ idempotencyKey
33115
+ }) {
33116
+ const response = await client.request(`/v1/sessions/${encodeURIComponent(sessionId)}/compact`, {
33117
+ method: "POST",
33118
+ headers: {
33119
+ "content-type": "application/json",
33120
+ "Idempotency-Key": idempotencyKey
33121
+ },
33122
+ body: "{}"
33123
+ });
33124
+ const parsed = compactSessionContextResponseSchema.safeParse(await parseJson2(response, "Session context compaction response was not valid JSON."));
33125
+ if (!parsed.success)
33126
+ throw new CodingAgentProtocolError("Session context compaction response did not match the public API contract.", { cause: parsed.error });
33127
+ return parsed.data.command;
33128
+ }
33073
33129
  async function completeSession({ client, sessionId }) {
33074
33130
  const response = await client.request(`/v1/sessions/${encodeURIComponent(sessionId)}/complete`, { method: "PUT" });
33075
33131
  const parsed = sessionDetailResponseSchema.safeParse(await parseJson2(response, "Session completion response was not valid JSON."));
@@ -34010,6 +34066,9 @@ var wrappedContextCompactionStartedAgentEventSchema = contextCompactionStartedAg
34010
34066
  var wrappedContextCompactionCompletedAgentEventSchema = contextCompactionCompletedAgentEventSchema.extend({
34011
34067
  type: zod_default2.literal("agent.context.compaction.completed")
34012
34068
  }).strict();
34069
+ var wrappedContextCompactionRequestCompletedAgentEventSchema = contextCompactionRequestCompletedAgentEventSchema.extend({
34070
+ type: zod_default2.literal("agent.context.compaction.request.completed")
34071
+ }).strict();
34013
34072
  var wrappedUserInputRequestedAgentEventSchema = userInputRequestedAgentEventSchema.extend({
34014
34073
  type: zod_default2.literal("agent.user-input.requested")
34015
34074
  }).strict();
@@ -34044,11 +34103,31 @@ var wrappedAgentEventSchema = zod_default2.discriminatedUnion("type", [
34044
34103
  wrappedContextUpdatedAgentEventSchema,
34045
34104
  wrappedContextCompactionStartedAgentEventSchema,
34046
34105
  wrappedContextCompactionCompletedAgentEventSchema,
34106
+ wrappedContextCompactionRequestCompletedAgentEventSchema,
34047
34107
  wrappedUserInputRequestedAgentEventSchema,
34048
34108
  wrappedUserInputResolvedAgentEventSchema,
34049
34109
  wrappedErrorAgentEventSchema
34050
34110
  ]);
34051
34111
 
34112
+ // ../../packages/agents-protocol/src/agent-identity.ts
34113
+ function normalizeAgentSubagentIdentity(identity) {
34114
+ return {
34115
+ actorId: identity.actorId,
34116
+ subagentId: identity.subagentId,
34117
+ parentActorId: identity.parentActorId,
34118
+ origin: identity.origin,
34119
+ parentToolCallId: identity.parentToolCallId ?? (identity.origin.type === "tool_call" ? identity.origin.toolCallId : undefined)
34120
+ };
34121
+ }
34122
+ function agentSubagentIdentitiesEqual(left, right) {
34123
+ const normalizedLeft = normalizeAgentSubagentIdentity(left);
34124
+ const normalizedRight = normalizeAgentSubagentIdentity(right);
34125
+ return normalizedLeft.actorId === normalizedRight.actorId && normalizedLeft.subagentId === normalizedRight.subagentId && normalizedLeft.parentActorId === normalizedRight.parentActorId && normalizedLeft.parentToolCallId === normalizedRight.parentToolCallId && (normalizedLeft.origin.type === "tool_call" ? normalizedRight.origin.type === "tool_call" && normalizedLeft.origin.toolCallId === normalizedRight.origin.toolCallId : normalizedRight.origin.type === "provider_task" && normalizedLeft.origin.taskId === normalizedRight.origin.taskId);
34126
+ }
34127
+ function agentRuntimeIdentityKey(event) {
34128
+ return `${event.sessionId.length}:${event.sessionId}:${event.providerSessionId.length}:${event.providerSessionId}`;
34129
+ }
34130
+
34052
34131
  // src/sessions/projection.ts
34053
34132
  var sessionMessageCreatedEventSchema = exports_external2.object({
34054
34133
  type: exports_external2.literal("session.message.created"),
@@ -34377,11 +34456,7 @@ function projectAgentTurnEnded({ state, event, occurredAt, retainedEventId }) {
34377
34456
  retainedTurnEnds: { ...state.retainedTurnEnds, [event.turnId]: { actorType: event.actor.type, outcome: event.payload.status } },
34378
34457
  messageTurns: Object.fromEntries(Object.entries(state.messageTurns).map(([messageId, turn]) => [messageId, turn.turnId === event.turnId ? { ...turn, outcome: event.payload.status } : turn]))
34379
34458
  } : state;
34380
- const card = event.actor.type === "main" ? event.payload.status === "failed" ? { kind: "failure", weight: "signal", title: "Remy turn failed", summary: "Turn failed." } : { kind: "lifecycle", weight: "noise", title: "Remy turn ended", summary: `Turn ${event.payload.status}.` } : createChildActivityCard({
34381
- identity: event.actor,
34382
- activityTitle: event.payload.status === "failed" ? "Turn failed" : "Turn ended",
34383
- card: event.payload.status === "failed" ? { kind: "failure", weight: "signal", summary: providerText(event.payload.error?.message, "Turn failed.") } : { kind: "lifecycle", weight: "noise", summary: `Turn ${event.payload.status}.` }
34384
- });
34459
+ const card = toAgentActivityCard(event);
34385
34460
  return appendActivity({ state: stateWithTurnOutcome, retainedEventId, occurredAt, card });
34386
34461
  }
34387
34462
  function projectDurableAgentEvent({ state, event, occurredAt, retainedEventId }) {
@@ -34526,7 +34601,7 @@ function toMainAgentActivityCard(event) {
34526
34601
  case "agent.turn.started":
34527
34602
  return { kind: "lifecycle", weight: "noise", title: "Remy turn started", summary: "Turn started." };
34528
34603
  case "agent.turn.ended":
34529
- return event.payload.status === "failed" ? { kind: "failure", weight: "signal", title: "Remy turn failed", summary: providerText(event.payload.error?.message, "Turn failed.") } : { kind: "lifecycle", weight: "noise", title: "Remy turn ended", summary: `Turn ${event.payload.status}.` };
34604
+ return event.payload.status === "failed" ? { kind: "failure", weight: "signal", title: "Remy turn failed", summary: "Turn failed." } : { kind: "lifecycle", weight: "noise", title: "Remy turn ended", summary: `Turn ${event.payload.status}.` };
34530
34605
  case "agent.work.observed":
34531
34606
  return { kind: "progress", weight: "noise", title: "Work progress", summary: "Remy updated its work plan.", detail: jsonDetail(event.payload.observations) };
34532
34607
  case "agent.message.started":
@@ -34562,6 +34637,16 @@ function toMainAgentActivityCard(event) {
34562
34637
  return { kind: "reasoning", weight: "noise", title: "Context compaction started", summary: "Remy is compacting context." };
34563
34638
  case "agent.context.compaction.completed":
34564
34639
  return event.payload.status === "failed" ? { kind: "failure", weight: "signal", title: "Context compaction failed", summary: providerText(event.payload.error?.message, "Context compaction failed.") } : { kind: "reasoning", weight: "noise", title: "Context compaction completed", summary: "Remy compacted context." };
34640
+ case "agent.context.compaction.request.completed": {
34641
+ const result = event.payload.result;
34642
+ if (result.status === "completed")
34643
+ return { kind: "progress", weight: "signal", title: "Context compaction completed", summary: "The provider completed manual context compaction." };
34644
+ if (result.status === "no_op")
34645
+ return { kind: "progress", weight: "signal", title: "Context not compacted", summary: providerText(result.reason, "The provider did not compact context.") };
34646
+ if (result.status === "failed")
34647
+ return { kind: "failure", weight: "signal", title: "Context compaction failed", summary: providerText(result.error.message, "Context compaction failed.") };
34648
+ return { kind: "progress", weight: "signal", title: "Context compaction result unknown", summary: "The provider result could not be correlated." };
34649
+ }
34565
34650
  case "agent.user-input.requested":
34566
34651
  return { kind: "approval-question", weight: "signal", title: "Remy needs input", summary: providerText(event.payload.prompt, "Remy needs input."), detail: jsonDetail(event.payload.questions) };
34567
34652
  case "agent.user-input.resolved":
@@ -34647,6 +34732,7 @@ function toChildAgentActivityCard({ event, identity }) {
34647
34732
  case "agent.session.skills.updated":
34648
34733
  case "agent.session.state.changed":
34649
34734
  case "agent.session.ended":
34735
+ case "agent.context.compaction.request.completed":
34650
34736
  case "agent.user-input.resolved":
34651
34737
  case "agent.error":
34652
34738
  throw new SessionProjectionProtocolError(`Cannot attribute non-child session event type ${event.type} to a subagent.`);
@@ -34689,7 +34775,7 @@ ${card.detail}`;
34689
34775
  function childActivityIdentity(event) {
34690
34776
  if (event.type === "agent.subagent.started" || event.type === "agent.subagent.progress" || event.type === "agent.subagent.ended") {
34691
34777
  if (event.actor.type === "subagent") {
34692
- if (!subagentLifecycleIdentityMatches({ actor: event.actor, payload: event.payload }))
34778
+ if (!agentSubagentIdentitiesEqual(event.actor, event.payload))
34693
34779
  throw new SessionProjectionProtocolError(`Retained session event type ${event.type} carried contradictory subagent actor and payload identity.`);
34694
34780
  return {
34695
34781
  ...event.actor,
@@ -34711,14 +34797,6 @@ function childActivityIdentity(event) {
34711
34797
  }
34712
34798
  return;
34713
34799
  }
34714
- function subagentLifecycleIdentityMatches({ actor, payload }) {
34715
- return actor.actorId === payload.actorId && actor.subagentId === payload.subagentId && actor.parentActorId === payload.parentActorId && actor.parentToolCallId === payload.parentToolCallId && subagentOriginsMatch(actor.origin, payload.origin);
34716
- }
34717
- function subagentOriginsMatch(left, right) {
34718
- if (left.type === "tool_call")
34719
- return right.type === "tool_call" && left.toolCallId === right.toolCallId;
34720
- return right.type === "provider_task" && left.taskId === right.taskId;
34721
- }
34722
34800
  function recordAgentLineageEvent({
34723
34801
  state,
34724
34802
  event,
@@ -34734,7 +34812,7 @@ function recordAgentLineageEvent({
34734
34812
  return state;
34735
34813
  throw error93;
34736
34814
  }
34737
- const runtimeBase = lineageRuntimeBase(parsed);
34815
+ const runtimeBase = agentRuntimeIdentityKey(parsed);
34738
34816
  let childLineage = state.childLineage;
34739
34817
  if (parsed.type === "agent.session.started" || parsed.type === "agent.session.ended") {
34740
34818
  const boundaryKey = `${runtimeBase}:${lengthPrefixed(parsed.eventId)}`;
@@ -34793,7 +34871,7 @@ function recordAgentLineageEvent({
34793
34871
  return stampResolvedAttribution({ state: nextState, retainedEventId, fact, owner: resolution.owner });
34794
34872
  }
34795
34873
  function resolveBodyFactAgainstOwners(owners, fact) {
34796
- const candidates = owners.filter((owner) => owner.runtimeScope === fact.runtimeScope && childIdentityMatches(owner.identity, fact.identity));
34874
+ const candidates = owners.filter((owner) => owner.runtimeScope === fact.runtimeScope && agentSubagentIdentitiesEqual(owner.identity, fact.identity));
34797
34875
  const turnCandidates = candidates.filter((owner) => owner.childTurnIds.has(fact.turnId));
34798
34876
  if (turnCandidates.length === 1)
34799
34877
  return { status: "known", owner: turnCandidates[0] };
@@ -34825,9 +34903,6 @@ function stampResolvedAttribution({ state, retainedEventId, fact, owner }) {
34825
34903
  }
34826
34904
  return state;
34827
34905
  }
34828
- function lineageRuntimeBase(event) {
34829
- return `${lengthPrefixed(event.sessionId)}:${lengthPrefixed(event.providerSessionId)}`;
34830
- }
34831
34906
  function lineageRuntimeScope({ runtimeBase, epoch }) {
34832
34907
  return `${runtimeBase}:${epoch}`;
34833
34908
  }
@@ -34840,9 +34915,6 @@ function isChildLineageFact(fact) {
34840
34915
  function isSubagentLifecycleType(type) {
34841
34916
  return type === "agent.subagent.started" || type === "agent.subagent.progress" || type === "agent.subagent.ended";
34842
34917
  }
34843
- function childIdentityMatches(left, right) {
34844
- return left.actorId === right.actorId && left.subagentId === right.subagentId && left.parentActorId === right.parentActorId && left.parentToolCallId === right.parentToolCallId && subagentOriginsMatch(left.origin, right.origin);
34845
- }
34846
34918
  function childIdentityCanAnchor(identity) {
34847
34919
  return identity.actorId !== identity.parentActorId && (identity.origin.type !== "tool_call" || identity.parentToolCallId === undefined || identity.parentToolCallId === identity.origin.toolCallId);
34848
34920
  }
@@ -34876,9 +34948,9 @@ function reconcileChildLineage(state) {
34876
34948
  if (parent && ownerHasActorAncestor(parent, fact.identity.actorId))
34877
34949
  return;
34878
34950
  const samePlacement = owners.filter((owner2) => owner2.runtimeScope === fact.runtimeScope && owner2.owningMainTurnId === owningMainTurnId && owner2.parent === parent && owner2.identity.actorId === fact.identity.actorId && owner2.identity.subagentId === fact.identity.subagentId);
34879
- if (samePlacement.some((owner2) => !childIdentityMatches(owner2.identity, fact.identity)))
34951
+ if (samePlacement.some((owner2) => !agentSubagentIdentitiesEqual(owner2.identity, fact.identity)))
34880
34952
  return;
34881
- const existing = samePlacement.find((owner2) => childIdentityMatches(owner2.identity, fact.identity));
34953
+ const existing = samePlacement.find((owner2) => agentSubagentIdentitiesEqual(owner2.identity, fact.identity));
34882
34954
  if (existing)
34883
34955
  return existing;
34884
34956
  const owner = {
@@ -34912,7 +34984,7 @@ function reconcileChildLineage(state) {
34912
34984
  const toolTurn = mainTurnForToolOrigin(fact);
34913
34985
  if (toolTurn === undefined)
34914
34986
  continue;
34915
- const owner = owners.find((candidate) => candidate.runtimeScope === fact.runtimeScope && candidate.parent === null && candidate.owningMainTurnId === toolTurn && childIdentityMatches(candidate.identity, fact.identity)) ?? createOwner({ fact, owningMainTurnId: toolTurn, parent: null });
34987
+ const owner = owners.find((candidate) => candidate.runtimeScope === fact.runtimeScope && candidate.parent === null && candidate.owningMainTurnId === toolTurn && agentSubagentIdentitiesEqual(candidate.identity, fact.identity)) ?? createOwner({ fact, owningMainTurnId: toolTurn, parent: null });
34916
34988
  if (owner) {
34917
34989
  ownerByFactOrder.set(fact.order, owner);
34918
34990
  owner.childTurnIds.add(fact.turnId);
@@ -34925,7 +34997,7 @@ function reconcileChildLineage(state) {
34925
34997
  for (const fact of childFacts) {
34926
34998
  if (ownerByFactOrder.has(fact.order))
34927
34999
  continue;
34928
- const candidates = owners.filter((owner2) => owner2.runtimeScope === fact.runtimeScope && childIdentityMatches(owner2.identity, fact.identity));
35000
+ const candidates = owners.filter((owner2) => owner2.runtimeScope === fact.runtimeScope && agentSubagentIdentitiesEqual(owner2.identity, fact.identity));
34929
35001
  const turnCandidates = candidates.filter((owner2) => owner2.childTurnIds.has(fact.turnId));
34930
35002
  const owner = turnCandidates.length === 1 ? turnCandidates[0] : candidates.length === 1 ? candidates[0] : undefined;
34931
35003
  if (!owner || fact.eventType === "agent.subagent.started")
@@ -35001,12 +35073,16 @@ function ownerPath(owner) {
35001
35073
  return path;
35002
35074
  }
35003
35075
  function childAttributionEqual(left, right) {
35004
- if (left.status !== right.status || left.activityTitle !== right.activityTitle || !childIdentityMatches(left.identity, right.identity)) {
35076
+ if (left === right)
35077
+ return true;
35078
+ if (!left || !right)
35079
+ return false;
35080
+ if (left.status !== right.status || left.activityTitle !== right.activityTitle || left.identity.name !== right.identity.name || !agentSubagentIdentitiesEqual(left.identity, right.identity)) {
35005
35081
  return false;
35006
35082
  }
35007
35083
  if (left.status === "unresolved" || right.status === "unresolved")
35008
35084
  return true;
35009
- return left.ownerKey === right.ownerKey && left.owningMainTurnId === right.owningMainTurnId && left.path.length === right.path.length && left.path.every((identity, index) => childIdentityMatches(identity, right.path[index]));
35085
+ return left.ownerKey === right.ownerKey && left.owningMainTurnId === right.owningMainTurnId && left.path.length === right.path.length && left.path.every((identity, index) => identity.name === right.path[index].name && agentSubagentIdentitiesEqual(identity, right.path[index]));
35010
35086
  }
35011
35087
  function terminalSafeSingleLine(value) {
35012
35088
  return stripAnsi(value).replace(/\s+/gu, " ").trim();
@@ -36935,6 +37011,19 @@ async function createNewSessionWizard({
36935
37011
  overrides.delete(repositoryId);
36936
37012
  else
36937
37013
  overrides.set(repositoryId, isSelected);
37014
+ }, branchOverridesForSelection = function() {
37015
+ return [...selectedBranches].map(([repositoryId, branchName]) => ({ repositoryId, branchName }));
37016
+ }, branchOptions = function() {
37017
+ return [...selectedRepositoryIds()].flatMap((repositoryId) => {
37018
+ const existing = branchSuggestions.filter((suggestion) => suggestion.repositoryId === repositoryId && suggestion.suggestionKind !== "createSessionBranch");
37019
+ return [...existing, { suggestionKind: "createSessionBranch", repositoryId, branchName: null, pullRequest: null }];
37020
+ });
37021
+ }, selectBranchOption = function() {
37022
+ const option = branchOptions()[branchOptionIndex];
37023
+ if (option.branchName === null)
37024
+ selectedBranches.delete(option.repositoryId);
37025
+ else
37026
+ selectedBranches.set(option.repositoryId, option.branchName);
36938
37027
  }, renderRepositoryLoadingSkeleton = function() {
36939
37028
  return new StyledText5([
36940
37029
  dim4(fg6(PALETTE.dimText)(`\u283F \u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588
@@ -36947,7 +37036,7 @@ async function createNewSessionWizard({
36947
37036
  const orient = (body) => joinStyled([renderStepIndicator({
36948
37037
  step,
36949
37038
  hasInstallationChoice: installationIds.length > 1,
36950
- hasBranchChoice: step === "loadingBranches" || branchSuggestions.some((suggestion) => suggestion.suggestionKind !== "createSessionBranch")
37039
+ hasBranchChoice: step === "loadingBranches" || step === "branchError" || branchSuggestions.some((suggestion) => suggestion.suggestionKind !== "createSessionBranch")
36951
37040
  }), body], `
36952
37041
  `);
36953
37042
  if (composerVisible && !composerMounted) {
@@ -37023,31 +37112,39 @@ async function createNewSessionWizard({
37023
37112
  } else if (step === "loadingBranches") {
37024
37113
  content.content = orient(joinStyled([
37025
37114
  new StyledText5([stepHeader("Choose branches")]),
37026
- new StyledText5([fg6(PALETTE.progress)(`${suggestionSpinnerFrames[suggestionSpinnerFrame]} Remy is checking for related open pull requests\u2026`)]),
37115
+ new StyledText5([fg6(PALETTE.progress)(`${suggestionSpinnerFrames[suggestionSpinnerFrame]} Remy is analyzing session, PR, and branch references\u2026`)]),
37027
37116
  new StyledText5([dim4(fg6(PALETTE.dimText)("This can take a few seconds."))]),
37028
37117
  stringToStyledText4("esc back")
37029
37118
  ], `
37030
37119
 
37120
+ `));
37121
+ } else if (step === "branchError") {
37122
+ content.content = orient(joinStyled([
37123
+ new StyledText5([stepHeader("Branch lookup failed")]),
37124
+ stringToStyledText4(status),
37125
+ stringToStyledText4("r retry \xB7 n explicitly choose new branches \xB7 esc back")
37126
+ ], `
37127
+
37031
37128
  `));
37032
37129
  } else if (step === "branches") {
37033
- const existing = branchSuggestions.filter((suggestion) => suggestion.suggestionKind !== "createSessionBranch");
37034
- const parts = [new StyledText5([stepHeader("Choose branches")])];
37035
- if (existing.length > 0) {
37036
- parts.push(stringToStyledText4("Remy found related open pull-request work:"));
37037
- for (const suggestion of existing) {
37038
- const repository = installationRepositories().find((candidate) => candidate.id === suggestion.repositoryId);
37039
- parts.push(stringToStyledText4(`${repository?.fullName ?? suggestion.repositoryId} \u2014 ${suggestion.branchName}${suggestion.pullRequest ? ` (PR #${suggestion.pullRequest.number}: ${suggestion.pullRequest.title})` : ""}`));
37040
- }
37041
- parts.push(new StyledText5(renderSelectableRow({ label: "Continue from the suggested branch", isCursor: branchChoice === "existing" })));
37042
- parts.push(new StyledText5(renderSelectableRow({ label: "Create a new session branch", isCursor: branchChoice === "new" })));
37043
- parts.push(stringToStyledText4("\u2191\u2193 choose \xB7 \u23CE continue \xB7 esc back"));
37044
- } else {
37045
- parts.push(stringToStyledText4("Remy recommends creating a new session branch."));
37046
- parts.push(new StyledText5([dim4(fg6(PALETTE.dimText)(status || "No related open pull request was identified from your request."))]));
37047
- parts.push(stringToStyledText4("\u23CE continue \xB7 esc back"));
37130
+ const options = branchOptions();
37131
+ const visibleCount = Math.max(2, renderer.height - 12);
37132
+ const start = Math.max(0, Math.min(branchOptionIndex - Math.floor(visibleCount / 2), options.length - visibleCount));
37133
+ const parts = [
37134
+ new StyledText5([stepHeader("Choose branches")]),
37135
+ stringToStyledText4("Continue from the suggested branch, or choose new work for each repository:")
37136
+ ];
37137
+ for (const [index, option] of options.slice(start, start + visibleCount).entries()) {
37138
+ const repository = installationRepositories().find((repository2) => repository2.id === option.repositoryId);
37139
+ const selected = (selectedBranches.get(option.repositoryId) ?? null) === option.branchName;
37140
+ const label = option.branchName === null ? "Create a new session branch" : `${option.branchName}${option.pullRequest ? ` (PR #${option.pullRequest.number}: ${option.pullRequest.title})` : ""}`;
37141
+ parts.push(new StyledText5(renderSelectableRow({
37142
+ label: `${selected ? "\u25CF" : "\u25CB"} ${repository?.fullName ?? option.repositoryId} \u2014 ${label}`,
37143
+ isCursor: start + index === branchOptionIndex
37144
+ })));
37048
37145
  }
37146
+ parts.push(stringToStyledText4(`\u2191\u2193 move \xB7 space select \xB7 \u23CE select & review \xB7 esc back (${branchOptionIndex + 1}/${options.length})`));
37049
37147
  content.content = orient(joinStyled(parts, `
37050
-
37051
37148
  `));
37052
37149
  } else if (repositoryListVisible) {
37053
37150
  const selectionOverrides = searchSelections ?? manualSelections;
@@ -37092,13 +37189,13 @@ async function createNewSessionWizard({
37092
37189
  editor.placeholder = "e.g. worker, migration, dashboard";
37093
37190
  } else {
37094
37191
  const selected = installationRepositories().filter((repository) => selectedRepositoryIds().has(repository.id));
37095
- const branchOverrides = branchChoice === "existing" ? branchSuggestions.filter((suggestion) => suggestion.suggestionKind !== "createSessionBranch") : [];
37192
+ const branchOverrides = branchOverridesForSelection();
37096
37193
  const meta5 = new StyledText5([
37097
37194
  fg6(PALETTE.bodyText)(`Installation: ${selectedInstallationId() ?? "(missing)"}
37098
37195
  `),
37099
37196
  fg6(PALETTE.bodyText)(`Repositories: ${selected.map((repository) => repository.fullName).join(", ") || "(none)"}
37100
37197
  `),
37101
- fg6(PALETTE.bodyText)(`Branches: ${branchOverrides.length > 0 ? branchOverrides.map((override) => override.branchName).join(", ") : "new session branches"}
37198
+ fg6(PALETTE.bodyText)(`Branches: ${branchOverrides.length > 0 ? selected.map((repository) => `${repository.fullName}: ${selectedBranches.get(repository.id) ?? "new session branch"}`).join(", ") : "new session branches"}
37102
37199
  `),
37103
37200
  fg6(PALETTE.bodyText)(`Model: ${newSessionModelLabel(model)} \xB7 ${newSessionReasoningEffortLabel(reasoningEffort)} reasoning`),
37104
37201
  dim4(fg6(PALETTE.dimText)(" \u25B8 m model \xB7 \u2190\u2192 reasoning"))
@@ -37111,7 +37208,7 @@ async function createNewSessionWizard({
37111
37208
  ];
37112
37209
  if (attachmentText.chunks.length > 0)
37113
37210
  parts.push(attachmentText);
37114
- 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."))]));
37211
+ 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."))]));
37115
37212
  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"));
37116
37213
  if (status)
37117
37214
  parts.push(stringToStyledText4(status));
@@ -37244,7 +37341,7 @@ async function createNewSessionWizard({
37244
37341
  returnToPromptFromRepositoryLoading();
37245
37342
  return;
37246
37343
  }
37247
- if (step === "loadingBranches" || step === "branches") {
37344
+ if (step === "loadingBranches" || step === "branches" || step === "branchError") {
37248
37345
  branchRequestGeneration += 1;
37249
37346
  step = "repositories";
37250
37347
  render();
@@ -37354,6 +37451,17 @@ async function createNewSessionWizard({
37354
37451
  return;
37355
37452
  }
37356
37453
  }
37454
+ if (step === "branchError" && (key.name === "r" || key.name === "n")) {
37455
+ key.preventDefault();
37456
+ if (key.name === "r") {
37457
+ startBranchReview();
37458
+ } else {
37459
+ status = "";
37460
+ step = "confirmation";
37461
+ render();
37462
+ }
37463
+ return;
37464
+ }
37357
37465
  if (step === "repositorySearch")
37358
37466
  return;
37359
37467
  if (step === "loadingSuggestions" && key.name === "s") {
@@ -37373,15 +37481,23 @@ async function createNewSessionWizard({
37373
37481
  return;
37374
37482
  }
37375
37483
  }
37484
+ if (step === "branches" && key.name === "space") {
37485
+ key.preventDefault();
37486
+ selectBranchOption();
37487
+ render();
37488
+ return;
37489
+ }
37376
37490
  if (step === "branches" && branchSuggestions.some((suggestion) => suggestion.suggestionKind !== "createSessionBranch") && (key.name === "up" || key.name === "down" || key.name === "left" || key.name === "right")) {
37377
37491
  key.preventDefault();
37378
- branchChoice = branchChoice === "existing" ? "new" : "existing";
37492
+ const options = branchOptions();
37493
+ const direction = key.name === "up" || key.name === "left" ? -1 : 1;
37494
+ branchOptionIndex = (branchOptionIndex + direction + options.length) % options.length;
37379
37495
  render();
37380
37496
  return;
37381
37497
  }
37382
37498
  if (!composerMounted && (key.name === "return" || key.name === "enter")) {
37383
37499
  key.preventDefault();
37384
- if (step === "loadingBranches")
37500
+ if (step === "loadingBranches" || step === "branchError")
37385
37501
  return;
37386
37502
  submitEditor();
37387
37503
  return;
@@ -37500,7 +37616,8 @@ async function createNewSessionWizard({
37500
37616
  branchName: override.branchName,
37501
37617
  pullRequest: null
37502
37618
  })) ?? [];
37503
- let branchChoice = initialDraft?.repositoryBranchOverrides?.length ? "existing" : "new";
37619
+ const selectedBranches = new Map(initialDraft?.repositoryBranchOverrides?.map((override) => [override.repositoryId, override.branchName]));
37620
+ let branchOptionIndex = 0;
37504
37621
  let status = initialError ?? "";
37505
37622
  let attachmentFeedback;
37506
37623
  let pendingPastedImageWrites = 0;
@@ -37575,9 +37692,16 @@ async function createNewSessionWizard({
37575
37692
  if (!installationId)
37576
37693
  return;
37577
37694
  const repositoryIds = [...selectedRepositoryIds()];
37695
+ if (repositoryIds.length === 0) {
37696
+ branchSuggestions = [];
37697
+ selectedBranches.clear();
37698
+ step = "confirmation";
37699
+ render();
37700
+ return;
37701
+ }
37578
37702
  const requestGeneration = ++branchRequestGeneration;
37579
37703
  branchSuggestions = [];
37580
- branchChoice = "new";
37704
+ selectedBranches.clear();
37581
37705
  step = "loadingBranches";
37582
37706
  status = "";
37583
37707
  render();
@@ -37587,15 +37711,19 @@ async function createNewSessionWizard({
37587
37711
  return;
37588
37712
  branchSuggestions = suggestions;
37589
37713
  const hasExistingBranch = branchSuggestions.some((suggestion) => suggestion.suggestionKind !== "createSessionBranch");
37590
- branchChoice = hasExistingBranch ? "existing" : "new";
37714
+ for (const suggestion of branchSuggestions) {
37715
+ if (suggestion.suggestionKind !== "createSessionBranch" && !selectedBranches.has(suggestion.repositoryId))
37716
+ selectedBranches.set(suggestion.repositoryId, suggestion.branchName);
37717
+ }
37718
+ branchOptionIndex = 0;
37591
37719
  step = hasExistingBranch ? "branches" : "confirmation";
37592
37720
  } catch (error93) {
37593
37721
  if (destroyed || requestGeneration !== branchRequestGeneration || step !== "loadingBranches")
37594
37722
  return;
37595
37723
  branchSuggestions = [];
37596
- branchChoice = "new";
37724
+ selectedBranches.clear();
37597
37725
  status = error93 instanceof Error ? error93.message : String(error93);
37598
- step = "confirmation";
37726
+ step = "branchError";
37599
37727
  }
37600
37728
  render();
37601
37729
  }
@@ -37668,7 +37796,7 @@ async function createNewSessionWizard({
37668
37796
  fail(new Error("Selected repositories must belong to the chosen GitHub installation."));
37669
37797
  return;
37670
37798
  }
37671
- const repositoryBranchOverrides = branchChoice === "existing" ? branchSuggestions.flatMap((suggestion) => suggestion.suggestionKind === "createSessionBranch" ? [] : [{ repositoryId: suggestion.repositoryId, branchName: suggestion.branchName }]) : [];
37799
+ const repositoryBranchOverrides = branchOverridesForSelection();
37672
37800
  const confirmation = Symbol("confirmation");
37673
37801
  const confirmedAttachments = [...attachments];
37674
37802
  const confirmedPrompt = prompt;
@@ -37755,6 +37883,7 @@ async function createNewSessionWizard({
37755
37883
  return;
37756
37884
  }
37757
37885
  if (step === "branches") {
37886
+ selectBranchOption();
37758
37887
  step = "confirmation";
37759
37888
  render();
37760
37889
  return;
@@ -37870,7 +37999,7 @@ function wizardStepKey(step) {
37870
37999
  return "describe";
37871
38000
  if (step === "installation")
37872
38001
  return "installation";
37873
- if (step === "loadingBranches" || step === "branches")
38002
+ if (step === "loadingBranches" || step === "branches" || step === "branchError")
37874
38003
  return "branches";
37875
38004
  if (step === "confirmation")
37876
38005
  return "confirm";
@@ -37925,6 +38054,7 @@ var composerSlashCommands = [
37925
38054
  { value: "/sessions", description: "Back to the session list" },
37926
38055
  { value: "/complete", description: "Finish this session" },
37927
38056
  { value: "/cancel", description: "Cancel this session" },
38057
+ { value: "/compact", description: "Compact main-thread context" },
37928
38058
  { value: "/new", description: "Start a new session" },
37929
38059
  { value: "/logout", description: "Sign out of Remy" },
37930
38060
  { value: "/help", description: "Show what you can do here" },
@@ -37936,6 +38066,7 @@ async function createSessionTui({
37936
38066
  controller,
37937
38067
  submitMessage,
37938
38068
  requestInterrupt,
38069
+ requestCompact,
37939
38070
  requestComplete,
37940
38071
  requestCancel,
37941
38072
  repositoryLabel,
@@ -38177,6 +38308,7 @@ async function createSessionTui({
38177
38308
  let admittedSubmissions = [];
38178
38309
  let stopState = { kind: "idle" };
38179
38310
  let lifecycleRequestState = { kind: "idle" };
38311
+ let contextCompactionRequestState = { kind: "idle" };
38180
38312
  let helpVisible = false;
38181
38313
  let logoutConfirmationOpen = false;
38182
38314
  let latestState = controller.getState();
@@ -38527,6 +38659,12 @@ async function createSessionTui({
38527
38659
  handleLifecycleRequest("cancel");
38528
38660
  return true;
38529
38661
  }
38662
+ if (command === "/compact") {
38663
+ composer.setText("");
38664
+ composerDraft = { ...composerDraft, text: "" };
38665
+ await handleCompactionRequest();
38666
+ return true;
38667
+ }
38530
38668
  if (command === "/logout") {
38531
38669
  composer.setText("");
38532
38670
  composerDraft = { ...composerDraft, text: "" };
@@ -38614,6 +38752,39 @@ async function createSessionTui({
38614
38752
  }
38615
38753
  render();
38616
38754
  }
38755
+ async function handleCompactionRequest() {
38756
+ if (contextCompactionRequestState.kind === "requesting")
38757
+ return;
38758
+ if (latestState.aggregateStatus !== "open") {
38759
+ composerFeedback = "This session is already terminal.";
38760
+ render();
38761
+ return;
38762
+ }
38763
+ const idempotencyKey = contextCompactionRequestState.kind === "delivery-unknown" ? contextCompactionRequestState.idempotencyKey : crypto.randomUUID();
38764
+ contextCompactionRequestState = { kind: "requesting", idempotencyKey };
38765
+ composerFeedback = "Requesting context compaction\u2026";
38766
+ render();
38767
+ try {
38768
+ await requestCompact({ idempotencyKey });
38769
+ if (!destroyed) {
38770
+ contextCompactionRequestState = { kind: "admitted" };
38771
+ composerFeedback = "Context compaction request admitted. Result will appear in the timeline.";
38772
+ }
38773
+ } catch (error93) {
38774
+ if (!destroyed) {
38775
+ const message = error93 instanceof Error ? error93.message : String(error93);
38776
+ if (isKnownClientRejection(error93)) {
38777
+ contextCompactionRequestState = { kind: "idle" };
38778
+ composerFeedback = `Could not request context compaction: ${message}`;
38779
+ } else {
38780
+ contextCompactionRequestState = { kind: "delivery-unknown", idempotencyKey };
38781
+ composerFeedback = `Context compaction admission is unknown: ${message}. Run /compact again to retry the same request.`;
38782
+ }
38783
+ }
38784
+ }
38785
+ if (!destroyed)
38786
+ render();
38787
+ }
38617
38788
  async function handleLifecycleRequest(operation) {
38618
38789
  if (lifecycleRequestState.kind === "pending")
38619
38790
  return;
@@ -38740,6 +38911,7 @@ var helpEntries = [
38740
38911
  { group: "command", token: "/sessions", description: "back to the session list" },
38741
38912
  { group: "command", token: "/complete", description: "finish this session" },
38742
38913
  { group: "command", token: "/cancel", description: "cancel this session" },
38914
+ { group: "command", token: "/compact", description: "compact main-thread context" },
38743
38915
  { group: "command", token: "/logout", description: "sign out of Remy" },
38744
38916
  { group: "command", token: "/exit", description: "leave Remy" },
38745
38917
  { group: "key", token: "esc", description: "stop Remy\u2019s current turn" },
@@ -38957,19 +39129,7 @@ function activityGlyph({ kind, inFlight }) {
38957
39129
  return { glyph: "\u2713", color: PALETTE.dimText };
38958
39130
  }
38959
39131
  function activityCardsHaveEqualDisclosure(left, right) {
38960
- return left.kind === right.kind && left.title === right.title && left.summary === right.summary && left.detail === right.detail && left.detailFormat === right.detailFormat && canonicalValuesEqual(left.attribution, right.attribution);
38961
- }
38962
- function canonicalValuesEqual(left, right) {
38963
- if (Object.is(left, right))
38964
- return true;
38965
- if (Array.isArray(left) || Array.isArray(right)) {
38966
- return Array.isArray(left) && Array.isArray(right) && left.length === right.length && left.every((value, index) => canonicalValuesEqual(value, right[index]));
38967
- }
38968
- if (typeof left !== "object" || left === null || typeof right !== "object" || right === null)
38969
- return false;
38970
- const leftEntries = Object.entries(left);
38971
- const rightEntries = Object.entries(right);
38972
- return leftEntries.length === rightEntries.length && leftEntries.every(([key, value], index) => rightEntries[index]?.[0] === key && canonicalValuesEqual(value, rightEntries[index]?.[1]));
39132
+ return left.kind === right.kind && left.title === right.title && left.summary === right.summary && left.detail === right.detail && left.detailFormat === right.detailFormat && childAttributionEqual(left.attribution, right.attribution);
38973
39133
  }
38974
39134
  function renderActivityGroup({ items, activityExpanded }) {
38975
39135
  if (items.length === 0)
@@ -39170,6 +39330,12 @@ function renderComposerStatus({ admittedSubmissions }) {
39170
39330
 
39171
39331
  `);
39172
39332
  }
39333
+ function isKnownClientRejection(error93) {
39334
+ if (typeof error93 !== "object" || error93 === null || !("status" in error93))
39335
+ return false;
39336
+ const status = error93.status;
39337
+ return typeof status === "number" && status >= 400 && status < 500;
39338
+ }
39173
39339
  async function createDefaultRenderer3() {
39174
39340
  return await createRemyRenderer();
39175
39341
  }
@@ -39430,7 +39596,7 @@ var compactMarkRows = 9;
39430
39596
  var compactMinWidth = 48;
39431
39597
  var compactMinHeight = 20;
39432
39598
  var markBrightnessGain = 4.2;
39433
- var remyCliVersion = "1.14.1";
39599
+ var remyCliVersion = "1.16.0";
39434
39600
  async function showRemySplash({
39435
39601
  createRenderer = createRemyRenderer,
39436
39602
  durationMs = splashDurationMs,
@@ -40833,6 +40999,9 @@ async function runAttachedSession({
40833
40999
  requestInterrupt: async ({ idempotencyKey }) => {
40834
41000
  await operations.interruptSession({ client: operations.client, sessionId, idempotencyKey });
40835
41001
  },
41002
+ requestCompact: async ({ idempotencyKey }) => {
41003
+ await operations.compactSessionContext({ client: operations.client, sessionId, idempotencyKey });
41004
+ },
40836
41005
  requestComplete: async () => {
40837
41006
  const detail = await operations.completeSession({ client: operations.client, sessionId });
40838
41007
  controller.updateDetail(detail);
@@ -40959,6 +41128,7 @@ async function createSessionOperations(dependencies, { onAuthenticated } = {}) {
40959
41128
  appendSessionMessage: dependencies.appendSessionMessage ?? appendSessionMessage,
40960
41129
  cancelSession: dependencies.cancelSession ?? cancelSession,
40961
41130
  completeSession: dependencies.completeSession ?? completeSession,
41131
+ compactSessionContext: dependencies.compactSessionContext ?? compactSessionContext,
40962
41132
  interruptSession: dependencies.interruptSession ?? interruptSession,
40963
41133
  getSession: dependencies.getSession ?? getSession,
40964
41134
  listSessionEvents: dependencies.listSessionEvents ?? listSessionEvents,
@@ -40979,6 +41149,7 @@ async function createSessionOperations(dependencies, { onAuthenticated } = {}) {
40979
41149
  appendSessionMessage: dependencies.appendSessionMessage ?? appendSessionMessage,
40980
41150
  cancelSession: dependencies.cancelSession ?? cancelSession,
40981
41151
  completeSession: dependencies.completeSession ?? completeSession,
41152
+ compactSessionContext: dependencies.compactSessionContext ?? compactSessionContext,
40982
41153
  interruptSession: dependencies.interruptSession ?? interruptSession,
40983
41154
  getSession: dependencies.getSession ?? getSession,
40984
41155
  listSessionEvents: dependencies.listSessionEvents ?? listSessionEvents,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@meistrari/remy-cli",
3
- "version": "1.14.1",
3
+ "version": "1.16.0",
4
4
  "description": "Remy, the Coding Agent terminal client.",
5
5
  "type": "module",
6
6
  "bin": {