@ours.network/fleet 0.16.0 → 0.17.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.
@@ -13,6 +13,9 @@ const CANCEL_SETTLE_GRACE_MS = 15_000;
13
13
  const PERMISSION_TIMEOUT_MS = 10 * 60_000;
14
14
  /** Spec §4.3: 10-15 s before a vanished controller triggers the unattended policy. */
15
15
  const CONTROLLER_GRACE_MS = 12_000;
16
+ /** Bound safe-boundary waiting without turning a hung tool into cancellation. */
17
+ export const AFTER_TOOL_BOUNDARY_TIMEOUT_MS = 120_000;
18
+ const TERMINAL_TOOL_STATUSES = new Set(['completed', 'failed']);
16
19
  const SCHEDULED_LOOP_REDACTION = '[scheduled-loop content redacted]';
17
20
  const OWNER_COMMENTARY_REDACTION = '[assistant commentary redacted]';
18
21
  const scheduledTurn = (turn) => turn?.origin?.kind === 'scheduled-loop';
@@ -95,9 +98,13 @@ export class AcpSession {
95
98
  runtimeModel;
96
99
  reasoningEffort;
97
100
  controllerCount = 0;
101
+ closing = false;
98
102
  /** Armed when the last controller detaches; unattended policy applies on fire. */
99
103
  controllerGrace;
100
104
  cancelEscalation;
105
+ /** ACP-authenticated in-flight calls, including independently reserved permissions. */
106
+ activeToolCalls = new Map();
107
+ toolBoundaryWaiters = new Set();
101
108
  activeTurn;
102
109
  constructor(options, child, connection) {
103
110
  this.options = options;
@@ -215,6 +222,142 @@ export class AcpSession {
215
222
  permissionMode: this.options.permissionMode,
216
223
  };
217
224
  }
225
+ toolCall(toolCallId) {
226
+ const existing = this.activeToolCalls.get(toolCallId);
227
+ if (existing)
228
+ return existing;
229
+ const created = { lifecycle: false, permissions: new Map() };
230
+ this.activeToolCalls.set(toolCallId, created);
231
+ return created;
232
+ }
233
+ reserveTool(toolCallId) {
234
+ if (toolCallId)
235
+ this.toolCall(toolCallId).lifecycle = true;
236
+ }
237
+ reservePermission(toolCallId, permissionId) {
238
+ if (toolCallId)
239
+ this.toolCall(toolCallId).permissions.set(permissionId, 'pending');
240
+ }
241
+ allowPermission(toolCallId, permissionId) {
242
+ if (!toolCallId)
243
+ return;
244
+ const permission = this.activeToolCalls.get(toolCallId)?.permissions;
245
+ if (permission?.has(permissionId))
246
+ permission.set(permissionId, 'allowed');
247
+ }
248
+ releasePermission(toolCallId, permissionId) {
249
+ const call = toolCallId && this.activeToolCalls.get(toolCallId);
250
+ if (!call || !call.permissions.delete(permissionId))
251
+ return;
252
+ this.releaseToolIfIdle(toolCallId, call);
253
+ }
254
+ releaseTool(toolCallId) {
255
+ const call = toolCallId && this.activeToolCalls.get(toolCallId);
256
+ if (!call)
257
+ return;
258
+ call.lifecycle = false;
259
+ // Terminal tool evidence consumes permissions already granted for this
260
+ // call, but never a separate request that is still awaiting a decision.
261
+ for (const [permissionId, state] of call.permissions)
262
+ if (state === 'allowed')
263
+ call.permissions.delete(permissionId);
264
+ this.releaseToolIfIdle(toolCallId, call);
265
+ }
266
+ releaseToolIfIdle(toolCallId, call) {
267
+ if (call.lifecycle || call.permissions.size > 0)
268
+ return;
269
+ if (!this.activeToolCalls.delete(toolCallId) || this.activeToolCalls.size > 0)
270
+ return;
271
+ for (const notify of [...this.toolBoundaryWaiters])
272
+ notify();
273
+ }
274
+ releaseAllTools() {
275
+ if (this.activeToolCalls.size === 0)
276
+ return;
277
+ this.activeToolCalls.clear();
278
+ for (const notify of [...this.toolBoundaryWaiters])
279
+ notify();
280
+ }
281
+ waitForToolBoundary(timeoutMs) {
282
+ if (this.activeToolCalls.size === 0)
283
+ return Promise.resolve(true);
284
+ return new Promise(resolve => {
285
+ let settled = false;
286
+ const finish = (atBoundary) => {
287
+ if (settled)
288
+ return;
289
+ settled = true;
290
+ clearTimeout(timer);
291
+ this.toolBoundaryWaiters.delete(check);
292
+ resolve(atBoundary);
293
+ };
294
+ const check = () => {
295
+ if (this.activeToolCalls.size === 0 || !this.isAlive())
296
+ finish(this.activeToolCalls.size === 0);
297
+ };
298
+ const timer = setTimeout(() => finish(false), Math.max(0, timeoutMs));
299
+ timer.unref?.();
300
+ this.toolBoundaryWaiters.add(check);
301
+ // Close the subscribe/check race without guessing about elapsed time.
302
+ check();
303
+ });
304
+ }
305
+ recordAfterToolDelivery(state, activeToolCount, waitedMs) {
306
+ this.events.emit('monitor_delivery', {
307
+ status: state, monitorPolicy: 'after_tool', activeToolCount, waitedMs,
308
+ });
309
+ this.conversation.appendSafe({
310
+ kind: 'monitor.delivery', sessionGeneration: this.sessionGeneration,
311
+ acpSessionId: this.sessionId, source: 'fleet_monitor',
312
+ payload: { policy: 'after_tool', state, activeToolCount, waitedMs },
313
+ });
314
+ }
315
+ /**
316
+ * Monitor-only safe-boundary delivery. Steering is the interruption: this
317
+ * path never calls session/cancel and never resolves a pending permission.
318
+ */
319
+ async submitPromptAfterTool(text, options = {}) {
320
+ if (this.closing || !this.isAlive())
321
+ return turnResult(false, 'failed', this.lastError ?? 'ACP session is closing');
322
+ const startedAt = Date.now();
323
+ const initialToolCount = this.activeToolCalls.size;
324
+ if (!this.steeringSupported) {
325
+ this.recordAfterToolDelivery('unsupported', initialToolCount, 0);
326
+ const result = await this.submitPrompt(text, { ...options, interrupt: false, steer: false });
327
+ return {
328
+ ...result,
329
+ safeBoundary: { state: 'unsupported', waitedMs: 0, activeToolCount: initialToolCount },
330
+ };
331
+ }
332
+ if (initialToolCount === 0) {
333
+ this.recordAfterToolDelivery('direct', 0, 0);
334
+ const result = await this.steerPrompt(text);
335
+ return { ...result, safeBoundary: { state: 'direct', waitedMs: 0, activeToolCount: 0 } };
336
+ }
337
+ this.recordAfterToolDelivery('deferred', initialToolCount, 0);
338
+ const timeoutMs = this.options.afterToolBoundaryTimeoutMs ?? AFTER_TOOL_BOUNDARY_TIMEOUT_MS;
339
+ const deadline = startedAt + timeoutMs;
340
+ let atBoundary = false;
341
+ // Re-check after every wake: another authenticated tool event may have
342
+ // arrived before this continuation ran. Only an empty tracked set is safe.
343
+ while (this.activeToolCalls.size > 0) {
344
+ const remaining = deadline - Date.now();
345
+ if (remaining <= 0 || !(await this.waitForToolBoundary(remaining)))
346
+ break;
347
+ }
348
+ atBoundary = this.activeToolCalls.size === 0;
349
+ if (this.closing || !this.isAlive())
350
+ return turnResult(false, 'failed', this.lastError ?? 'ACP session closed during after_tool wait');
351
+ const waitedMs = Math.max(0, Date.now() - startedAt);
352
+ const state = atBoundary ? 'after_tool' : 'timeout';
353
+ const remainingToolCount = this.activeToolCalls.size;
354
+ this.recordAfterToolDelivery(state, remainingToolCount, waitedMs);
355
+ const result = await this.steerPrompt(text);
356
+ return {
357
+ ...result,
358
+ safeBoundary: { state, waitedMs, activeToolCount: remainingToolCount },
359
+ };
360
+ }
218
361
  /**
219
362
  * Accept responsibility for a prompt, then return. The turn itself may run
220
363
  * for minutes behind other queued turns; making an interactive caller wait
@@ -365,6 +508,10 @@ export class AcpSession {
365
508
  clearTimeout(pending.expiry);
366
509
  pending.resolve({ outcome: { outcome: 'selected', optionId } });
367
510
  const decision = chosen.kind.startsWith('reject') ? 'denied' : 'allowed';
511
+ if (decision === 'allowed')
512
+ this.allowPermission(pending.toolCallId, permissionId);
513
+ else
514
+ this.releasePermission(pending.toolCallId, permissionId);
368
515
  this.events.emit('permission', {
369
516
  turnId: this.activeTurn?.id,
370
517
  origin: this.activeTurn?.origin,
@@ -381,7 +528,7 @@ export class AcpSession {
381
528
  promptId: this.activeTurn?.id, turnId: this.activeTurn?.id,
382
529
  payload: { decision, decisionSource: 'manual', optionId },
383
530
  });
384
- this.readiness = 'running';
531
+ this.readiness = this.pendingPermissions.size > 0 ? 'awaiting_permission' : 'running';
385
532
  return true;
386
533
  }
387
534
  /**
@@ -446,11 +593,12 @@ export class AcpSession {
446
593
  ? { outcome: { outcome: 'selected', optionId: rejectOption.optionId } }
447
594
  : { outcome: { outcome: 'cancelled' } });
448
595
  const settled = decision === 'denied' && !rejectOption ? 'cancelled' : decision;
596
+ this.releasePermission(pending.toolCallId, permissionId);
449
597
  this.events.emit('permission', {
450
598
  turnId: this.activeTurn?.id,
451
599
  origin: this.activeTurn?.origin,
452
600
  permissionId,
453
- toolCallId: pending.toolCallId,
601
+ toolCallId: pending.eventToolCallId,
454
602
  status: 'completed',
455
603
  decision: settled === 'expired' ? 'cancelled' : settled,
456
604
  decisionSource: 'automatic',
@@ -462,7 +610,7 @@ export class AcpSession {
462
610
  kind: 'permission.resolved', sessionGeneration: this.sessionGeneration,
463
611
  acpSessionId: this.sessionId, permissionId,
464
612
  promptId: this.activeTurn?.id, turnId: this.activeTurn?.id,
465
- toolCallId: pending.toolCallId,
613
+ toolCallId: pending.eventToolCallId,
466
614
  payload: {
467
615
  decision: settled, decisionSource: 'automatic',
468
616
  ...(policy ? { policy } : {}), reason,
@@ -476,6 +624,7 @@ export class AcpSession {
476
624
  return this.exit;
477
625
  }
478
626
  async close() {
627
+ this.closing = true;
479
628
  if (this.cancelEscalation)
480
629
  clearTimeout(this.cancelEscalation);
481
630
  this.cancelEscalation = undefined;
@@ -484,6 +633,7 @@ export class AcpSession {
484
633
  this.controllerGrace = undefined;
485
634
  for (const [permissionId, pending] of [...this.pendingPermissions])
486
635
  this.settlePendingAutomatically(permissionId, pending, 'cancelled', undefined, 'the session closed while this request was pending');
636
+ this.releaseAllTools();
487
637
  if (this.sessionId && this.capabilities?.sessionCapabilities?.close != null) {
488
638
  await this.connection.agent.request(acp.methods.agent.session.close, { sessionId: this.sessionId }).catch(() => undefined);
489
639
  }
@@ -627,6 +777,7 @@ export class AcpSession {
627
777
  return turnResult(false, 'failed', this.lastError, this.activeTurn?.id === turnId ? this.activeTurn.output : undefined);
628
778
  }
629
779
  finally {
780
+ this.releaseAllTools();
630
781
  if (this.activeTurn?.id === turnId) {
631
782
  if (this.cancelEscalation)
632
783
  clearTimeout(this.cancelEscalation);
@@ -667,9 +818,19 @@ export class AcpSession {
667
818
  }
668
819
  return undefined;
669
820
  };
821
+ const toolCallId = params.toolCall.toolCallId;
822
+ const permissionId = randomUUID();
823
+ // Permission is part of the tool lifecycle. Reserve before any policy or
824
+ // human decision so a monitor wake cannot slip between request and answer.
825
+ this.reservePermission(toolCallId, permissionId);
670
826
  if (this.options.permissions.approval === 'allow' && this.withinAutomaticBoundary(params)) {
671
827
  const option = choose(['allow_always', 'allow_once']);
672
- return Promise.resolve(this.settleAutomatically(params, option, 'allowed', 'permissions.approval=allow', `the request is inside the ${this.options.permissions.filesystem} boundary`));
828
+ const response = this.settleAutomatically(params, option, 'allowed', 'permissions.approval=allow', `the request is inside the ${this.options.permissions.filesystem} boundary`);
829
+ if (option)
830
+ this.allowPermission(toolCallId, permissionId);
831
+ else
832
+ this.releasePermission(toolCallId, permissionId);
833
+ return Promise.resolve(response);
673
834
  }
674
835
  // A live grace window still counts as attended: the controller may be
675
836
  // mid-reconnect, and denying instantly is exactly what the grace prevents.
@@ -680,11 +841,12 @@ export class AcpSession {
680
841
  // a decision no human made, so one unattended denial would silently disable
681
842
  // the tool for the rest of the session.
682
843
  const option = choose(['reject_once', 'reject_always']);
683
- return Promise.resolve(this.settleAutomatically(params, option, 'denied', unattended ? 'permissions.unattended=deny' : 'permissions.approval=deny', unattended
844
+ const response = this.settleAutomatically(params, option, 'denied', unattended ? 'permissions.unattended=deny' : 'permissions.approval=deny', unattended
684
845
  ? 'no controller is attached, so the request cannot be shown to anyone'
685
- : 'the role denies every permission request by policy'));
846
+ : 'the role denies every permission request by policy');
847
+ this.releasePermission(toolCallId, permissionId);
848
+ return Promise.resolve(response);
686
849
  }
687
- const permissionId = randomUUID();
688
850
  const timeoutMs = this.options.permissionTimeoutMs ?? PERMISSION_TIMEOUT_MS;
689
851
  const expiresAt = new Date(Date.now() + timeoutMs).toISOString();
690
852
  this.readiness = 'awaiting_permission';
@@ -723,8 +885,8 @@ export class AcpSession {
723
885
  return new Promise(resolve => {
724
886
  const pending = {
725
887
  options: params.options, resolve,
726
- toolCallId: scheduledTurn(this.activeTurn)
727
- ? 'scheduled-loop-tool' : params.toolCall.toolCallId,
888
+ toolCallId,
889
+ eventToolCallId: scheduledTurn(this.activeTurn) ? 'scheduled-loop-tool' : toolCallId,
728
890
  };
729
891
  pending.expiry = setTimeout(() => {
730
892
  this.settlePendingAutomatically(permissionId, pending, 'expired', undefined, `no decision arrived within ${Math.round(timeoutMs / 1000)}s`);
@@ -832,6 +994,10 @@ export class AcpSession {
832
994
  title: scheduled ? 'scheduled-loop tool' : update.title,
833
995
  status: update.status,
834
996
  });
997
+ if (TERMINAL_TOOL_STATUSES.has(update.status ?? ''))
998
+ this.releaseTool(update.toolCallId);
999
+ else
1000
+ this.reserveTool(update.toolCallId);
835
1001
  break;
836
1002
  case 'tool_call_update':
837
1003
  this.events.emit('tool_update', {
@@ -841,6 +1007,10 @@ export class AcpSession {
841
1007
  title: scheduled ? 'scheduled-loop tool' : update.title ?? undefined,
842
1008
  status: update.status ?? undefined,
843
1009
  });
1010
+ if (TERMINAL_TOOL_STATUSES.has(update.status ?? ''))
1011
+ this.releaseTool(update.toolCallId);
1012
+ else if (update.status !== undefined)
1013
+ this.reserveTool(update.toolCallId);
844
1014
  break;
845
1015
  default:
846
1016
  break;
@@ -864,7 +1034,10 @@ export class AcpSession {
864
1034
  }
865
1035
  /** Normalize every ACP update losslessly into the durable ledger. */
866
1036
  recordConversationUpdate(update, scheduled, commentary = false) {
867
- const normalized = normalizeSessionUpdate(update, scheduled ? { redactText: SCHEDULED_LOOP_REDACTION }
1037
+ const normalized = normalizeSessionUpdate(update, scheduled ? {
1038
+ redactText: SCHEDULED_LOOP_REDACTION,
1039
+ redactToolCallId: 'scheduled-loop-tool',
1040
+ }
868
1041
  : commentary ? { redactText: OWNER_COMMENTARY_REDACTION } : {});
869
1042
  this.conversation.appendSafe({
870
1043
  kind: normalized.kind,
@@ -27,6 +27,11 @@ export declare class RoleTurnArbiter implements SessionHandle {
27
27
  private track;
28
28
  queuePrompt(text: string, options?: SubmitPromptOptions): Promise<QueuedPrompt>;
29
29
  submitPrompt(text: string, options?: SubmitPromptOptions): Promise<TurnResult>;
30
+ /**
31
+ * Do not hold `exclusive` while ACP waits for a tool boundary: permission
32
+ * answers and explicit interrupts must remain able to pass immediately.
33
+ */
34
+ submitPromptAfterTool(text: string, options?: SubmitPromptOptions): Promise<TurnResult>;
30
35
  tryScheduled(text: string, origin: Extract<PromptOrigin, {
31
36
  kind: 'scheduled-loop';
32
37
  }>, beforeQueue?: () => void | Promise<void>): Promise<ScheduledAttempt>;
@@ -32,6 +32,14 @@ export class RoleTurnArbiter {
32
32
  async submitPrompt(text, options = {}) {
33
33
  return (await this.queuePrompt(text, options)).completion;
34
34
  }
35
+ /**
36
+ * Do not hold `exclusive` while ACP waits for a tool boundary: permission
37
+ * answers and explicit interrupts must remain able to pass immediately.
38
+ */
39
+ submitPromptAfterTool(text, options = {}) {
40
+ return this.session.submitPromptAfterTool?.(text, options)
41
+ ?? this.session.submitPrompt(text, { ...options, interrupt: false, steer: false });
42
+ }
35
43
  async tryScheduled(text, origin, beforeQueue) {
36
44
  // Give owner/console/I/O callbacks already ready in this event-loop turn a
37
45
  // chance to claim the arbiter first. Scheduled work is best-effort; humans
@@ -23,6 +23,12 @@ export interface NormalizeOptions {
23
23
  * digest. Used for scheduled-loop turns whose output must not be retained.
24
24
  */
25
25
  redactText?: string;
26
+ /**
27
+ * Replace ACP tool-call IDs in both the normalized event correlation field
28
+ * and payload. The caller may still use the original update for in-memory
29
+ * lifecycle tracking without persisting its private identifier.
30
+ */
31
+ redactToolCallId?: string;
26
32
  }
27
33
  export interface NormalizedUpdate {
28
34
  kind: ConversationEventKind;
@@ -203,9 +203,10 @@ function normalizeToolContent(raw, redact) {
203
203
  }
204
204
  });
205
205
  }
206
- function toolUpsert(update, snapshot, redact) {
206
+ function toolUpsert(update, snapshot, options) {
207
+ const redact = options.redactText;
207
208
  const payload = {
208
- toolCallId: asString(update.toolCallId) ?? '',
209
+ toolCallId: options.redactToolCallId ?? asString(update.toolCallId) ?? '',
209
210
  snapshot,
210
211
  };
211
212
  if (asString(update.title) !== undefined)
@@ -271,7 +272,7 @@ export function normalizeSessionUpdate(update, options = {}) {
271
272
  }
272
273
  case 'tool_call':
273
274
  case 'tool_call_update': {
274
- const payload = toolUpsert(raw, raw.sessionUpdate === 'tool_call', redact);
275
+ const payload = toolUpsert(raw, raw.sessionUpdate === 'tool_call', options);
275
276
  return withMeta({
276
277
  kind: 'tool.upsert', payload,
277
278
  ...(payload.toolCallId ? { toolCallId: payload.toolCallId } : {}),
@@ -7,7 +7,7 @@ import type { PromptOrigin, TurnCancellationSource, TurnOutcome } from './types.
7
7
  * file touches the wire: ACP updates are reduced into these shapes by the
8
8
  * normalizer, and the store (phase 1) assigns `seq`/`eventId`/timestamps.
9
9
  */
10
- export type ConversationEventKind = 'prompt.admitted' | 'prompt.started' | 'prompt.interrupt_requested' | 'message.chunk' | 'message.replace' | 'thought.chunk' | 'thought.replace' | 'plan.replace' | 'tool.upsert' | 'tool.content_chunk' | 'permission.requested' | 'permission.resolved' | 'usage.updated' | 'turn.state' | 'turn.completed' | 'session.state' | 'session.info' | 'capabilities.updated' | 'error'
10
+ export type ConversationEventKind = 'prompt.admitted' | 'prompt.started' | 'prompt.interrupt_requested' | 'message.chunk' | 'message.replace' | 'thought.chunk' | 'thought.replace' | 'plan.replace' | 'tool.upsert' | 'tool.content_chunk' | 'permission.requested' | 'permission.resolved' | 'monitor.delivery' | 'usage.updated' | 'turn.state' | 'turn.completed' | 'session.state' | 'session.info' | 'capabilities.updated' | 'error'
11
11
  /** A well-formed ACP update this version cannot represent. Bounded, never a crash. */
12
12
  | 'unsupported';
13
13
  /** Where a conversation record came from. Typed provenance, never prompt text. */
@@ -178,6 +178,13 @@ export interface PermissionResolvedPayload {
178
178
  policy?: string;
179
179
  reason?: string;
180
180
  }
181
+ /** Body-free monitor evidence. Tool ids, titles, output, and wake text are never stored. */
182
+ export interface MonitorDeliveryPayload {
183
+ policy: 'after_tool';
184
+ state: 'deferred' | 'direct' | 'after_tool' | 'timeout' | 'unsupported';
185
+ activeToolCount: number;
186
+ waitedMs: number;
187
+ }
181
188
  export interface TurnStatePayload {
182
189
  state: 'queued' | 'running' | 'awaiting_permission' | 'interrupt_requested';
183
190
  }
@@ -201,7 +208,7 @@ export interface BoundedJson {
201
208
  digest?: string;
202
209
  redacted?: true;
203
210
  }
204
- export type ConversationPayload = MessageChunkPayload | ThoughtChunkPayload | PlanReplacePayload | ToolUpsertPayload | UsageUpdatedPayload | SessionStatePayload | SessionInfoPayload | CapabilitiesUpdatedPayload | UnsupportedPayload | PromptAdmittedPayload | PromptStartedPayload | PromptInterruptRequestedPayload | PermissionRequestedPayload | PermissionResolvedPayload | TurnStatePayload | TurnCompletedPayload | SessionLifecyclePayload | ErrorPayload;
211
+ export type ConversationPayload = MessageChunkPayload | ThoughtChunkPayload | PlanReplacePayload | ToolUpsertPayload | UsageUpdatedPayload | SessionStatePayload | SessionInfoPayload | CapabilitiesUpdatedPayload | UnsupportedPayload | PromptAdmittedPayload | PromptStartedPayload | PromptInterruptRequestedPayload | PermissionRequestedPayload | PermissionResolvedPayload | TurnStatePayload | TurnCompletedPayload | MonitorDeliveryPayload | SessionLifecyclePayload | ErrorPayload;
205
212
  export interface ConversationEventV1 {
206
213
  schemaVersion: 1;
207
214
  roleId: string;
@@ -49,6 +49,12 @@ export interface TurnResult {
49
49
  cancellationSource?: TurnCancellationSource;
50
50
  /** Final assistant text captured structurally by a backend, when available. */
51
51
  output?: string;
52
+ /** Body-free monitor safe-boundary disposition, when this was an after_tool wake. */
53
+ safeBoundary?: {
54
+ state: 'direct' | 'after_tool' | 'timeout' | 'unsupported';
55
+ waitedMs: number;
56
+ activeToolCount: number;
57
+ };
52
58
  }
53
59
  /**
54
60
  * Why a control operation failed. The distinctions exist because collapsing
@@ -137,7 +143,7 @@ export interface SessionSnapshot {
137
143
  nativeMode: string;
138
144
  };
139
145
  }
140
- export type SessionEventKind = 'state' | 'agent_text' | 'thought' | 'tool_call' | 'tool_update' | 'permission' | 'turn_stop' | 'error';
146
+ export type SessionEventKind = 'state' | 'agent_text' | 'thought' | 'tool_call' | 'tool_update' | 'permission' | 'monitor_delivery' | 'turn_stop' | 'error';
141
147
  /** What a settled permission request resolved to. */
142
148
  export type PermissionDecision = 'allowed' | 'denied' | 'cancelled';
143
149
  export interface SessionEvent {
@@ -178,6 +184,10 @@ export interface SessionEvent {
178
184
  reason?: string;
179
185
  /** The option actually selected, when one was. */
180
186
  optionId?: string;
187
+ /** Body-free evidence for monitor safe-boundary delivery. */
188
+ monitorPolicy?: 'after_tool';
189
+ activeToolCount?: number;
190
+ waitedMs?: number;
181
191
  }
182
192
  export interface ConversationHandlePage {
183
193
  events: ConversationEventV1[];
@@ -206,6 +216,8 @@ export interface SessionHandle {
206
216
  queuePrompt(text: string, options?: SubmitPromptOptions): Promise<QueuedPrompt>;
207
217
  /** Queue a prompt and wait for its terminal result. */
208
218
  submitPrompt(text: string, options?: SubmitPromptOptions): Promise<TurnResult>;
219
+ /** Monitor-only ACP safe-boundary delivery. Never implies human/control cancellation. */
220
+ submitPromptAfterTool?(text: string, options?: SubmitPromptOptions): Promise<TurnResult>;
209
221
  interrupt(source?: TurnCancellationSource): Promise<void>;
210
222
  respondPermission(permissionId: string, optionId: string): boolean;
211
223
  /** Generation-bound browser decision; stale/settled/invalid all fail closed. */
@@ -1,4 +1,4 @@
1
- import{r as le,a as Ee,j as re}from"./index-CsHEL0f6.js";var ge={exports:{}},Se;function ke(){return Se||(Se=1,(function(se,ne){(function(Q,X){se.exports=X()})(globalThis,(()=>(()=>{var Q={4567:function(B,r,o){var l=this&&this.__decorate||function(e,i,a,v){var f,g=arguments.length,c=g<3?i:v===null?v=Object.getOwnPropertyDescriptor(i,a):v;if(typeof Reflect=="object"&&typeof Reflect.decorate=="function")c=Reflect.decorate(e,i,a,v);else for(var m=e.length-1;m>=0;m--)(f=e[m])&&(c=(g<3?f(c):g>3?f(i,a,c):f(i,a))||c);return g>3&&c&&Object.defineProperty(i,a,c),c},_=this&&this.__param||function(e,i){return function(a,v){i(a,v,e)}};Object.defineProperty(r,"__esModule",{value:!0}),r.AccessibilityManager=void 0;const n=o(9042),d=o(9924),u=o(844),p=o(4725),h=o(2585),t=o(3656);let s=r.AccessibilityManager=class extends u.Disposable{constructor(e,i,a,v){super(),this._terminal=e,this._coreBrowserService=a,this._renderService=v,this._rowColumns=new WeakMap,this._liveRegionLineCount=0,this._charsToConsume=[],this._charsToAnnounce="",this._accessibilityContainer=this._coreBrowserService.mainDocument.createElement("div"),this._accessibilityContainer.classList.add("xterm-accessibility"),this._rowContainer=this._coreBrowserService.mainDocument.createElement("div"),this._rowContainer.setAttribute("role","list"),this._rowContainer.classList.add("xterm-accessibility-tree"),this._rowElements=[];for(let f=0;f<this._terminal.rows;f++)this._rowElements[f]=this._createAccessibilityTreeNode(),this._rowContainer.appendChild(this._rowElements[f]);if(this._topBoundaryFocusListener=f=>this._handleBoundaryFocus(f,0),this._bottomBoundaryFocusListener=f=>this._handleBoundaryFocus(f,1),this._rowElements[0].addEventListener("focus",this._topBoundaryFocusListener),this._rowElements[this._rowElements.length-1].addEventListener("focus",this._bottomBoundaryFocusListener),this._refreshRowsDimensions(),this._accessibilityContainer.appendChild(this._rowContainer),this._liveRegion=this._coreBrowserService.mainDocument.createElement("div"),this._liveRegion.classList.add("live-region"),this._liveRegion.setAttribute("aria-live","assertive"),this._accessibilityContainer.appendChild(this._liveRegion),this._liveRegionDebouncer=this.register(new d.TimeBasedDebouncer(this._renderRows.bind(this))),!this._terminal.element)throw new Error("Cannot enable accessibility before Terminal.open");this._terminal.element.insertAdjacentElement("afterbegin",this._accessibilityContainer),this.register(this._terminal.onResize((f=>this._handleResize(f.rows)))),this.register(this._terminal.onRender((f=>this._refreshRows(f.start,f.end)))),this.register(this._terminal.onScroll((()=>this._refreshRows()))),this.register(this._terminal.onA11yChar((f=>this._handleChar(f)))),this.register(this._terminal.onLineFeed((()=>this._handleChar(`
1
+ import{r as le,a as Ee,j as re}from"./index-CliHATFt.js";var ge={exports:{}},Se;function ke(){return Se||(Se=1,(function(se,ne){(function(Q,X){se.exports=X()})(globalThis,(()=>(()=>{var Q={4567:function(B,r,o){var l=this&&this.__decorate||function(e,i,a,v){var f,g=arguments.length,c=g<3?i:v===null?v=Object.getOwnPropertyDescriptor(i,a):v;if(typeof Reflect=="object"&&typeof Reflect.decorate=="function")c=Reflect.decorate(e,i,a,v);else for(var m=e.length-1;m>=0;m--)(f=e[m])&&(c=(g<3?f(c):g>3?f(i,a,c):f(i,a))||c);return g>3&&c&&Object.defineProperty(i,a,c),c},_=this&&this.__param||function(e,i){return function(a,v){i(a,v,e)}};Object.defineProperty(r,"__esModule",{value:!0}),r.AccessibilityManager=void 0;const n=o(9042),d=o(9924),u=o(844),p=o(4725),h=o(2585),t=o(3656);let s=r.AccessibilityManager=class extends u.Disposable{constructor(e,i,a,v){super(),this._terminal=e,this._coreBrowserService=a,this._renderService=v,this._rowColumns=new WeakMap,this._liveRegionLineCount=0,this._charsToConsume=[],this._charsToAnnounce="",this._accessibilityContainer=this._coreBrowserService.mainDocument.createElement("div"),this._accessibilityContainer.classList.add("xterm-accessibility"),this._rowContainer=this._coreBrowserService.mainDocument.createElement("div"),this._rowContainer.setAttribute("role","list"),this._rowContainer.classList.add("xterm-accessibility-tree"),this._rowElements=[];for(let f=0;f<this._terminal.rows;f++)this._rowElements[f]=this._createAccessibilityTreeNode(),this._rowContainer.appendChild(this._rowElements[f]);if(this._topBoundaryFocusListener=f=>this._handleBoundaryFocus(f,0),this._bottomBoundaryFocusListener=f=>this._handleBoundaryFocus(f,1),this._rowElements[0].addEventListener("focus",this._topBoundaryFocusListener),this._rowElements[this._rowElements.length-1].addEventListener("focus",this._bottomBoundaryFocusListener),this._refreshRowsDimensions(),this._accessibilityContainer.appendChild(this._rowContainer),this._liveRegion=this._coreBrowserService.mainDocument.createElement("div"),this._liveRegion.classList.add("live-region"),this._liveRegion.setAttribute("aria-live","assertive"),this._accessibilityContainer.appendChild(this._liveRegion),this._liveRegionDebouncer=this.register(new d.TimeBasedDebouncer(this._renderRows.bind(this))),!this._terminal.element)throw new Error("Cannot enable accessibility before Terminal.open");this._terminal.element.insertAdjacentElement("afterbegin",this._accessibilityContainer),this.register(this._terminal.onResize((f=>this._handleResize(f.rows)))),this.register(this._terminal.onRender((f=>this._refreshRows(f.start,f.end)))),this.register(this._terminal.onScroll((()=>this._refreshRows()))),this.register(this._terminal.onA11yChar((f=>this._handleChar(f)))),this.register(this._terminal.onLineFeed((()=>this._handleChar(`
2
2
  `)))),this.register(this._terminal.onA11yTab((f=>this._handleTab(f)))),this.register(this._terminal.onKey((f=>this._handleKey(f.key)))),this.register(this._terminal.onBlur((()=>this._clearLiveRegion()))),this.register(this._renderService.onDimensionsChange((()=>this._refreshRowsDimensions()))),this.register((0,t.addDisposableDomListener)(document,"selectionchange",(()=>this._handleSelectionChange()))),this.register(this._coreBrowserService.onDprChange((()=>this._refreshRowsDimensions()))),this._refreshRows(),this.register((0,u.toDisposable)((()=>{this._accessibilityContainer.remove(),this._rowElements.length=0})))}_handleTab(e){for(let i=0;i<e;i++)this._handleChar(" ")}_handleChar(e){this._liveRegionLineCount<21&&(this._charsToConsume.length>0?this._charsToConsume.shift()!==e&&(this._charsToAnnounce+=e):this._charsToAnnounce+=e,e===`
3
3
  `&&(this._liveRegionLineCount++,this._liveRegionLineCount===21&&(this._liveRegion.textContent+=n.tooMuchOutput)))}_clearLiveRegion(){this._liveRegion.textContent="",this._liveRegionLineCount=0}_handleKey(e){this._clearLiveRegion(),new RegExp("\\p{Control}","u").test(e)||this._charsToConsume.push(e)}_refreshRows(e,i){this._liveRegionDebouncer.refresh(e,i,this._terminal.rows)}_renderRows(e,i){const a=this._terminal.buffer,v=a.lines.length.toString();for(let f=e;f<=i;f++){const g=a.lines.get(a.ydisp+f),c=[],m=g?.translateToString(!0,void 0,void 0,c)||"",E=(a.ydisp+f+1).toString(),k=this._rowElements[f];k&&(m.length===0?(k.innerText=" ",this._rowColumns.set(k,[0,1])):(k.textContent=m,this._rowColumns.set(k,c)),k.setAttribute("aria-posinset",E),k.setAttribute("aria-setsize",v))}this._announceCharacters()}_announceCharacters(){this._charsToAnnounce.length!==0&&(this._liveRegion.textContent+=this._charsToAnnounce,this._charsToAnnounce="")}_handleBoundaryFocus(e,i){const a=e.target,v=this._rowElements[i===0?1:this._rowElements.length-2];if(a.getAttribute("aria-posinset")===(i===0?"1":`${this._terminal.buffer.lines.length}`)||e.relatedTarget!==v)return;let f,g;if(i===0?(f=a,g=this._rowElements.pop(),this._rowContainer.removeChild(g)):(f=this._rowElements.shift(),g=a,this._rowContainer.removeChild(f)),f.removeEventListener("focus",this._topBoundaryFocusListener),g.removeEventListener("focus",this._bottomBoundaryFocusListener),i===0){const c=this._createAccessibilityTreeNode();this._rowElements.unshift(c),this._rowContainer.insertAdjacentElement("afterbegin",c)}else{const c=this._createAccessibilityTreeNode();this._rowElements.push(c),this._rowContainer.appendChild(c)}this._rowElements[0].addEventListener("focus",this._topBoundaryFocusListener),this._rowElements[this._rowElements.length-1].addEventListener("focus",this._bottomBoundaryFocusListener),this._terminal.scrollLines(i===0?-1:1),this._rowElements[i===0?1:this._rowElements.length-2].focus(),e.preventDefault(),e.stopImmediatePropagation()}_handleSelectionChange(){if(this._rowElements.length===0)return;const e=document.getSelection();if(!e)return;if(e.isCollapsed)return void(this._rowContainer.contains(e.anchorNode)&&this._terminal.clearSelection());if(!e.anchorNode||!e.focusNode)return void console.error("anchorNode and/or focusNode are null");let i={node:e.anchorNode,offset:e.anchorOffset},a={node:e.focusNode,offset:e.focusOffset};if((i.node.compareDocumentPosition(a.node)&Node.DOCUMENT_POSITION_PRECEDING||i.node===a.node&&i.offset>a.offset)&&([i,a]=[a,i]),i.node.compareDocumentPosition(this._rowElements[0])&(Node.DOCUMENT_POSITION_CONTAINED_BY|Node.DOCUMENT_POSITION_FOLLOWING)&&(i={node:this._rowElements[0].childNodes[0],offset:0}),!this._rowContainer.contains(i.node))return;const v=this._rowElements.slice(-1)[0];if(a.node.compareDocumentPosition(v)&(Node.DOCUMENT_POSITION_CONTAINED_BY|Node.DOCUMENT_POSITION_PRECEDING)&&(a={node:v,offset:v.textContent?.length??0}),!this._rowContainer.contains(a.node))return;const f=({node:m,offset:E})=>{const k=m instanceof Text?m.parentNode:m;let D=parseInt(k?.getAttribute("aria-posinset"),10)-1;if(isNaN(D))return console.warn("row is invalid. Race condition?"),null;const b=this._rowColumns.get(k);if(!b)return console.warn("columns is null. Race condition?"),null;let x=E<b.length?b[E]:b.slice(-1)[0]+1;return x>=this._terminal.cols&&(++D,x=0),{row:D,column:x}},g=f(i),c=f(a);if(g&&c){if(g.row>c.row||g.row===c.row&&g.column>=c.column)throw new Error("invalid range");this._terminal.select(g.column,g.row,(c.row-g.row)*this._terminal.cols-g.column+c.column)}}_handleResize(e){this._rowElements[this._rowElements.length-1].removeEventListener("focus",this._bottomBoundaryFocusListener);for(let i=this._rowContainer.children.length;i<this._terminal.rows;i++)this._rowElements[i]=this._createAccessibilityTreeNode(),this._rowContainer.appendChild(this._rowElements[i]);for(;this._rowElements.length>e;)this._rowContainer.removeChild(this._rowElements.pop());this._rowElements[this._rowElements.length-1].addEventListener("focus",this._bottomBoundaryFocusListener),this._refreshRowsDimensions()}_createAccessibilityTreeNode(){const e=this._coreBrowserService.mainDocument.createElement("div");return e.setAttribute("role","listitem"),e.tabIndex=-1,this._refreshRowDimensions(e),e}_refreshRowsDimensions(){if(this._renderService.dimensions.css.cell.height){this._accessibilityContainer.style.width=`${this._renderService.dimensions.css.canvas.width}px`,this._rowElements.length!==this._terminal.rows&&this._handleResize(this._terminal.rows);for(let e=0;e<this._terminal.rows;e++)this._refreshRowDimensions(this._rowElements[e])}}_refreshRowDimensions(e){e.style.height=`${this._renderService.dimensions.css.cell.height}px`}};r.AccessibilityManager=s=l([_(1,h.IInstantiationService),_(2,p.ICoreBrowserService),_(3,p.IRenderService)],s)},3614:(B,r)=>{function o(d){return d.replace(/\r?\n/g,"\r")}function l(d,u){return u?"\x1B[200~"+d+"\x1B[201~":d}function _(d,u,p,h){d=l(d=o(d),p.decPrivateModes.bracketedPasteMode&&h.rawOptions.ignoreBracketedPasteMode!==!0),p.triggerDataEvent(d,!0),u.value=""}function n(d,u,p){const h=p.getBoundingClientRect(),t=d.clientX-h.left-10,s=d.clientY-h.top-10;u.style.width="20px",u.style.height="20px",u.style.left=`${t}px`,u.style.top=`${s}px`,u.style.zIndex="1000",u.focus()}Object.defineProperty(r,"__esModule",{value:!0}),r.rightClickHandler=r.moveTextAreaUnderMouseCursor=r.paste=r.handlePasteEvent=r.copyHandler=r.bracketTextForPaste=r.prepareTextForTerminal=void 0,r.prepareTextForTerminal=o,r.bracketTextForPaste=l,r.copyHandler=function(d,u){d.clipboardData&&d.clipboardData.setData("text/plain",u.selectionText),d.preventDefault()},r.handlePasteEvent=function(d,u,p,h){d.stopPropagation(),d.clipboardData&&_(d.clipboardData.getData("text/plain"),u,p,h)},r.paste=_,r.moveTextAreaUnderMouseCursor=n,r.rightClickHandler=function(d,u,p,h,t){n(d,u,p),t&&h.rightClickSelect(d),u.value=h.selectionText,u.select()}},7239:(B,r,o)=>{Object.defineProperty(r,"__esModule",{value:!0}),r.ColorContrastCache=void 0;const l=o(1505);r.ColorContrastCache=class{constructor(){this._color=new l.TwoKeyMap,this._css=new l.TwoKeyMap}setCss(_,n,d){this._css.set(_,n,d)}getCss(_,n){return this._css.get(_,n)}setColor(_,n,d){this._color.set(_,n,d)}getColor(_,n){return this._color.get(_,n)}clear(){this._color.clear(),this._css.clear()}}},3656:(B,r)=>{Object.defineProperty(r,"__esModule",{value:!0}),r.addDisposableDomListener=void 0,r.addDisposableDomListener=function(o,l,_,n){o.addEventListener(l,_,n);let d=!1;return{dispose:()=>{d||(d=!0,o.removeEventListener(l,_,n))}}}},3551:function(B,r,o){var l=this&&this.__decorate||function(s,e,i,a){var v,f=arguments.length,g=f<3?e:a===null?a=Object.getOwnPropertyDescriptor(e,i):a;if(typeof Reflect=="object"&&typeof Reflect.decorate=="function")g=Reflect.decorate(s,e,i,a);else for(var c=s.length-1;c>=0;c--)(v=s[c])&&(g=(f<3?v(g):f>3?v(e,i,g):v(e,i))||g);return f>3&&g&&Object.defineProperty(e,i,g),g},_=this&&this.__param||function(s,e){return function(i,a){e(i,a,s)}};Object.defineProperty(r,"__esModule",{value:!0}),r.Linkifier=void 0;const n=o(3656),d=o(8460),u=o(844),p=o(2585),h=o(4725);let t=r.Linkifier=class extends u.Disposable{get currentLink(){return this._currentLink}constructor(s,e,i,a,v){super(),this._element=s,this._mouseService=e,this._renderService=i,this._bufferService=a,this._linkProviderService=v,this._linkCacheDisposables=[],this._isMouseOut=!0,this._wasResized=!1,this._activeLine=-1,this._onShowLinkUnderline=this.register(new d.EventEmitter),this.onShowLinkUnderline=this._onShowLinkUnderline.event,this._onHideLinkUnderline=this.register(new d.EventEmitter),this.onHideLinkUnderline=this._onHideLinkUnderline.event,this.register((0,u.getDisposeArrayDisposable)(this._linkCacheDisposables)),this.register((0,u.toDisposable)((()=>{this._lastMouseEvent=void 0,this._activeProviderReplies?.clear()}))),this.register(this._bufferService.onResize((()=>{this._clearCurrentLink(),this._wasResized=!0}))),this.register((0,n.addDisposableDomListener)(this._element,"mouseleave",(()=>{this._isMouseOut=!0,this._clearCurrentLink()}))),this.register((0,n.addDisposableDomListener)(this._element,"mousemove",this._handleMouseMove.bind(this))),this.register((0,n.addDisposableDomListener)(this._element,"mousedown",this._handleMouseDown.bind(this))),this.register((0,n.addDisposableDomListener)(this._element,"mouseup",this._handleMouseUp.bind(this)))}_handleMouseMove(s){this._lastMouseEvent=s;const e=this._positionFromMouseEvent(s,this._element,this._mouseService);if(!e)return;this._isMouseOut=!1;const i=s.composedPath();for(let a=0;a<i.length;a++){const v=i[a];if(v.classList.contains("xterm"))break;if(v.classList.contains("xterm-hover"))return}this._lastBufferCell&&e.x===this._lastBufferCell.x&&e.y===this._lastBufferCell.y||(this._handleHover(e),this._lastBufferCell=e)}_handleHover(s){if(this._activeLine!==s.y||this._wasResized)return this._clearCurrentLink(),this._askForLink(s,!1),void(this._wasResized=!1);this._currentLink&&this._linkAtPosition(this._currentLink.link,s)||(this._clearCurrentLink(),this._askForLink(s,!0))}_askForLink(s,e){this._activeProviderReplies&&e||(this._activeProviderReplies?.forEach((a=>{a?.forEach((v=>{v.link.dispose&&v.link.dispose()}))})),this._activeProviderReplies=new Map,this._activeLine=s.y);let i=!1;for(const[a,v]of this._linkProviderService.linkProviders.entries())e?this._activeProviderReplies?.get(a)&&(i=this._checkLinkProviderResult(a,s,i)):v.provideLinks(s.y,(f=>{if(this._isMouseOut)return;const g=f?.map((c=>({link:c})));this._activeProviderReplies?.set(a,g),i=this._checkLinkProviderResult(a,s,i),this._activeProviderReplies?.size===this._linkProviderService.linkProviders.length&&this._removeIntersectingLinks(s.y,this._activeProviderReplies)}))}_removeIntersectingLinks(s,e){const i=new Set;for(let a=0;a<e.size;a++){const v=e.get(a);if(v)for(let f=0;f<v.length;f++){const g=v[f],c=g.link.range.start.y<s?0:g.link.range.start.x,m=g.link.range.end.y>s?this._bufferService.cols:g.link.range.end.x;for(let E=c;E<=m;E++){if(i.has(E)){v.splice(f--,1);break}i.add(E)}}}}_checkLinkProviderResult(s,e,i){if(!this._activeProviderReplies)return i;const a=this._activeProviderReplies.get(s);let v=!1;for(let f=0;f<s;f++)this._activeProviderReplies.has(f)&&!this._activeProviderReplies.get(f)||(v=!0);if(!v&&a){const f=a.find((g=>this._linkAtPosition(g.link,e)));f&&(i=!0,this._handleNewLink(f))}if(this._activeProviderReplies.size===this._linkProviderService.linkProviders.length&&!i)for(let f=0;f<this._activeProviderReplies.size;f++){const g=this._activeProviderReplies.get(f)?.find((c=>this._linkAtPosition(c.link,e)));if(g){i=!0,this._handleNewLink(g);break}}return i}_handleMouseDown(){this._mouseDownLink=this._currentLink}_handleMouseUp(s){if(!this._currentLink)return;const e=this._positionFromMouseEvent(s,this._element,this._mouseService);e&&this._mouseDownLink===this._currentLink&&this._linkAtPosition(this._currentLink.link,e)&&this._currentLink.link.activate(s,this._currentLink.link.text)}_clearCurrentLink(s,e){this._currentLink&&this._lastMouseEvent&&(!s||!e||this._currentLink.link.range.start.y>=s&&this._currentLink.link.range.end.y<=e)&&(this._linkLeave(this._element,this._currentLink.link,this._lastMouseEvent),this._currentLink=void 0,(0,u.disposeArray)(this._linkCacheDisposables))}_handleNewLink(s){if(!this._lastMouseEvent)return;const e=this._positionFromMouseEvent(this._lastMouseEvent,this._element,this._mouseService);e&&this._linkAtPosition(s.link,e)&&(this._currentLink=s,this._currentLink.state={decorations:{underline:s.link.decorations===void 0||s.link.decorations.underline,pointerCursor:s.link.decorations===void 0||s.link.decorations.pointerCursor},isHovered:!0},this._linkHover(this._element,s.link,this._lastMouseEvent),s.link.decorations={},Object.defineProperties(s.link.decorations,{pointerCursor:{get:()=>this._currentLink?.state?.decorations.pointerCursor,set:i=>{this._currentLink?.state&&this._currentLink.state.decorations.pointerCursor!==i&&(this._currentLink.state.decorations.pointerCursor=i,this._currentLink.state.isHovered&&this._element.classList.toggle("xterm-cursor-pointer",i))}},underline:{get:()=>this._currentLink?.state?.decorations.underline,set:i=>{this._currentLink?.state&&this._currentLink?.state?.decorations.underline!==i&&(this._currentLink.state.decorations.underline=i,this._currentLink.state.isHovered&&this._fireUnderlineEvent(s.link,i))}}}),this._linkCacheDisposables.push(this._renderService.onRenderedViewportChange((i=>{if(!this._currentLink)return;const a=i.start===0?0:i.start+1+this._bufferService.buffer.ydisp,v=this._bufferService.buffer.ydisp+1+i.end;if(this._currentLink.link.range.start.y>=a&&this._currentLink.link.range.end.y<=v&&(this._clearCurrentLink(a,v),this._lastMouseEvent)){const f=this._positionFromMouseEvent(this._lastMouseEvent,this._element,this._mouseService);f&&this._askForLink(f,!1)}}))))}_linkHover(s,e,i){this._currentLink?.state&&(this._currentLink.state.isHovered=!0,this._currentLink.state.decorations.underline&&this._fireUnderlineEvent(e,!0),this._currentLink.state.decorations.pointerCursor&&s.classList.add("xterm-cursor-pointer")),e.hover&&e.hover(i,e.text)}_fireUnderlineEvent(s,e){const i=s.range,a=this._bufferService.buffer.ydisp,v=this._createLinkUnderlineEvent(i.start.x-1,i.start.y-a-1,i.end.x,i.end.y-a-1,void 0);(e?this._onShowLinkUnderline:this._onHideLinkUnderline).fire(v)}_linkLeave(s,e,i){this._currentLink?.state&&(this._currentLink.state.isHovered=!1,this._currentLink.state.decorations.underline&&this._fireUnderlineEvent(e,!1),this._currentLink.state.decorations.pointerCursor&&s.classList.remove("xterm-cursor-pointer")),e.leave&&e.leave(i,e.text)}_linkAtPosition(s,e){const i=s.range.start.y*this._bufferService.cols+s.range.start.x,a=s.range.end.y*this._bufferService.cols+s.range.end.x,v=e.y*this._bufferService.cols+e.x;return i<=v&&v<=a}_positionFromMouseEvent(s,e,i){const a=i.getCoords(s,e,this._bufferService.cols,this._bufferService.rows);if(a)return{x:a[0],y:a[1]+this._bufferService.buffer.ydisp}}_createLinkUnderlineEvent(s,e,i,a,v){return{x1:s,y1:e,x2:i,y2:a,cols:this._bufferService.cols,fg:v}}};r.Linkifier=t=l([_(1,h.IMouseService),_(2,h.IRenderService),_(3,p.IBufferService),_(4,h.ILinkProviderService)],t)},9042:(B,r)=>{Object.defineProperty(r,"__esModule",{value:!0}),r.tooMuchOutput=r.promptLabel=void 0,r.promptLabel="Terminal input",r.tooMuchOutput="Too much output to announce, navigate to rows manually to read"},3730:function(B,r,o){var l=this&&this.__decorate||function(h,t,s,e){var i,a=arguments.length,v=a<3?t:e===null?e=Object.getOwnPropertyDescriptor(t,s):e;if(typeof Reflect=="object"&&typeof Reflect.decorate=="function")v=Reflect.decorate(h,t,s,e);else for(var f=h.length-1;f>=0;f--)(i=h[f])&&(v=(a<3?i(v):a>3?i(t,s,v):i(t,s))||v);return a>3&&v&&Object.defineProperty(t,s,v),v},_=this&&this.__param||function(h,t){return function(s,e){t(s,e,h)}};Object.defineProperty(r,"__esModule",{value:!0}),r.OscLinkProvider=void 0;const n=o(511),d=o(2585);let u=r.OscLinkProvider=class{constructor(h,t,s){this._bufferService=h,this._optionsService=t,this._oscLinkService=s}provideLinks(h,t){const s=this._bufferService.buffer.lines.get(h-1);if(!s)return void t(void 0);const e=[],i=this._optionsService.rawOptions.linkHandler,a=new n.CellData,v=s.getTrimmedLength();let f=-1,g=-1,c=!1;for(let m=0;m<v;m++)if(g!==-1||s.hasContent(m)){if(s.loadCell(m,a),a.hasExtendedAttrs()&&a.extended.urlId){if(g===-1){g=m,f=a.extended.urlId;continue}c=a.extended.urlId!==f}else g!==-1&&(c=!0);if(c||g!==-1&&m===v-1){const E=this._oscLinkService.getLinkData(f)?.uri;if(E){const k={start:{x:g+1,y:h},end:{x:m+(c||m!==v-1?0:1),y:h}};let D=!1;if(!i?.allowNonHttpProtocols)try{const b=new URL(E);["http:","https:"].includes(b.protocol)||(D=!0)}catch{D=!0}D||e.push({text:E,range:k,activate:(b,x)=>i?i.activate(b,x,k):p(0,x),hover:(b,x)=>i?.hover?.(b,x,k),leave:(b,x)=>i?.leave?.(b,x,k)})}c=!1,a.hasExtendedAttrs()&&a.extended.urlId?(g=m,f=a.extended.urlId):(g=-1,f=-1)}}t(e)}};function p(h,t){if(confirm(`Do you want to navigate to ${t}?
4
4