@khorsheed/dsh-file-preview 0.1.1 → 0.3.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.
@@ -1,6 +1,9 @@
1
1
  /* Generated by @deepseek-ai/dsh-typert-generator from the Host FaceModel — do not edit. */
2
2
  import { z } from 'zod'
3
3
 
4
+ const _khorsheed_dsh_file_preview_filePreview_capabilities_result$schema = z.object({
5
+ 'protocolVersion': z.literal(1),
6
+ })
4
7
  const _khorsheed_dsh_file_preview_filePreview_list_parameter_0$schema = z.intersection(z.string(), z.unknown())
5
8
  const _khorsheed_dsh_file_preview_filePreview_list_result$schema = z.object({
6
9
  'entries': z.array(z.object({
@@ -24,11 +27,20 @@ const _khorsheed_dsh_file_preview_filePreview_list_result$schema = z.object({
24
27
  'asOfSeq': z.number().readonly(),
25
28
  'truncated': z.boolean().readonly(),
26
29
  })
30
+ const _khorsheed_dsh_file_preview_filePreview_openExternal_parameter_0$schema = z.intersection(z.string(), z.unknown())
31
+ const _khorsheed_dsh_file_preview_filePreview_openExternal_parameter_1$schema = z.string()
32
+ const _khorsheed_dsh_file_preview_filePreview_openExternal_parameter_2$schema = z.string()
33
+ const _khorsheed_dsh_file_preview_filePreview_openExternal_result$schema = z.union([z.object({
34
+ 'opened': z.literal(true).readonly(),
35
+ }), z.object({
36
+ 'opened': z.literal(false).readonly(),
37
+ 'reason': z.union([z.literal("missing"), z.literal("unknown-app"), z.literal("unsupported-platform"), z.literal("launch-failed")]).readonly(),
38
+ })])
27
39
  const _khorsheed_dsh_file_preview_filePreview_read_parameter_0$schema = z.intersection(z.string(), z.unknown())
28
40
  const _khorsheed_dsh_file_preview_filePreview_read_parameter_1$schema = z.string()
29
41
  const _khorsheed_dsh_file_preview_filePreview_read_result$schema = z.object({
30
42
  'path': z.string().readonly(),
31
- 'kind': z.union([z.literal("text"), z.literal("image"), z.literal("binary"), z.literal("missing"), z.literal("too-large"), z.literal("error")]).readonly(),
43
+ 'kind': z.union([z.literal("missing"), z.literal("error"), z.literal("text"), z.literal("image"), z.literal("binary"), z.literal("too-large")]).readonly(),
32
44
  'content': z.string().readonly().optional(),
33
45
  'url': z.string().readonly().optional(),
34
46
  'truncated': z.boolean().readonly().optional(),
@@ -62,6 +74,21 @@ const _khorsheed_dsh_file_preview_filePreview_turnFiles_result$schema = z.object
62
74
  export const TYPERT_REMOTE = {
63
75
  package: '@khorsheed/dsh-file-preview',
64
76
  descriptors: [
77
+ {
78
+ id: '@khorsheed/dsh-file-preview#filePreview/capabilities',
79
+ service: 'filePreview',
80
+ namespace: 'filePreview',
81
+ method: 'capabilities',
82
+ invocation: { kind: 'direct' },
83
+ parameters: [
84
+ ],
85
+ result: {
86
+ mode: 'strict',
87
+ typeSymbol: '@khorsheed/dsh-file-preview#filePreview/capabilities:result',
88
+ schema: _khorsheed_dsh_file_preview_filePreview_capabilities_result$schema,
89
+ },
90
+ sourceLocation: {"file":"packages/file-preview/src/index.ts","line":191,"column":3},
91
+ },
65
92
  {
66
93
  id: '@khorsheed/dsh-file-preview#filePreview/list',
67
94
  service: 'filePreview',
@@ -90,7 +117,58 @@ export const TYPERT_REMOTE = {
90
117
  typeSymbol: '@khorsheed/dsh-file-preview/types#FilePreviewList',
91
118
  schema: _khorsheed_dsh_file_preview_filePreview_list_result$schema,
92
119
  },
93
- sourceLocation: {"file":"packages/file-preview/src/index.ts","line":316,"column":3},
120
+ sourceLocation: {"file":"packages/file-preview/src/index.ts","line":311,"column":9},
121
+ },
122
+ {
123
+ id: '@khorsheed/dsh-file-preview#filePreview/openExternal',
124
+ service: 'filePreview',
125
+ namespace: 'filePreview',
126
+ method: 'openExternal',
127
+ invocation: { kind: 'direct' },
128
+ scope: {
129
+ context: 'agent',
130
+ wire: 'agentId',
131
+ },
132
+ parameters: [
133
+ {
134
+ name: 'agent',
135
+ wire: 'agentId',
136
+ source: 'lookup',
137
+ lookup: 'agent',
138
+ codec: {
139
+ mode: 'strict',
140
+ typeSymbol: '@deepseek-ai/dsh-session/types#SessionId',
141
+ schema: _khorsheed_dsh_file_preview_filePreview_openExternal_parameter_0$schema,
142
+ },
143
+ },
144
+ {
145
+ name: 'path',
146
+ wire: 'path',
147
+ source: 'json',
148
+ codec: {
149
+ mode: 'strict',
150
+ typeSymbol: '@khorsheed/dsh-file-preview#filePreview/openExternal:path',
151
+ schema: _khorsheed_dsh_file_preview_filePreview_openExternal_parameter_1$schema,
152
+ },
153
+ },
154
+ {
155
+ name: 'app',
156
+ wire: 'app',
157
+ source: 'json',
158
+ codec: {
159
+ mode: 'strict',
160
+ typeSymbol: '@khorsheed/dsh-file-preview#filePreview/openExternal:app',
161
+ schema: _khorsheed_dsh_file_preview_filePreview_openExternal_parameter_2$schema,
162
+ },
163
+ },
164
+ ],
165
+ cancellation: { parameter: 'signal' },
166
+ result: {
167
+ mode: 'strict',
168
+ typeSymbol: '@khorsheed/dsh-file-preview/types#FilePreviewOpenExternal',
169
+ schema: _khorsheed_dsh_file_preview_filePreview_openExternal_result$schema,
170
+ },
171
+ sourceLocation: {"file":"packages/file-preview/src/index.ts","line":528,"column":9},
94
172
  },
95
173
  {
96
174
  id: '@khorsheed/dsh-file-preview#filePreview/read',
@@ -131,7 +209,7 @@ export const TYPERT_REMOTE = {
131
209
  typeSymbol: '@khorsheed/dsh-file-preview/types#FilePreviewRead',
132
210
  schema: _khorsheed_dsh_file_preview_filePreview_read_result$schema,
133
211
  },
134
- sourceLocation: {"file":"packages/file-preview/src/index.ts","line":392,"column":9},
212
+ sourceLocation: {"file":"packages/file-preview/src/index.ts","line":401,"column":9},
135
213
  },
136
214
  {
137
215
  id: '@khorsheed/dsh-file-preview#filePreview/reveal',
@@ -172,7 +250,7 @@ export const TYPERT_REMOTE = {
172
250
  typeSymbol: '@khorsheed/dsh-file-preview/types#FilePreviewReveal',
173
251
  schema: _khorsheed_dsh_file_preview_filePreview_reveal_result$schema,
174
252
  },
175
- sourceLocation: {"file":"packages/file-preview/src/index.ts","line":469,"column":9},
253
+ sourceLocation: {"file":"packages/file-preview/src/index.ts","line":478,"column":9},
176
254
  },
177
255
  {
178
256
  id: '@khorsheed/dsh-file-preview#filePreview/turnFiles',
@@ -202,7 +280,7 @@ export const TYPERT_REMOTE = {
202
280
  typeSymbol: '@khorsheed/dsh-file-preview/types#FilePreviewTurnMap',
203
281
  schema: _khorsheed_dsh_file_preview_filePreview_turnFiles_result$schema,
204
282
  },
205
- sourceLocation: {"file":"packages/file-preview/src/index.ts","line":347,"column":3},
283
+ sourceLocation: {"file":"packages/file-preview/src/index.ts","line":348,"column":9},
206
284
  },
207
285
  ],
208
286
  }
@@ -305,7 +305,7 @@ export class BashWriteCollector {
305
305
  #replay(session) {
306
306
  this.#pending.set(session.id, new Map());
307
307
  this.#captured.set(session.id, new Map());
308
- for (const event of session.events)
308
+ for (const event of session.snapshotEvents())
309
309
  this.#onEvent(session, event);
310
310
  }
311
311
  #onEvent(session, event) {
@@ -26,9 +26,11 @@ export declare function diffsFromResultMeta(meta: unknown): readonly FilePreview
26
26
  * first-seen order and deduplicated by display path; a later occurrence
27
27
  * refreshes the entry's op and location without moving it, and each write/edit
28
28
  * tool result appends its change's diff to the entry's `diffs` in event order.
29
- * Nested Code Mode file dispatches (`tool/code-dispatch` events) count too —
30
- * they carry no turn/step of their own, so the entry borrows the enclosing
31
- * root call's location.
29
+ * Nested PTC file dispatches (`tool/ptc-dispatch` events — the host's Code
30
+ * Mode name through 0.1.2, renamed with the 0.1.5 format; the v2→v3 log
31
+ * migration renames persisted rows, so only the ptc name is matched) count
32
+ * too — they carry no turn/step of their own, so the entry borrows the
33
+ * enclosing root call's location.
32
34
  * @param events - the session's events in ascending seq order.
33
35
  * @param maxFiles - cap on returned entries; excess files are dropped in
34
36
  * first-seen order after the cap is reached.
@@ -55,11 +57,12 @@ export type TurnFilesByTurn = ReadonlyMap<number, ReadonlyMap<string, TurnFileFa
55
57
  * single source of truth. Unlike {@link foldFilePreview}, this does NOT dedupe
56
58
  * a path to its last occurrence: a file touched in two turns appears in BOTH
57
59
  * turn maps, so each turn's card lists exactly what that turn mutated.
58
- * write/edit calls register with their own turn; nested Code Mode dispatches
59
- * borrow the enclosing root call's turn (dispatch events carry none); a
60
- * `tool/result` whose presentation meta carries diffs registers its paths (the
61
- * render-intent vocabulary) with the result's turn, and per-turn line deltas
62
- * are summed from the diffs. A `write` whose result carries no diffs is a
60
+ * Reads leave no card entry (the card is the mutation vocabulary — write/edit
61
+ * only), so a pure-read call never registers; write/edit calls register with
62
+ * their own turn; nested PTC dispatches borrow the enclosing root call's
63
+ * turn (dispatch events carry none); a `tool/result` whose presentation meta
64
+ * carries diffs registers its paths (the render-intent vocabulary) with the
65
+ * result's turn, and per-turn line deltas are summed from the diffs. A `write` whose result carries no diffs is a
63
66
  * create (the write tool records no diffs when the file had no prior content):
64
67
  * its full written content — read from the call arguments, which the log keeps
65
68
  * — is the added-line count, once per file per turn.
@@ -67,7 +70,7 @@ export type TurnFilesByTurn = ReadonlyMap<number, ReadonlyMap<string, TurnFileFa
67
70
  * Count discipline: a write/edit tool/call only registers the path's location
68
71
  * and never touches counts (its counted result follows); the first count
69
72
  * contribution for a turn+path is adopted verbatim, later ones accumulate per
70
- * field with unknown-wins — an uncounted mutation (a Code Mode dispatch, or a
73
+ * field with unknown-wins — an uncounted mutation (a PTC dispatch, or a
71
74
  * diff whose side reports no prior content) poisons that field to undefined
72
75
  * rather than reporting a misleading partial.
73
76
  * @param events - the session's events in ascending seq order.
package/lib/types/fold.js CHANGED
@@ -57,9 +57,11 @@ export function diffsFromResultMeta(meta) {
57
57
  * first-seen order and deduplicated by display path; a later occurrence
58
58
  * refreshes the entry's op and location without moving it, and each write/edit
59
59
  * tool result appends its change's diff to the entry's `diffs` in event order.
60
- * Nested Code Mode file dispatches (`tool/code-dispatch` events) count too —
61
- * they carry no turn/step of their own, so the entry borrows the enclosing
62
- * root call's location.
60
+ * Nested PTC file dispatches (`tool/ptc-dispatch` events — the host's Code
61
+ * Mode name through 0.1.2, renamed with the 0.1.5 format; the v2→v3 log
62
+ * migration renames persisted rows, so only the ptc name is matched) count
63
+ * too — they carry no turn/step of their own, so the entry borrows the
64
+ * enclosing root call's location.
63
65
  * @param events - the session's events in ascending seq order.
64
66
  * @param maxFiles - cap on returned entries; excess files are dropped in
65
67
  * first-seen order after the cap is reached.
@@ -67,7 +69,7 @@ export function diffsFromResultMeta(meta) {
67
69
  */
68
70
  export function foldFilePreview(events, maxFiles) {
69
71
  const entries = new Map();
70
- /** Root tool/call locations, so nested code dispatches borrow their turn/step. */
72
+ /** Root tool/call locations, so nested dispatches borrow their turn/step. */
71
73
  const callSites = new Map();
72
74
  let asOfSeq = -1;
73
75
  /** Upsert one touched path, refreshing a repeat in place and keeping its diffs. */
@@ -88,7 +90,7 @@ export function foldFilePreview(events, maxFiles) {
88
90
  record(target, event.seq, event.data.turn, event.data.step);
89
91
  continue;
90
92
  }
91
- if (event.type === 'tool/code-dispatch') {
93
+ if (event.type === 'tool/ptc-dispatch') {
92
94
  // The dispatch event IS the settled outcome: a failed sub-call changed
93
95
  // nothing, so only successful file touches record.
94
96
  if (event.data.isError)
@@ -172,11 +174,12 @@ function resultCallFacts(message) {
172
174
  * single source of truth. Unlike {@link foldFilePreview}, this does NOT dedupe
173
175
  * a path to its last occurrence: a file touched in two turns appears in BOTH
174
176
  * turn maps, so each turn's card lists exactly what that turn mutated.
175
- * write/edit calls register with their own turn; nested Code Mode dispatches
176
- * borrow the enclosing root call's turn (dispatch events carry none); a
177
- * `tool/result` whose presentation meta carries diffs registers its paths (the
178
- * render-intent vocabulary) with the result's turn, and per-turn line deltas
179
- * are summed from the diffs. A `write` whose result carries no diffs is a
177
+ * Reads leave no card entry (the card is the mutation vocabulary — write/edit
178
+ * only), so a pure-read call never registers; write/edit calls register with
179
+ * their own turn; nested PTC dispatches borrow the enclosing root call's
180
+ * turn (dispatch events carry none); a `tool/result` whose presentation meta
181
+ * carries diffs registers its paths (the render-intent vocabulary) with the
182
+ * result's turn, and per-turn line deltas are summed from the diffs. A `write` whose result carries no diffs is a
180
183
  * create (the write tool records no diffs when the file had no prior content):
181
184
  * its full written content — read from the call arguments, which the log keeps
182
185
  * — is the added-line count, once per file per turn.
@@ -184,7 +187,7 @@ function resultCallFacts(message) {
184
187
  * Count discipline: a write/edit tool/call only registers the path's location
185
188
  * and never touches counts (its counted result follows); the first count
186
189
  * contribution for a turn+path is adopted verbatim, later ones accumulate per
187
- * field with unknown-wins — an uncounted mutation (a Code Mode dispatch, or a
190
+ * field with unknown-wins — an uncounted mutation (a PTC dispatch, or a
188
191
  * diff whose side reports no prior content) poisons that field to undefined
189
192
  * rather than reporting a misleading partial.
190
193
  * @param events - the session's events in ascending seq order.
@@ -192,7 +195,7 @@ function resultCallFacts(message) {
192
195
  */
193
196
  export function foldFilePreviewByTurn(events) {
194
197
  const byTurn = new Map();
195
- /** Root tool/call locations, so nested code dispatches borrow their turn/step. */
198
+ /** Root tool/call locations, so nested dispatches borrow their turn/step. */
196
199
  const callSites = new Map();
197
200
  /** Write-tool calls keyed by callId (create fallback; see {@link WriteCallFacts}). */
198
201
  const writeCalls = new Map();
@@ -222,7 +225,7 @@ export function foldFilePreviewByTurn(events) {
222
225
  * a turn+path is adopted verbatim (a count-less placeholder from a
223
226
  * preceding tool/call must not poison it); later contributions accumulate
224
227
  * per field with unknown-wins. `unknown` marks an uncountable mutation (a
225
- * Code Mode dispatch): it poisons both fields. */
228
+ * PTC dispatch): it poisons both fields. */
226
229
  const recordContribution = (path, turn, seq, step, added, removed, unknown) => {
227
230
  const map = turnMap(turn);
228
231
  const key = countKey(turn, path);
@@ -257,6 +260,11 @@ export function foldFilePreviewByTurn(events) {
257
260
  const target = pathFromToolCall(event.data.name, event.data.arguments);
258
261
  if (target === undefined)
259
262
  continue;
263
+ // The card's vocabulary is mutations only: a read call registers
264
+ // nothing (it may still anchor a nested dispatch's location via
265
+ // callSites above).
266
+ if (target.op === 'read')
267
+ continue;
260
268
  if (target.op === 'write') {
261
269
  const content = contentFromWriteCall(event.data.arguments);
262
270
  if (content !== undefined) {
@@ -268,9 +276,9 @@ export function foldFilePreviewByTurn(events) {
268
276
  recordLocation(target.path, event.data.turn, event.seq, event.data.step);
269
277
  continue;
270
278
  }
271
- if (event.type === 'tool/code-dispatch') {
279
+ if (event.type === 'tool/ptc-dispatch') {
272
280
  // The dispatch event IS the settled outcome: a failed sub-call changed
273
- // nothing, so only successful file touches record. Code Mode writes are
281
+ // nothing, so only successful file touches record. PTC writes are
274
282
  // uncountable (no result diffs reach the session), so they register the
275
283
  // path and poison the line-count totals (unknown wins).
276
284
  if (event.data.isError)
@@ -278,6 +286,9 @@ export function foldFilePreviewByTurn(events) {
278
286
  const target = targetFromArguments(event.data.name, event.data.arguments);
279
287
  if (target === undefined)
280
288
  continue;
289
+ // Reads leave no card entry here too — only mutations register.
290
+ if (target.op === 'read')
291
+ continue;
281
292
  const site = callSites.get(String(event.data.rootCallId)) ?? { turn: 0, step: 0 };
282
293
  sessionSeen.add(target.path);
283
294
  recordContribution(target.path, site.turn, event.seq, site.step, undefined, undefined, true);
@@ -5,7 +5,7 @@ import type { Context } from '@deepseek-ai/cordis';
5
5
  import type { Agent } from '@deepseek-ai/dsh-agent';
6
6
  import { TypertRemoteService } from '@deepseek-ai/dsh-typert-protocol';
7
7
  import z from '@deepseek-ai/schemastery';
8
- import type { FilePreviewConfig, FilePreviewList, FilePreviewRead, FilePreviewReveal, FilePreviewTurnMap } from './types.ts';
8
+ import type { FilePreviewConfig, FilePreviewList, FilePreviewOpenExternal, FilePreviewRead, FilePreviewReveal, FilePreviewTurnMap } from './types.ts';
9
9
  declare module '@deepseek-ai/cordis' {
10
10
  interface Context {
11
11
  filePreview: FilePreviewService;
@@ -13,8 +13,9 @@ declare module '@deepseek-ai/cordis' {
13
13
  }
14
14
  /**
15
15
  * The `filePreview` Remote service: session-scoped read-only file inspection
16
- * for web surfaces. `list` is a pure fold over the session log (no filesystem
17
- * access); `read` resolves the path against the session cwd and serves current
16
+ * for web surfaces. `list` is a fold over the session log, then filtered to the
17
+ * paths that still exist on disk (resolved against the session cwd and stat-ed
18
+ * per call); `read` resolves the path against the session cwd and serves current
18
19
  * text content through `ctx.fs` (or a browser URL for images), capped by
19
20
  * config. Image bytes ride a dedicated host route so the browser loads them
20
21
  * natively without bloating the RPC channel.
@@ -32,6 +33,8 @@ export declare class FilePreviewService extends TypertRemoteService {
32
33
  private readonly agents;
33
34
  /** Native reveal runner; a constructor seam for deterministic tests. */
34
35
  private readonly revealNative;
36
+ /** Native open-in-app runner; a constructor seam for deterministic tests. */
37
+ private readonly openExternalNative;
35
38
  /** Bash-write collector (S2 seam), or undefined when disabled in config. */
36
39
  private readonly collector;
37
40
  /** Per-session by-turn fold cache, invalidated by the log watermark. */
@@ -45,7 +48,12 @@ export declare class FilePreviewService extends TypertRemoteService {
45
48
  */
46
49
  constructor(ctx: Context, config?: FilePreviewConfig, deps?: {
47
50
  revealNative?: (path: string, signal: AbortSignal) => Promise<void>;
51
+ openExternalNative?: (path: string, app: string, signal: AbortSignal) => Promise<void>;
48
52
  });
53
+ /** Zero-session availability handshake for browser companions. */
54
+ capabilities(): {
55
+ protocolVersion: 1;
56
+ };
49
57
  private get fs();
50
58
  /**
51
59
  * Serve one image file's bytes for a browser `<img>` request. The URL is
@@ -55,27 +63,44 @@ export declare class FilePreviewService extends TypertRemoteService {
55
63
  * @param res - the response to fill with bytes or an error status.
56
64
  */
57
65
  private serveImage;
66
+ /** Resolve the session's recorded display paths against its cwd and keep only
67
+ * those that currently exist as a regular file. The products surfaces fold
68
+ * the session log (which is history, not disk state): a path the log wrote
69
+ * may have been cleaned up since (a temp script the turn deleted), and such
70
+ * a path is not a product to list. Existence is checked fresh on every call
71
+ * (never cached), so a deletion that lands after a fold is visible on the
72
+ * next fetch. Unresolvable/unstat-able paths are treated as absent.
73
+ * @param agent - owning live agent; its session cwd anchors relative paths.
74
+ * @param paths - the display paths to probe.
75
+ * @returns the subset that resolves to an existing regular file.
76
+ */
77
+ private retainExisting;
58
78
  /**
59
79
  * List the files one session wrote or edited: the log fold plus any
60
80
  * bash-written files the collector verified (the S2 seam), merged so a
61
- * captured path the fold already knows keeps its log-derived entry.
81
+ * captured path the fold already knows keeps its log-derived entry. Only
82
+ * paths that currently exist on disk are returned — a file the session
83
+ * wrote and later deleted is history, not a product.
62
84
  * @param agent - owning live agent; its session log is the data source.
63
- * @returns first-seen files capped by `maxFiles`, with the log watermark.
85
+ * @returns existing first-seen files capped by `maxFiles`, with the log watermark.
64
86
  */
65
- list(agent: Agent): FilePreviewList;
87
+ list(agent: Agent): Promise<FilePreviewList>;
66
88
  /**
67
89
  * Every turn's file mutations for the turn-tail card — the single source of
68
90
  * truth the card renders (the client's old write/edit-only fold retired).
69
- * Built by folding the session log per turn (write/edit calls, Code Mode
91
+ * Built by folding the session log per turn (write/edit calls, PTC
70
92
  * dispatches borrowing the root call's turn, and render-intent paths from
71
93
  * result diff meta) and merging the collector's bash-written captures by
72
94
  * their own turn. The fold is cached per session and invalidated by the log
73
95
  * watermark, so repeated card fetches do not refold. A path touched in two
74
- * turns appears in BOTH turn groups — per-turn attribution is exact.
96
+ * turns appears in BOTH turn groups — per-turn attribution is exact. Only
97
+ * paths that currently exist on disk are returned (a deleted temp script is
98
+ * history, not a product); existence is probed fresh on every call, so the
99
+ * cached fold is filtered per request rather than cached.
75
100
  * @param agent - owning live agent; its session log is the data source.
76
- * @returns per-turn file groups plus the scanned watermark.
101
+ * @returns existing per-turn file groups plus the scanned watermark.
77
102
  */
78
- turnFiles(agent: Agent): FilePreviewTurnMap;
103
+ turnFiles(agent: Agent): Promise<FilePreviewTurnMap>;
79
104
  /**
80
105
  * Read the current content of one recorded file, resolved against the
81
106
  * session cwd and capped by `maxReadBytes`.
@@ -100,6 +125,22 @@ export declare class FilePreviewService extends TypertRemoteService {
100
125
  * @returns whether the file manager selected the file, or why not.
101
126
  */
102
127
  reveal(agent: Agent, path: string, signal: AbortSignal): Promise<FilePreviewReveal>;
128
+ /**
129
+ * Open one recorded file in a specific host application (the "open in IDE"
130
+ * gesture). The official open-in-app route only accepts directories — a
131
+ * file path 404s — so file-exact opens go through this method: macOS
132
+ * `open -a <App> <path>` via the same native-command runner reveal uses.
133
+ * The browser names the application by official open-in-app catalog id
134
+ * (probed from `/open-in-app/apps`); the id → app-name map lives in
135
+ * open-external.ts. Non-macOS hosts and unknown ids answer without
136
+ * launching, and the client hides the gesture.
137
+ * @param agent - owning live agent; its session cwd anchors relative paths.
138
+ * @param path - the display path recorded by the read/write/edit tool call.
139
+ * @param app - official open-in-app catalog id (e.g. `cursor`).
140
+ * @param signal - cooperative cancellation from the calling UI request.
141
+ * @returns whether the application launched, or why not.
142
+ */
143
+ openExternal(agent: Agent, path: string, app: string, signal: AbortSignal): Promise<FilePreviewOpenExternal>;
103
144
  }
104
145
  export default FilePreviewService;
105
146
  //# sourceMappingURL=index.d.ts.map