@meistrari/remy-cli 1.17.2 → 1.18.0-rc.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 +10 -0
  2. package/dist/remy.js +381 -43
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -22,6 +22,12 @@ bun i -g @meistrari/remy-cli
22
22
  pnpm i -g @meistrari/remy-cli
23
23
  ```
24
24
 
25
+ These commands install the stable release from npm's `latest` channel. To try the release candidate from `main`, install the `rc` channel:
26
+
27
+ ```bash
28
+ bun i -g @meistrari/remy-cli@rc
29
+ ```
30
+
25
31
  Then open Remy:
26
32
 
27
33
  ```bash
@@ -56,6 +62,10 @@ Published files and Tela Pages appear in the timeline. File artifacts include th
56
62
 
57
63
  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.
58
64
 
65
+ Press `Ctrl+O` to inspect tool output, including partial output from failed tools. Ordinary tools keep a single text-output block. MCP tools show ordered text and JSON blocks with separate labels; structured content appears in its own section unless it is null or absent. MCP images, audio, and embedded binary resources show media details instead of base64. Each expanded activity includes a **View event in Web** link when the server supplies its Web URL. Follow it to open the exact retained event and its output, including older or child-agent activity. The full URL remains visible for copying when your terminal does not support clickable links. Older servers without a Web URL show an explicit unavailable message instead of a guessed link. Resource links remain references, not a promise that their targets are accessible. Additional background-tool output appears as a correlated update without replacing the earlier result.
66
+
67
+ Terminal previews show up to 50 content blocks and 8,000 characters per block, with explicit shortening notices. JSON previews also limit nested collections. The complete output remains retained; terminal controls are removed only for display. Different results remain accessible even when their activity labels match.
68
+
59
69
  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.
60
70
 
61
71
  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.
package/dist/remy.js CHANGED
@@ -32152,13 +32152,102 @@ var jsonPrimitiveSchema = zod_default2.union([
32152
32152
  zod_default2.boolean(),
32153
32153
  zod_default2.null()
32154
32154
  ]);
32155
- var jsonValueSchema = zod_default2.lazy(() => zod_default2.union([
32156
- jsonPrimitiveSchema,
32157
- zod_default2.array(jsonValueSchema),
32158
- zod_default2.record(zod_default2.string(), jsonValueSchema)
32159
- ]));
32160
- var jsonObjectSchema = zod_default2.record(zod_default2.string(), jsonValueSchema);
32161
- var jsonArraySchema = zod_default2.array(jsonValueSchema);
32155
+ var jsonWireValueSchema = zod_default2.json();
32156
+ var jsonWireObjectSchema = zod_default2.record(zod_default2.string(), jsonWireValueSchema);
32157
+ var jsonWireArraySchema = zod_default2.array(jsonWireValueSchema);
32158
+ var jsonValueSchema = zod_default2.preprocess(encodeJsonObjectKeys, jsonWireValueSchema).overwrite(decodeJsonObjectKeys);
32159
+ var jsonObjectSchema = zod_default2.preprocess(encodeJsonObjectKeys, jsonWireObjectSchema).overwrite(decodeJsonObject);
32160
+ var jsonArraySchema = zod_default2.preprocess(encodeJsonObjectKeys, jsonWireArraySchema).overwrite((values) => values.map(decodeJsonObjectKeys));
32161
+ var JSON_VALIDATION_KEY_PREFIX = "$";
32162
+ var invalidJsonValue = Symbol("invalid canonical JSON value");
32163
+ function encodeJsonObjectKeys(value) {
32164
+ return encodeJsonValue(value, new WeakSet);
32165
+ }
32166
+ function encodeJsonValue(value, ancestors) {
32167
+ if (Array.isArray(value))
32168
+ return encodeJsonArray(value, ancestors);
32169
+ if (typeof value !== "object" || value === null)
32170
+ return value;
32171
+ if (!isPlainObject5(value))
32172
+ return invalidJsonValue;
32173
+ return encodeJsonObject(value, ancestors);
32174
+ }
32175
+ function encodeJsonArray(value, ancestors) {
32176
+ if (ancestors.has(value))
32177
+ return invalidJsonValue;
32178
+ ancestors.add(value);
32179
+ try {
32180
+ const encoded = [];
32181
+ for (let index = 0;index < value.length; index += 1) {
32182
+ const descriptor = Object.getOwnPropertyDescriptor(value, String(index));
32183
+ if (!descriptor?.enumerable || !("value" in descriptor))
32184
+ return invalidJsonValue;
32185
+ const entry = encodeJsonValue(descriptor.value, ancestors);
32186
+ if (entry === invalidJsonValue)
32187
+ return invalidJsonValue;
32188
+ encoded.push(entry);
32189
+ }
32190
+ for (const key of Reflect.ownKeys(value)) {
32191
+ const descriptor = Object.getOwnPropertyDescriptor(value, key);
32192
+ if (!descriptor || !descriptor.enumerable)
32193
+ continue;
32194
+ if (typeof key !== "string" || !isArrayIndex(key, value.length))
32195
+ return invalidJsonValue;
32196
+ }
32197
+ return encoded;
32198
+ } finally {
32199
+ ancestors.delete(value);
32200
+ }
32201
+ }
32202
+ function encodeJsonObject(value, ancestors) {
32203
+ if (ancestors.has(value))
32204
+ return invalidJsonValue;
32205
+ ancestors.add(value);
32206
+ try {
32207
+ const entries = [];
32208
+ for (const key of Reflect.ownKeys(value)) {
32209
+ const descriptor = Object.getOwnPropertyDescriptor(value, key);
32210
+ if (!descriptor || !descriptor.enumerable)
32211
+ continue;
32212
+ if (typeof key !== "string" || !("value" in descriptor))
32213
+ return invalidJsonValue;
32214
+ const entry = encodeJsonValue(descriptor.value, ancestors);
32215
+ if (entry === invalidJsonValue)
32216
+ return invalidJsonValue;
32217
+ entries.push([encodeJsonKey(key), entry]);
32218
+ }
32219
+ return Object.fromEntries(entries);
32220
+ } finally {
32221
+ ancestors.delete(value);
32222
+ }
32223
+ }
32224
+ function decodeJsonObjectKeys(value) {
32225
+ if (Array.isArray(value))
32226
+ return value.map(decodeJsonObjectKeys);
32227
+ if (typeof value !== "object" || value === null)
32228
+ return value;
32229
+ return decodeJsonObject(value);
32230
+ }
32231
+ function decodeJsonObject(value) {
32232
+ const entries = [];
32233
+ for (const [key, entry] of Object.entries(value))
32234
+ entries.push([decodeJsonKey(key), decodeJsonObjectKeys(entry)]);
32235
+ return Object.fromEntries(entries);
32236
+ }
32237
+ function isPlainObject5(value) {
32238
+ const prototype = Object.getPrototypeOf(value);
32239
+ return prototype === Object.prototype || prototype === null;
32240
+ }
32241
+ function isArrayIndex(value, length) {
32242
+ const index = Number(value);
32243
+ return Number.isInteger(index) && index >= 0 && index < length && String(index) === value;
32244
+ }
32245
+ function encodeJsonKey(value) {
32246
+ return `${JSON_VALIDATION_KEY_PREFIX}${value}`;
32247
+ }
32248
+ function decodeJsonKey(value) {
32249
+ return value.slice(JSON_VALIDATION_KEY_PREFIX.length);
32250
+ }
32162
32251
 
32163
32252
  // ../../packages/agents-protocol/src/agent-user-input.ts
32164
32253
  var agentUserInputOptionSchema = zod_default2.object({
@@ -32310,13 +32399,57 @@ var agentToolImageContentSchema = zod_default2.object({
32310
32399
  data: zod_default2.string().min(1),
32311
32400
  mimeType: zod_default2.string().min(1)
32312
32401
  }).strict();
32313
- var agentToolContentSchema = zod_default2.discriminatedUnion("type", [
32314
- agentToolTextContentSchema,
32315
- agentToolImageContentSchema
32402
+ var observedContentMetadata = {
32403
+ annotations: jsonObjectSchema.optional(),
32404
+ extras: jsonObjectSchema.optional()
32405
+ };
32406
+ var agentToolResourceLinkContentSchema = zod_default2.object({
32407
+ type: zod_default2.literal("resource_link"),
32408
+ name: zod_default2.string(),
32409
+ uri: zod_default2.string(),
32410
+ mimeType: zod_default2.string().optional(),
32411
+ description: zod_default2.string().optional(),
32412
+ title: zod_default2.string().optional(),
32413
+ size: zod_default2.number().nonnegative().optional(),
32414
+ ...observedContentMetadata
32415
+ }).strict();
32416
+ var resourceMetadata = {
32417
+ uri: zod_default2.string(),
32418
+ mimeType: zod_default2.string().optional(),
32419
+ extras: jsonObjectSchema.optional()
32420
+ };
32421
+ var agentToolResourceContentSchema = zod_default2.object({
32422
+ type: zod_default2.literal("resource"),
32423
+ resource: zod_default2.union([
32424
+ zod_default2.object({ ...resourceMetadata, text: zod_default2.string() }).strict(),
32425
+ zod_default2.object({ ...resourceMetadata, blob: zod_default2.string() }).strict()
32426
+ ]),
32427
+ ...observedContentMetadata
32428
+ }).strict();
32429
+ var agentToolAudioContentSchema = zod_default2.object({
32430
+ type: zod_default2.literal("audio"),
32431
+ data: zod_default2.string().min(1),
32432
+ mimeType: zod_default2.string().min(1),
32433
+ ...observedContentMetadata
32434
+ }).strict();
32435
+ var agentToolJsonContentSchema = zod_default2.object({
32436
+ type: zod_default2.literal("json"),
32437
+ value: jsonValueSchema
32438
+ }).strict();
32439
+ var agentToolContentSchema = zod_default2.union([
32440
+ agentToolTextContentSchema.extend(observedContentMetadata).strict(),
32441
+ agentToolImageContentSchema.extend(observedContentMetadata).strict(),
32442
+ zod_default2.object({ type: zod_default2.literal("image"), uri: zod_default2.string().min(1), ...observedContentMetadata }).strict(),
32443
+ agentToolAudioContentSchema,
32444
+ agentToolResourceContentSchema,
32445
+ agentToolResourceLinkContentSchema,
32446
+ agentToolJsonContentSchema
32316
32447
  ]);
32317
32448
  var agentToolResultSchema = zod_default2.object({
32318
32449
  success: zod_default2.boolean(),
32319
- content: zod_default2.array(agentToolContentSchema)
32450
+ content: zod_default2.array(agentToolContentSchema),
32451
+ structuredContent: jsonValueSchema.optional(),
32452
+ reportedSuccess: zod_default2.boolean().optional()
32320
32453
  }).strict();
32321
32454
  var agentToolCallStatusSchema = zod_default2.enum(["completed", "failed", "cancelled"]);
32322
32455
 
@@ -32412,7 +32545,7 @@ function applyAgentWorkObservations(state, observations) {
32412
32545
 
32413
32546
  // ../../packages/agents-protocol/src/agent-event.ts
32414
32547
  var agentErrorSchema = zod_default2.object({
32415
- message: zod_default2.string().min(1),
32548
+ message: zod_default2.string(),
32416
32549
  code: zod_default2.string().min(1).optional(),
32417
32550
  name: zod_default2.string().min(1).optional(),
32418
32551
  stack: zod_default2.string().min(1).optional(),
@@ -32600,6 +32733,13 @@ var toolOutputDeltaAgentEventSchema = agentTurnEventBaseSchema.extend({
32600
32733
  delta: zod_default2.string()
32601
32734
  }).strict()
32602
32735
  }).strict();
32736
+ var toolOutputUpdatedAgentEventSchema = agentTurnEventBaseSchema.extend({
32737
+ type: zod_default2.literal("tool.output.updated"),
32738
+ payload: zod_default2.object({
32739
+ toolCallId: zod_default2.string().min(1),
32740
+ output: agentToolResultSchema
32741
+ }).strict()
32742
+ }).strict();
32603
32743
  var toolCallCompletedAgentEventSchema = agentTurnEventBaseSchema.extend({
32604
32744
  type: zod_default2.literal("tool.call.completed"),
32605
32745
  payload: zod_default2.object({
@@ -32735,6 +32875,7 @@ var agentEventSchema = zod_default2.discriminatedUnion("type", [
32735
32875
  toolCallStartedAgentEventSchema,
32736
32876
  toolOutputDeltaAgentEventSchema,
32737
32877
  toolCallCompletedAgentEventSchema,
32878
+ toolOutputUpdatedAgentEventSchema,
32738
32879
  subagentStartedAgentEventSchema,
32739
32880
  subagentProgressAgentEventSchema,
32740
32881
  subagentEndedAgentEventSchema,
@@ -32947,6 +33088,14 @@ var withdrawSessionMessageResponseSchema = exports_external2.strictObject({
32947
33088
  });
32948
33089
  var sessionDetailResponseSchema = exports_external2.object({
32949
33090
  id: exports_external2.string(),
33091
+ web_url: exports_external2.url().refine((value) => {
33092
+ try {
33093
+ const url3 = new URL(value);
33094
+ return !url3.username && !url3.password;
33095
+ } catch {
33096
+ return false;
33097
+ }
33098
+ }, "Session Web URL must not contain credentials.").optional(),
32950
33099
  title: exports_external2.string().nullable(),
32951
33100
  status: sessionStatusSchema,
32952
33101
  session_number: exports_external2.number().int().positive(),
@@ -34042,6 +34191,9 @@ var wrappedToolCallStartedAgentEventSchema = toolCallStartedAgentEventSchema.ext
34042
34191
  var wrappedToolOutputDeltaAgentEventSchema = toolOutputDeltaAgentEventSchema.extend({
34043
34192
  type: zod_default2.literal("agent.tool.output.delta")
34044
34193
  }).strict();
34194
+ var wrappedToolOutputUpdatedAgentEventSchema = toolOutputUpdatedAgentEventSchema.extend({
34195
+ type: zod_default2.literal("agent.tool.output.updated")
34196
+ }).strict();
34045
34197
  var wrappedToolCallCompletedAgentEventSchema = toolCallCompletedAgentEventSchema.extend({
34046
34198
  type: zod_default2.literal("agent.tool.call.completed")
34047
34199
  }).strict();
@@ -34096,6 +34248,7 @@ var wrappedAgentEventSchema = zod_default2.discriminatedUnion("type", [
34096
34248
  wrappedToolCallStartedAgentEventSchema,
34097
34249
  wrappedToolOutputDeltaAgentEventSchema,
34098
34250
  wrappedToolCallCompletedAgentEventSchema,
34251
+ wrappedToolOutputUpdatedAgentEventSchema,
34099
34252
  wrappedSubagentStartedAgentEventSchema,
34100
34253
  wrappedSubagentProgressAgentEventSchema,
34101
34254
  wrappedSubagentEndedAgentEventSchema,
@@ -34128,6 +34281,22 @@ function agentRuntimeIdentityKey(event) {
34128
34281
  return `${event.sessionId.length}:${event.sessionId}:${event.providerSessionId.length}:${event.providerSessionId}`;
34129
34282
  }
34130
34283
 
34284
+ // src/sessions/event-url.ts
34285
+ function sessionEventWebUrl({ sessionWebUrl, eventId }) {
34286
+ if (sessionWebUrl === undefined)
34287
+ return;
34288
+ try {
34289
+ const url3 = new URL(sessionWebUrl);
34290
+ if (url3.protocol !== "https:" && url3.protocol !== "http:" || url3.username || url3.password)
34291
+ return;
34292
+ url3.searchParams.set("event_id", eventId);
34293
+ url3.hash = "";
34294
+ return url3.href;
34295
+ } catch {
34296
+ return;
34297
+ }
34298
+ }
34299
+
34131
34300
  // src/sessions/projection.ts
34132
34301
  var sessionMessageCreatedEventSchema = exports_external2.object({
34133
34302
  type: exports_external2.literal("session.message.created"),
@@ -34218,6 +34387,7 @@ function createSessionViewState({ detail, activeMessageId }) {
34218
34387
  return {
34219
34388
  kind: "session-view",
34220
34389
  sessionId: detail.id,
34390
+ ...detail.web_url === undefined ? {} : { webUrl: detail.web_url },
34221
34391
  ...detail.sessionNumber === undefined ? {} : { sessionNumber: detail.sessionNumber },
34222
34392
  title: detail.title ?? null,
34223
34393
  aggregateStatus: detail.status,
@@ -34253,6 +34423,7 @@ function updateSessionDetail({ state, detail }) {
34253
34423
  return {
34254
34424
  ...state,
34255
34425
  sessionId: detail.id,
34426
+ ...detail.web_url === undefined ? {} : { webUrl: detail.web_url },
34256
34427
  ...detail.sessionNumber === undefined ? {} : { sessionNumber: detail.sessionNumber },
34257
34428
  ..."title" in detail ? { title: detail.title ?? null } : {},
34258
34429
  aggregateStatus: detail.status,
@@ -34277,6 +34448,7 @@ function projectRemoteSessionEvent({ state, frame }) {
34277
34448
  event: frame.data.event,
34278
34449
  occurredAt: frame.data.occurred_at,
34279
34450
  retainedEventId: frame.id,
34451
+ eventUrl: sessionEventWebUrl({ sessionWebUrl: state.webUrl, eventId: frame.data.id }),
34280
34452
  artifact: frame.data.artifact
34281
34453
  });
34282
34454
  const annotation = frame.data.context;
@@ -34313,6 +34485,7 @@ function projectRetainedEvent({
34313
34485
  event,
34314
34486
  occurredAt,
34315
34487
  retainedEventId,
34488
+ eventUrl,
34316
34489
  artifact
34317
34490
  }) {
34318
34491
  if (event.type === "session.title.generated") {
@@ -34327,7 +34500,7 @@ function projectRetainedEvent({
34327
34500
  const workspaceGitInitialized = sessionWorkspaceGitInitializedEventSchema.safeParse(event);
34328
34501
  const workspaceGitRevision = sessionWorkspaceGitRevisionEventSchema.safeParse(event);
34329
34502
  const turnEnded = agentTurnEndedEventSchema.safeParse(event);
34330
- 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 });
34503
+ 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, eventUrl }) : workspaceGitInitialized.success ? projectSessionWorkspaceGitInitialized({ state, event: workspaceGitInitialized.data, occurredAt, retainedEventId, eventUrl }) : workspaceGitRevision.success ? projectSessionWorkspaceGitRevision({ state, event: workspaceGitRevision.data, occurredAt, retainedEventId, eventUrl }) : turnEnded.success ? projectAgentTurnEnded({ state, event: turnEnded.data, occurredAt, retainedEventId, eventUrl }) : projectDurableAgentEvent({ state, event, occurredAt, retainedEventId, eventUrl });
34331
34504
  projected = recordAgentLineageEvent({ state: projected, event, retainedEventId });
34332
34505
  if (artifact) {
34333
34506
  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 };
@@ -34415,7 +34588,7 @@ function projectSessionMessageTurnAssociated({ state, event }) {
34415
34588
  };
34416
34589
  return { ...state, messageTurns: { ...state.messageTurns, [event.payload.messageId]: nextTurn } };
34417
34590
  }
34418
- function projectSessionMessageDispatch({ state, event, occurredAt, retainedEventId }) {
34591
+ function projectSessionMessageDispatch({ state, event, occurredAt, retainedEventId, eventUrl }) {
34419
34592
  if (event.type === "session.message.dispatched")
34420
34593
  return state;
34421
34594
  const withdrawn = event.type === "session.message.withdrawn";
@@ -34430,14 +34603,16 @@ function projectSessionMessageDispatch({ state, event, occurredAt, retainedEvent
34430
34603
  },
34431
34604
  occurredAt,
34432
34605
  retainedEventId,
34606
+ eventUrl,
34433
34607
  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." }
34434
34608
  });
34435
34609
  }
34436
- function projectSessionWorkspaceGitInitialized({ state, event, occurredAt, retainedEventId }) {
34610
+ function projectSessionWorkspaceGitInitialized({ state, event, occurredAt, retainedEventId, eventUrl }) {
34437
34611
  return appendActivity({
34438
34612
  state,
34439
34613
  retainedEventId,
34440
34614
  occurredAt,
34615
+ eventUrl,
34441
34616
  card: {
34442
34617
  kind: "lifecycle",
34443
34618
  weight: "signal",
@@ -34446,12 +34621,13 @@ function projectSessionWorkspaceGitInitialized({ state, event, occurredAt, retai
34446
34621
  }
34447
34622
  });
34448
34623
  }
34449
- function projectSessionWorkspaceGitRevision({ state, event, occurredAt, retainedEventId }) {
34624
+ function projectSessionWorkspaceGitRevision({ state, event, occurredAt, retainedEventId, eventUrl }) {
34450
34625
  const title = event.type === "session.workspace.git.committed" ? "Workspace committed" : "Workspace pushed";
34451
34626
  return appendActivity({
34452
34627
  state,
34453
34628
  retainedEventId,
34454
34629
  occurredAt,
34630
+ eventUrl,
34455
34631
  card: {
34456
34632
  kind: "lifecycle",
34457
34633
  weight: "signal",
@@ -34460,19 +34636,19 @@ function projectSessionWorkspaceGitRevision({ state, event, occurredAt, retained
34460
34636
  }
34461
34637
  });
34462
34638
  }
34463
- function projectAgentTurnEnded({ state, event, occurredAt, retainedEventId }) {
34639
+ function projectAgentTurnEnded({ state, event, occurredAt, retainedEventId, eventUrl }) {
34464
34640
  const stateWithTurnOutcome = event.actor.type === "main" ? {
34465
34641
  ...state,
34466
34642
  retainedTurnEnds: { ...state.retainedTurnEnds, [event.turnId]: { actorType: event.actor.type, outcome: event.payload.status } },
34467
34643
  messageTurns: Object.fromEntries(Object.entries(state.messageTurns).map(([messageId, turn]) => [messageId, turn.turnId === event.turnId ? { ...turn, outcome: event.payload.status } : turn]))
34468
34644
  } : state;
34469
34645
  const card = toAgentActivityCard(event);
34470
- return appendActivity({ state: stateWithTurnOutcome, retainedEventId, occurredAt, card });
34646
+ return appendActivity({ state: stateWithTurnOutcome, retainedEventId, occurredAt, card, eventUrl });
34471
34647
  }
34472
- function projectDurableAgentEvent({ state, event, occurredAt, retainedEventId }) {
34648
+ function projectDurableAgentEvent({ state, event, occurredAt, retainedEventId, eventUrl }) {
34473
34649
  const agentEvent = parseDurableAgentEvent(event);
34474
34650
  if (agentEvent.type === "agent.message.ended")
34475
- return projectAgentMessageEnded({ state, event: agentEvent, occurredAt, retainedEventId });
34651
+ return projectAgentMessageEnded({ state, event: agentEvent, occurredAt, retainedEventId, eventUrl });
34476
34652
  if (agentEvent.type === "agent.context.updated")
34477
34653
  return state;
34478
34654
  if (agentEvent.type === "agent.work.observed" && agentEvent.actor.type === "main")
@@ -34482,7 +34658,21 @@ function projectDurableAgentEvent({ state, event, occurredAt, retainedEventId })
34482
34658
  retainedTurnStarts: { ...state.retainedTurnStarts, [agentEvent.turnId]: { actorType: agentEvent.actor.type, startedAt: occurredAt } },
34483
34659
  messageTurns: Object.fromEntries(Object.entries(state.messageTurns).map(([messageId, turn]) => [messageId, turn.turnId === agentEvent.turnId ? { ...turn, startedAt: occurredAt } : turn]))
34484
34660
  } : state;
34485
- return appendActivity({ state: stateWithTurnStart, retainedEventId, occurredAt, card: toAgentActivityCard(agentEvent) });
34661
+ const card = toAgentActivityCard(agentEvent);
34662
+ if (agentEvent.type === "agent.tool.call.started" || agentEvent.type === "agent.tool.call.completed" || agentEvent.type === "agent.tool.output.updated") {
34663
+ const runtime = agentRuntimeIdentityKey(agentEvent);
34664
+ const actor = agentEvent.actor;
34665
+ const child = actor.type === "subagent" ? normalizeAgentSubagentIdentity(actor) : null;
34666
+ const actorIdentity = child === null ? [actor.type, actor.actorId] : [actor.type, child.actorId, child.subagentId, child.parentActorId, child.origin.type, child.origin.type === "tool_call" ? child.origin.toolCallId : child.origin.taskId, child.parentToolCallId ?? null];
34667
+ const key = JSON.stringify([runtime, state.childLineage.runtimeEpochs[runtime] ?? 0, agentEvent.turnId, actorIdentity, agentEvent.payload.toolCallId]);
34668
+ const start = agentEvent.type === "agent.tool.call.started";
34669
+ const previous = state.transcript.find((item) => item.kind === "activity" && item.card.toolCall?.key === key);
34670
+ const mcp = start ? agentEvent.payload.toolName.startsWith("mcp:") : previous?.kind === "activity" && previous.card.toolCall?.mcp === true;
34671
+ card.toolCall = { key, mcp };
34672
+ const reconciled = start ? { ...stateWithTurnStart, transcript: stateWithTurnStart.transcript.map((item) => item.kind === "activity" && item.card.toolCall?.key === key ? { ...item, card: { ...item.card, toolCall: { key, mcp } } } : item) } : stateWithTurnStart;
34673
+ return appendActivity({ state: reconciled, retainedEventId, occurredAt, card, eventUrl });
34674
+ }
34675
+ return appendActivity({ state: stateWithTurnStart, retainedEventId, occurredAt, card, eventUrl });
34486
34676
  }
34487
34677
  function hasOwnContextIdentity(identities, identity) {
34488
34678
  return Object.prototype.hasOwnProperty.call(identities, identity);
@@ -34558,7 +34748,7 @@ function patchedWorkItemId(observation) {
34558
34748
  return observation.itemId;
34559
34749
  return null;
34560
34750
  }
34561
- function projectAgentMessageEnded({ state, event, occurredAt, retainedEventId }) {
34751
+ function projectAgentMessageEnded({ state, event, occurredAt, retainedEventId, eventUrl }) {
34562
34752
  const messageId = event.payload.messageId;
34563
34753
  const text = event.payload.content.map(publicMessageContentSegmentText).join("");
34564
34754
  if (event.actor.type === "subagent") {
@@ -34574,7 +34764,7 @@ function projectAgentMessageEnded({ state, event, occurredAt, retainedEventId })
34574
34764
  detail: stripAnsi(text) || "[Empty message]"
34575
34765
  }
34576
34766
  });
34577
- return appendActivity({ state, retainedEventId, occurredAt, card });
34767
+ return appendActivity({ state, retainedEventId, occurredAt, card, eventUrl });
34578
34768
  }
34579
34769
  if (state.transcript.some((item) => item.kind === "message" && item.messageId === messageId))
34580
34770
  return state;
@@ -34587,8 +34777,8 @@ function projectAgentMessageEnded({ state, event, occurredAt, retainedEventId })
34587
34777
  transcript: [...state.transcript, { kind: "message", messageId, occurredAt, author, text: displayedText, attachments: [] }]
34588
34778
  };
34589
34779
  }
34590
- function appendActivity({ state, retainedEventId, occurredAt, card }) {
34591
- return { ...state, transcript: [...state.transcript, { kind: "activity", activityId: `activity:${retainedEventId}`, occurredAt, card }] };
34780
+ function appendActivity({ state, retainedEventId, occurredAt, card, eventUrl }) {
34781
+ return { ...state, transcript: [...state.transcript, { kind: "activity", activityId: `activity:${retainedEventId}`, occurredAt, card, ...eventUrl === undefined ? {} : { eventUrl } }] };
34592
34782
  }
34593
34783
  function toAgentActivityCard(event) {
34594
34784
  const identity = childActivityIdentity(event);
@@ -34626,17 +34816,27 @@ function toMainAgentActivityCard(event) {
34626
34816
  return {
34627
34817
  kind: "tool",
34628
34818
  weight: "signal",
34629
- title: event.payload.toolName,
34819
+ title: providerText(event.payload.toolName, "Tool"),
34630
34820
  summary: "Tool started.",
34631
34821
  ...event.payload.input === undefined ? {} : { detail: jsonDetail(event.payload.input), detailFormat: "code" }
34632
34822
  };
34633
34823
  case "agent.tool.call.completed": {
34634
34824
  const failed = event.payload.status === "failed" || event.payload.status === "cancelled";
34635
- const detail = event.payload.output === undefined ? undefined : toolOutputDetail(event.payload.output);
34636
- return failed ? { kind: "failure", weight: "signal", title: "Tool failed", summary: providerText(event.payload.error?.message, `Tool ${event.payload.status}.`), ...detail === undefined ? {} : { detail, detailFormat: "code" } } : { kind: "command-output", weight: "signal", title: "Tool completed", summary: "Tool completed.", ...detail === undefined ? {} : { detail, detailFormat: "code" } };
34825
+ const toolOutput = event.payload.output;
34826
+ return failed ? { kind: "failure", weight: "signal", title: "Tool failed", summary: providerText(event.payload.error?.message, `Tool ${event.payload.status}.`), ...toolOutput === undefined ? {} : { toolOutput } } : { kind: "command-output", weight: "signal", title: "Tool completed", summary: "Tool completed.", ...toolOutput === undefined ? {} : { toolOutput } };
34637
34827
  }
34828
+ case "agent.tool.output.updated":
34829
+ return {
34830
+ kind: "command-output",
34831
+ weight: "signal",
34832
+ title: "Tool output updated",
34833
+ summary: "Additional tool output.",
34834
+ detail: `Tool call: ${providerText(event.payload.toolCallId, "tool")}
34835
+ Background outcome: ${event.payload.output.success ? "completed" : "failed"}`,
34836
+ toolOutput: event.payload.output
34837
+ };
34638
34838
  case "agent.subagent.started":
34639
- return { kind: "progress", weight: "signal", title: "Subagent started", summary: event.payload.name ?? event.payload.subagentId };
34839
+ return { kind: "progress", weight: "signal", title: "Subagent started", summary: providerText(event.payload.name ?? event.payload.subagentId, "Subagent started.") };
34640
34840
  case "agent.subagent.progress":
34641
34841
  return { kind: "progress", weight: "signal", title: "Subagent progress", summary: providerText(event.payload.summary, "Subagent is working.") };
34642
34842
  case "agent.subagent.ended":
@@ -34708,13 +34908,26 @@ function toChildAgentActivityCard({ event, identity }) {
34708
34908
  });
34709
34909
  case "agent.tool.call.completed": {
34710
34910
  const failed = event.payload.status === "failed" || event.payload.status === "cancelled";
34711
- const detail = event.payload.output === undefined ? undefined : toolOutputDetail(event.payload.output);
34911
+ const toolOutput = event.payload.output;
34712
34912
  return createChildActivityCard({
34713
34913
  identity,
34714
34914
  activityTitle: failed ? "Tool failed" : "Tool completed",
34715
- card: failed ? { kind: "failure", weight: "signal", summary: providerText(event.payload.error?.message, `Tool ${event.payload.status}.`), ...detail === undefined ? {} : { detail, detailFormat: "code" } } : { kind: "command-output", weight: "signal", summary: "Tool completed.", ...detail === undefined ? {} : { detail, detailFormat: "code" } }
34915
+ card: failed ? { kind: "failure", weight: "signal", summary: providerText(event.payload.error?.message, `Tool ${event.payload.status}.`), ...toolOutput === undefined ? {} : { toolOutput } } : { kind: "command-output", weight: "signal", summary: "Tool completed.", ...toolOutput === undefined ? {} : { toolOutput } }
34716
34916
  });
34717
34917
  }
34918
+ case "agent.tool.output.updated":
34919
+ return createChildActivityCard({
34920
+ identity,
34921
+ activityTitle: "Tool output updated",
34922
+ card: {
34923
+ kind: "command-output",
34924
+ weight: "signal",
34925
+ summary: "Additional tool output.",
34926
+ detail: `Tool call: ${providerText(event.payload.toolCallId, "tool")}
34927
+ Background outcome: ${event.payload.output.success ? "completed" : "failed"}`,
34928
+ toolOutput: event.payload.output
34929
+ }
34930
+ });
34718
34931
  case "agent.subagent.started":
34719
34932
  return createChildActivityCard({ identity, activityTitle: "Started", card: { kind: "progress", weight: "signal", summary: providerText(event.payload.name, event.payload.subagentId) } });
34720
34933
  case "agent.subagent.progress":
@@ -35153,11 +35366,6 @@ function providerText(raw, fallback) {
35153
35366
  const cleaned = stripAnsi(raw ?? "").trim();
35154
35367
  return cleaned.length > 0 ? cleaned : fallback;
35155
35368
  }
35156
- function toolOutputDetail(output) {
35157
- const text = output.content.filter((content) => content.type === "text").map((content) => stripAnsi(content.text)).filter((text2) => text2.length > 0).join(`
35158
- `);
35159
- return text.length > 0 ? text : undefined;
35160
- }
35161
35369
  function toConnectionPreviews(detail) {
35162
35370
  return detail.connections.map((connection) => ({ provider: connection.provider, status: connection.status }));
35163
35371
  }
@@ -38114,7 +38322,98 @@ async function createDefaultRenderer2() {
38114
38322
  }
38115
38323
 
38116
38324
  // src/tui/session-view.ts
38117
- import { CliRenderEvents as CliRenderEvents4, BoxRenderable as BoxRenderable4, bg as bg4, bold as bold4, dim as dim5, fg as fg7, ScrollBoxRenderable as ScrollBoxRenderable3, StyledText as StyledText6, stringToStyledText as stringToStyledText5, TextRenderable as TextRenderable4 } from "@opentui/core";
38325
+ import { CliRenderEvents as CliRenderEvents4, BoxRenderable as BoxRenderable4, bg as bg4, bold as bold4, dim as dim5, fg as fg7, link, ScrollBoxRenderable as ScrollBoxRenderable3, StyledText as StyledText6, stringToStyledText as stringToStyledText5, TextRenderable as TextRenderable4 } from "@opentui/core";
38326
+
38327
+ // src/tui/tool-output.ts
38328
+ var maxPreviewCharacters = 8000;
38329
+ var maxPreviewBlocks = 50;
38330
+ function toolOutputPreviews(output) {
38331
+ const previews = output.content.slice(0, maxPreviewBlocks).map((content, index) => {
38332
+ const position = index + 1;
38333
+ switch (content.type) {
38334
+ case "text":
38335
+ return preview(`text \xB7 ${position}`, content.text === "" ? "Empty text block." : content.text);
38336
+ case "image":
38337
+ return preview(`image \xB7 ${position}`, "data" in content ? `${content.mimeType}
38338
+ Inline image retained.` : `Reference: ${content.uri}
38339
+ Image bytes are not embedded in this reference.`);
38340
+ case "audio":
38341
+ return preview(`audio \xB7 ${position}`, `${content.mimeType}
38342
+ Inline audio retained.`);
38343
+ case "resource": {
38344
+ const resource = content.resource;
38345
+ const metadata = `${resource.uri}
38346
+ ${resource.mimeType ?? "Media type not supplied"}`;
38347
+ return preview(`resource \xB7 ${position}`, "text" in resource ? `${metadata}
38348
+
38349
+ ${resource.text}` : `${metadata}
38350
+ Embedded binary retained.`);
38351
+ }
38352
+ case "resource_link":
38353
+ return preview(`resource link \xB7 ${position}`, [
38354
+ content.name,
38355
+ content.title === undefined ? undefined : `Title: ${content.title}`,
38356
+ content.uri,
38357
+ content.mimeType,
38358
+ content.size === undefined ? undefined : `Size: ${content.size} bytes`,
38359
+ content.description,
38360
+ "Reference only; target bytes are not embedded."
38361
+ ].filter((value) => value !== undefined).join(`
38362
+ `));
38363
+ case "json":
38364
+ return preview(`json \xB7 ${position}`, formattedJson(content.value));
38365
+ default: {
38366
+ const exhaustiveContent = content;
38367
+ return exhaustiveContent;
38368
+ }
38369
+ }
38370
+ });
38371
+ if (output.content.length === 0)
38372
+ previews.push(preview("tool output", "This tool returned no content blocks."));
38373
+ if (output.content.length > maxPreviewBlocks)
38374
+ previews.push(preview("tool output", `${output.content.length - maxPreviewBlocks} more content blocks retained. Preview shortened.`));
38375
+ if (output.structuredContent !== undefined && output.structuredContent !== null)
38376
+ previews.push(preview("structured content", formattedJson(output.structuredContent)));
38377
+ if (output.reportedSuccess !== undefined && output.reportedSuccess !== output.success) {
38378
+ previews.unshift(preview("tool outcome mismatch", `Provider outcome: ${output.success ? "success" : "failure"}
38379
+ Tool-reported outcome: ${output.reportedSuccess ? "success" : "failure"}
38380
+ The provider execution outcome is unchanged.`));
38381
+ }
38382
+ return previews;
38383
+ }
38384
+ function preview(language, text) {
38385
+ const safe = terminalSafeText(text);
38386
+ return { language, text: safe.length <= maxPreviewCharacters ? safe : `${safe.slice(0, maxPreviewCharacters)}
38387
+ Preview shortened; full output remains retained.` };
38388
+ }
38389
+ function isJsonArray(value) {
38390
+ return Array.isArray(value);
38391
+ }
38392
+ function formattedJson(value) {
38393
+ let remainingNodes = 1000;
38394
+ function presentation(value2) {
38395
+ if (--remainingNodes < 0)
38396
+ return "[Preview shortened; full value remains retained.]";
38397
+ if (typeof value2 === "string")
38398
+ return value2.length > maxPreviewCharacters ? `${value2.slice(0, maxPreviewCharacters)}\u2026 [Preview shortened]` : value2;
38399
+ if (value2 === null || typeof value2 !== "object")
38400
+ return value2;
38401
+ if (isJsonArray(value2)) {
38402
+ const values = value2.slice(0, 100).map(presentation);
38403
+ if (value2.length > 100)
38404
+ values.push(`[${value2.length - 100} more items retained]`);
38405
+ return values;
38406
+ }
38407
+ const entries = Object.entries(value2);
38408
+ const result = Object.fromEntries(entries.slice(0, 100).map(([key, item]) => [key, key === "data" && (value2.type === "image" || value2.type === "audio") || key === "blob" && typeof value2.uri === "string" ? "[Inline base64 retained; omitted from terminal preview.]" : presentation(item)]));
38409
+ if (entries.length > 100)
38410
+ result["[Preview shortened]"] = `${entries.length - 100} more fields retained`;
38411
+ return result;
38412
+ }
38413
+ return JSON.stringify(presentation(value), null, 2);
38414
+ }
38415
+
38416
+ // src/tui/session-view.ts
38118
38417
  var composerSlashCommands = [
38119
38418
  { value: "/sessions", description: "Back to the session list" },
38120
38419
  { value: "/complete", description: "Finish this session" },
@@ -39194,7 +39493,19 @@ function activityGlyph({ kind, inFlight }) {
39194
39493
  return { glyph: "\u2713", color: PALETTE.dimText };
39195
39494
  }
39196
39495
  function activityCardsHaveEqualDisclosure(left, right) {
39197
- 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);
39496
+ 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) && left.toolCall?.mcp === right.toolCall?.mcp && canonicalValuesEqual(left.toolOutput, right.toolOutput);
39497
+ }
39498
+ function canonicalValuesEqual(left, right) {
39499
+ if (Object.is(left, right))
39500
+ return true;
39501
+ if (Array.isArray(left) || Array.isArray(right)) {
39502
+ return Array.isArray(left) && Array.isArray(right) && left.length === right.length && left.every((value, index) => canonicalValuesEqual(value, right[index]));
39503
+ }
39504
+ if (typeof left !== "object" || left === null || typeof right !== "object" || right === null)
39505
+ return false;
39506
+ const leftEntries = Object.entries(left);
39507
+ const rightEntries = Object.entries(right);
39508
+ return leftEntries.length === rightEntries.length && leftEntries.every(([key, value], index) => rightEntries[index]?.[0] === key && canonicalValuesEqual(value, rightEntries[index]?.[1]));
39198
39509
  }
39199
39510
  function renderActivityGroup({ items, activityExpanded }) {
39200
39511
  if (items.length === 0)
@@ -39245,13 +39556,14 @@ function renderExpandedActivityHierarchy({ items, lastInFlightIndex }) {
39245
39556
  item,
39246
39557
  count,
39247
39558
  inFlight: item.card.kind === "tool" && index === lastInFlightIndex,
39248
- nested: attribution?.status === "resolved"
39559
+ nested: attribution?.status === "resolved",
39560
+ eventUrls: items.slice(index, index + count).flatMap((entry) => entry.eventUrl === undefined ? [] : [entry.eventUrl])
39249
39561
  }));
39250
39562
  index += count;
39251
39563
  }
39252
39564
  return rendered;
39253
39565
  }
39254
- function renderExpandedActivityStep({ item, count, inFlight, nested }) {
39566
+ function renderExpandedActivityStep({ item, count, inFlight, nested, eventUrls }) {
39255
39567
  const { glyph, color } = activityGlyph({ kind: item.card.kind, inFlight });
39256
39568
  const showSummary = item.card.summary.length > 0 && item.card.summary !== item.card.title && !boilerplateActivitySummaries.has(item.card.summary);
39257
39569
  const disclosure = renderActivityDisclosure(item.card);
@@ -39264,8 +39576,12 @@ function renderExpandedActivityStep({ item, count, inFlight, nested }) {
39264
39576
  ...showSummary ? [dim5(fg7(PALETTE.dimText)(`
39265
39577
  ${indent} ${item.card.summary}`))] : []
39266
39578
  ]);
39267
- return disclosure ? joinStyled([step, disclosure], `
39268
- `) : step;
39579
+ const links = eventUrls.map((url3) => new StyledText6([
39580
+ fg7(PALETTE.tool)(link(url3)(`${indent} View event in Web: ${url3}`))
39581
+ ]));
39582
+ const unavailable = eventUrls.length === 0 && item.card.toolOutput !== undefined ? [new StyledText6([dim5(fg7(PALETTE.dimText)(`${indent} Web event link unavailable from this server.`))])] : [];
39583
+ return joinStyled([step, ...disclosure ? [disclosure] : [], ...links, ...unavailable], `
39584
+ `);
39269
39585
  }
39270
39586
  function expandedActivityTitle(card) {
39271
39587
  if (!card.attribution)
@@ -39285,13 +39601,35 @@ function childIdentityLabel(identity) {
39285
39601
  return terminalSafeText(identity.subagentId).replace(/\s+/gu, " ").trim();
39286
39602
  }
39287
39603
  function renderActivityDisclosure(card) {
39604
+ if (card.toolOutput !== undefined && !card.toolCall?.mcp) {
39605
+ const text = legacyToolOutputText(card.toolOutput);
39606
+ if (text !== undefined) {
39607
+ const detail = card.detail === undefined ? text : `${terminalSafeText(card.detail)}
39608
+
39609
+ ${text}`;
39610
+ return renderCodeSnippet({ text: detail, indent: " " });
39611
+ }
39612
+ }
39288
39613
  const details = [];
39289
39614
  if (card.detail !== undefined) {
39290
39615
  const safeDetail = terminalSafeText(card.detail);
39291
39616
  details.push(card.detailFormat === "code" ? renderCodeSnippet({ text: safeDetail, indent: " " }) : new StyledText6([dim5(fg7(PALETTE.dimText)(` ${safeDetail}`))]));
39292
39617
  }
39618
+ const toolOutput = card.toolOutput !== undefined && card.toolCall?.mcp ? renderToolOutputDetail(card.toolOutput) : undefined;
39619
+ if (toolOutput)
39620
+ details.push(toolOutput);
39293
39621
  return details.length === 0 ? undefined : joinStyled(details, `
39294
39622
 
39623
+ `);
39624
+ }
39625
+ function legacyToolOutputText(output) {
39626
+ const text = output.content.filter((content) => content.type === "text").map((content) => terminalSafeText(content.text)).filter((text2) => text2.length > 0).join(`
39627
+ `);
39628
+ return text.length > 0 ? text : undefined;
39629
+ }
39630
+ function renderToolOutputDetail(output) {
39631
+ return joinStyled(toolOutputPreviews(output).map(({ language, text }) => renderCodeSnippet({ text, language, indent: " " })), `
39632
+
39295
39633
  `);
39296
39634
  }
39297
39635
  function renderActivitySummary({ items, includeTimestamp }) {
@@ -39686,7 +40024,7 @@ var compactMarkRows = 9;
39686
40024
  var compactMinWidth = 48;
39687
40025
  var compactMinHeight = 20;
39688
40026
  var markBrightnessGain = 4.2;
39689
- var remyCliVersion = "1.17.2";
40027
+ var remyCliVersion = "1.18.0-rc.0";
39690
40028
  async function showRemySplash({
39691
40029
  createRenderer = createRemyRenderer,
39692
40030
  durationMs = splashDurationMs,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@meistrari/remy-cli",
3
- "version": "1.17.2",
3
+ "version": "1.18.0-rc.0",
4
4
  "description": "Remy, the Coding Agent terminal client.",
5
5
  "type": "module",
6
6
  "bin": {