@hyperdrive.bot/fleet-server 0.3.99 → 0.3.101

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 (73) hide show
  1. package/dist/server/server/ingestion/composio/gateway.js +6 -1
  2. package/dist/server/server/ingestion/pipedream/gateway.js +7 -0
  3. package/dist/server/server/ingestion/service.d.ts +31 -0
  4. package/dist/server/server/ingestion/service.js +81 -4
  5. package/dist/server/server/ingestion/types.d.ts +9 -0
  6. package/dist/server/server/session/ingestion/source-session.d.ts +10 -0
  7. package/dist/server/server/session/ingestion/source-session.js +25 -0
  8. package/dist/server/server/session.js +11 -3
  9. package/dist/server/web-ui/_expo/static/js/web/{desktop-attachment-bridge-67f19cbfce758da6aa23c38c2dbd6a33.js → desktop-attachment-bridge-6beae08a69e097c7f552119696c67413.js} +5 -5
  10. package/dist/server/web-ui/_expo/static/js/web/desktop-attachment-bridge-6beae08a69e097c7f552119696c67413.js.br +0 -0
  11. package/dist/server/web-ui/_expo/static/js/web/desktop-attachment-bridge-6beae08a69e097c7f552119696c67413.js.gz +0 -0
  12. package/dist/server/web-ui/_expo/static/js/web/desktop-attachment-bridge-6beae08a69e097c7f552119696c67413.js.map.br +0 -0
  13. package/dist/server/web-ui/_expo/static/js/web/desktop-attachment-bridge-6beae08a69e097c7f552119696c67413.js.map.gz +0 -0
  14. package/dist/server/web-ui/_expo/static/js/web/{desktop-attachment-store-6888615a6b700f975c1f78501ad8577c.js → desktop-attachment-store-7a589090b52127457319ba733fcca36f.js} +3 -3
  15. package/dist/server/web-ui/_expo/static/js/web/desktop-attachment-store-7a589090b52127457319ba733fcca36f.js.br +0 -0
  16. package/dist/server/web-ui/_expo/static/js/web/desktop-attachment-store-7a589090b52127457319ba733fcca36f.js.gz +0 -0
  17. package/dist/server/web-ui/_expo/static/js/web/desktop-attachment-store-7a589090b52127457319ba733fcca36f.js.map.br +0 -0
  18. package/dist/server/web-ui/_expo/static/js/web/desktop-attachment-store-7a589090b52127457319ba733fcca36f.js.map.gz +0 -0
  19. package/dist/server/web-ui/_expo/static/js/web/{index-dc1e81e7cbad84d30a01c48dcc9a5a3e.js → index-cd94e627d4feefdc781faccc3da11ade.js} +30 -29
  20. package/dist/server/web-ui/_expo/static/js/web/index-cd94e627d4feefdc781faccc3da11ade.js.br +0 -0
  21. package/dist/server/web-ui/_expo/static/js/web/index-cd94e627d4feefdc781faccc3da11ade.js.gz +0 -0
  22. package/dist/server/web-ui/_expo/static/js/web/index-cd94e627d4feefdc781faccc3da11ade.js.map.br +0 -0
  23. package/dist/server/web-ui/_expo/static/js/web/{index-dc1e81e7cbad84d30a01c48dcc9a5a3e.js.map.gz → index-cd94e627d4feefdc781faccc3da11ade.js.map.gz} +0 -0
  24. package/dist/server/web-ui/_expo/static/js/web/{indexeddb-attachment-store-991ae7fd00f9fed45084fbb39160e8b8.js → indexeddb-attachment-store-425dc000c40ab14c7de479c8a86e55b3.js} +3 -3
  25. package/dist/server/web-ui/_expo/static/js/web/indexeddb-attachment-store-425dc000c40ab14c7de479c8a86e55b3.js.br +0 -0
  26. package/dist/server/web-ui/_expo/static/js/web/indexeddb-attachment-store-425dc000c40ab14c7de479c8a86e55b3.js.gz +0 -0
  27. package/dist/server/web-ui/_expo/static/js/web/indexeddb-attachment-store-425dc000c40ab14c7de479c8a86e55b3.js.map.br +0 -0
  28. package/dist/server/web-ui/_expo/static/js/web/indexeddb-attachment-store-425dc000c40ab14c7de479c8a86e55b3.js.map.gz +0 -0
  29. package/dist/server/web-ui/_expo/static/js/web/{native-file-attachment-store-fdb4d787a259ce350f76280ca0e2bfa2.js → native-file-attachment-store-5a21541a0e9eb4097726331dae9f2952.js} +5 -5
  30. package/dist/server/web-ui/_expo/static/js/web/native-file-attachment-store-5a21541a0e9eb4097726331dae9f2952.js.br +0 -0
  31. package/dist/server/web-ui/_expo/static/js/web/native-file-attachment-store-5a21541a0e9eb4097726331dae9f2952.js.gz +0 -0
  32. package/dist/server/web-ui/_expo/static/js/web/native-file-attachment-store-5a21541a0e9eb4097726331dae9f2952.js.map.br +0 -0
  33. package/dist/server/web-ui/_expo/static/js/web/native-file-attachment-store-5a21541a0e9eb4097726331dae9f2952.js.map.gz +0 -0
  34. package/dist/server/web-ui/_expo/static/js/web/{profiler-9502a8e721925a6353ec45f7613f537e.js → profiler-d61e032c3f43b3aa19e02fb97c3f7331.js} +11 -11
  35. package/dist/server/web-ui/_expo/static/js/web/profiler-d61e032c3f43b3aa19e02fb97c3f7331.js.br +0 -0
  36. package/dist/server/web-ui/_expo/static/js/web/profiler-d61e032c3f43b3aa19e02fb97c3f7331.js.gz +0 -0
  37. package/dist/server/web-ui/_expo/static/js/web/profiler-d61e032c3f43b3aa19e02fb97c3f7331.js.map.br +0 -0
  38. package/dist/server/web-ui/_expo/static/js/web/profiler-d61e032c3f43b3aa19e02fb97c3f7331.js.map.gz +0 -0
  39. package/dist/server/web-ui/_expo/static/js/web/{startRecording-4ed5094aa059a0fc724f5ae70dd2f693.js → startRecording-1bb242d6754dee4266ba9a09a252ccea.js} +60 -60
  40. package/dist/server/web-ui/_expo/static/js/web/startRecording-1bb242d6754dee4266ba9a09a252ccea.js.br +0 -0
  41. package/dist/server/web-ui/_expo/static/js/web/startRecording-1bb242d6754dee4266ba9a09a252ccea.js.gz +0 -0
  42. package/dist/server/web-ui/_expo/static/js/web/startRecording-1bb242d6754dee4266ba9a09a252ccea.js.map.br +0 -0
  43. package/dist/server/web-ui/_expo/static/js/web/{startRecording-4ed5094aa059a0fc724f5ae70dd2f693.js.map.gz → startRecording-1bb242d6754dee4266ba9a09a252ccea.js.map.gz} +0 -0
  44. package/dist/server/web-ui/index.html +1 -1
  45. package/dist/server/web-ui/index.html.br +0 -0
  46. package/dist/server/web-ui/index.html.gz +0 -0
  47. package/package.json +6 -6
  48. package/dist/server/web-ui/_expo/static/js/web/desktop-attachment-bridge-67f19cbfce758da6aa23c38c2dbd6a33.js.br +0 -0
  49. package/dist/server/web-ui/_expo/static/js/web/desktop-attachment-bridge-67f19cbfce758da6aa23c38c2dbd6a33.js.gz +0 -0
  50. package/dist/server/web-ui/_expo/static/js/web/desktop-attachment-bridge-67f19cbfce758da6aa23c38c2dbd6a33.js.map.br +0 -0
  51. package/dist/server/web-ui/_expo/static/js/web/desktop-attachment-bridge-67f19cbfce758da6aa23c38c2dbd6a33.js.map.gz +0 -0
  52. package/dist/server/web-ui/_expo/static/js/web/desktop-attachment-store-6888615a6b700f975c1f78501ad8577c.js.br +0 -0
  53. package/dist/server/web-ui/_expo/static/js/web/desktop-attachment-store-6888615a6b700f975c1f78501ad8577c.js.gz +0 -0
  54. package/dist/server/web-ui/_expo/static/js/web/desktop-attachment-store-6888615a6b700f975c1f78501ad8577c.js.map.br +0 -0
  55. package/dist/server/web-ui/_expo/static/js/web/desktop-attachment-store-6888615a6b700f975c1f78501ad8577c.js.map.gz +0 -0
  56. package/dist/server/web-ui/_expo/static/js/web/index-dc1e81e7cbad84d30a01c48dcc9a5a3e.js.br +0 -0
  57. package/dist/server/web-ui/_expo/static/js/web/index-dc1e81e7cbad84d30a01c48dcc9a5a3e.js.gz +0 -0
  58. package/dist/server/web-ui/_expo/static/js/web/index-dc1e81e7cbad84d30a01c48dcc9a5a3e.js.map.br +0 -0
  59. package/dist/server/web-ui/_expo/static/js/web/indexeddb-attachment-store-991ae7fd00f9fed45084fbb39160e8b8.js.br +0 -0
  60. package/dist/server/web-ui/_expo/static/js/web/indexeddb-attachment-store-991ae7fd00f9fed45084fbb39160e8b8.js.gz +0 -0
  61. package/dist/server/web-ui/_expo/static/js/web/indexeddb-attachment-store-991ae7fd00f9fed45084fbb39160e8b8.js.map.br +0 -0
  62. package/dist/server/web-ui/_expo/static/js/web/indexeddb-attachment-store-991ae7fd00f9fed45084fbb39160e8b8.js.map.gz +0 -0
  63. package/dist/server/web-ui/_expo/static/js/web/native-file-attachment-store-fdb4d787a259ce350f76280ca0e2bfa2.js.br +0 -0
  64. package/dist/server/web-ui/_expo/static/js/web/native-file-attachment-store-fdb4d787a259ce350f76280ca0e2bfa2.js.gz +0 -0
  65. package/dist/server/web-ui/_expo/static/js/web/native-file-attachment-store-fdb4d787a259ce350f76280ca0e2bfa2.js.map.br +0 -0
  66. package/dist/server/web-ui/_expo/static/js/web/native-file-attachment-store-fdb4d787a259ce350f76280ca0e2bfa2.js.map.gz +0 -0
  67. package/dist/server/web-ui/_expo/static/js/web/profiler-9502a8e721925a6353ec45f7613f537e.js.br +0 -0
  68. package/dist/server/web-ui/_expo/static/js/web/profiler-9502a8e721925a6353ec45f7613f537e.js.gz +0 -0
  69. package/dist/server/web-ui/_expo/static/js/web/profiler-9502a8e721925a6353ec45f7613f537e.js.map.br +0 -0
  70. package/dist/server/web-ui/_expo/static/js/web/profiler-9502a8e721925a6353ec45f7613f537e.js.map.gz +0 -0
  71. package/dist/server/web-ui/_expo/static/js/web/startRecording-4ed5094aa059a0fc724f5ae70dd2f693.js.br +0 -0
  72. package/dist/server/web-ui/_expo/static/js/web/startRecording-4ed5094aa059a0fc724f5ae70dd2f693.js.gz +0 -0
  73. package/dist/server/web-ui/_expo/static/js/web/startRecording-4ed5094aa059a0fc724f5ae70dd2f693.js.map.br +0 -0
@@ -375,7 +375,12 @@ export function createComposioGateway(config) {
375
375
  if (!item.id) {
376
376
  continue;
377
377
  }
378
- accounts.push({ id: item.id, status: normalizeStatus(item.status) });
378
+ // Composio's connected-account payload carries no email or display
379
+ // name for the authorized account - `user_id` is the caller-supplied
380
+ // external id, which is the daemon's own tenant string here and so
381
+ // identifies nothing about the user. Null rather than a value that
382
+ // would look like an identity and not be one.
383
+ accounts.push({ id: item.id, status: normalizeStatus(item.status), label: null });
379
384
  }
380
385
  return accounts;
381
386
  },
@@ -181,6 +181,13 @@ export function createPipedreamGateway(config) {
181
181
  accounts.push({
182
182
  id: account.id,
183
183
  status: account.healthy === false ? "inactive" : "active",
184
+ // Pipedream's `name` is the account's custom name, which for an OAuth
185
+ // app is normally the address the user authorized with. It is
186
+ // optional in the SDK type, so it is coalesced rather than assumed -
187
+ // an absent label renders as "Not linked to an account", never as the
188
+ // opaque `apn_...` id, which would be an identifier pretending to be
189
+ // an identity.
190
+ label: account.name ?? null,
184
191
  });
185
192
  }
186
193
  return accounts;
@@ -137,6 +137,37 @@ export declare class IngestionService {
137
137
  * uniformly cheerful `true`.
138
138
  */
139
139
  deleteFilter(filterId: string): Promise<boolean>;
140
+ /**
141
+ * The catalogue's own name and icon for an app slug.
142
+ *
143
+ * Best-effort by design: a catalogue call that fails or returns no match must
144
+ * not fail a connect whose OAuth handoff already succeeded, so it degrades to
145
+ * exactly what this method replaced (the raw slug, no icon) rather than
146
+ * throwing. `imgSrc` stays `""` in that case, matching what every source
147
+ * written before this change already holds on disk.
148
+ */
149
+ private resolvePresentation;
150
+ /**
151
+ * Forget a source and every filter bound to it.
152
+ *
153
+ * LOCAL ONLY. The aggregator keeps the grant, so this is "paseo stops
154
+ * watching", not "the provider forgot you" - and the confirm copy must say
155
+ * that, because promising a revoke paseo does not perform is the same class
156
+ * of lie as the connect sheet's old "it updates on its own".
157
+ *
158
+ * Filters CASCADE rather than being orphaned. A filter whose `sourceId` no
159
+ * longer resolves is not inert: it resolves to `SOURCE_MISSING` and shows up
160
+ * as a broken row forever, so leaving them would trade one piece of
161
+ * unremovable state for another.
162
+ *
163
+ * The in-flight connect poll is cancelled FIRST. It writes health on a timer,
164
+ * so deleting the record underneath a live poll would let it recreate state
165
+ * for a source the user just removed.
166
+ */
167
+ disconnect(sourceId: string): Promise<{
168
+ removed: boolean;
169
+ removedFilterIds: string[];
170
+ }>;
140
171
  /**
141
172
  * Field by field on purpose. A `...stored` spread would mean a field added to
142
173
  * StoredSource later reaches the wire the day it is added, with no diff on
@@ -104,13 +104,25 @@ export class IngestionService {
104
104
  const gateway = this.resolveGateway(kind);
105
105
  const handoff = await gateway.connect(this.externalUserId, appSlug);
106
106
  const timestamp = this.now().toISOString();
107
+ // The catalogue already knows this app as "Google Calendar" with a real
108
+ // icon, and the client rendered exactly that one tap earlier. Writing the
109
+ // raw slug threw both away at the moment of persisting, so every row read
110
+ // "google_calendar" with no icon forever after.
111
+ //
112
+ // Resolved daemon-side rather than accepted from the client: a client that
113
+ // could supply displayName and imgSrc could write the strings the row
114
+ // renders, and store.test.ts already guards against exactly that shape.
115
+ // Best-effort - a catalogue hiccup must not fail a connect that otherwise
116
+ // succeeded, so it falls back to the previous behaviour.
117
+ const presentation = await this.resolvePresentation(gateway, appSlug);
107
118
  const source = await this.store.create({
108
119
  kind,
109
120
  appSlug,
110
- displayName: appSlug,
111
- imgSrc: "",
121
+ displayName: presentation.displayName,
122
+ imgSrc: presentation.imgSrc,
112
123
  externalUserId: this.externalUserId,
113
124
  externalAccountId: null,
125
+ accountLabel: null,
114
126
  status: "connecting",
115
127
  createdAt: timestamp,
116
128
  updatedAt: timestamp,
@@ -205,7 +217,7 @@ export class IngestionService {
205
217
  }
206
218
  const active = accounts.find((account) => account.status === "active");
207
219
  if (active) {
208
- await this.persistHealth(source.id, { status: "active", lastError: null }, active.id);
220
+ await this.persistHealth(source.id, { status: "active", lastError: null }, active.id, active.label);
209
221
  return;
210
222
  }
211
223
  await this.sleep(CONNECT_POLL_INTERVAL_MS, state);
@@ -254,7 +266,7 @@ export class IngestionService {
254
266
  * Re-reads the record first so a source deleted while a poll or a sweep was
255
267
  * in flight is not resurrected by a stale write.
256
268
  */
257
- async persistHealth(sourceId, health, externalAccountId) {
269
+ async persistHealth(sourceId, health, externalAccountId, accountLabel) {
258
270
  const current = await this.store.get(sourceId);
259
271
  if (!current) {
260
272
  return null;
@@ -267,6 +279,7 @@ export class IngestionService {
267
279
  lastCheckedAt: timestamp,
268
280
  updatedAt: timestamp,
269
281
  ...(externalAccountId !== undefined ? { externalAccountId } : {}),
282
+ ...(accountLabel !== undefined ? { accountLabel } : {}),
270
283
  };
271
284
  await this.store.put(next);
272
285
  return next;
@@ -340,6 +353,69 @@ export class IngestionService {
340
353
  await this.filterStore.delete(filterId);
341
354
  return true;
342
355
  }
356
+ /**
357
+ * The catalogue's own name and icon for an app slug.
358
+ *
359
+ * Best-effort by design: a catalogue call that fails or returns no match must
360
+ * not fail a connect whose OAuth handoff already succeeded, so it degrades to
361
+ * exactly what this method replaced (the raw slug, no icon) rather than
362
+ * throwing. `imgSrc` stays `""` in that case, matching what every source
363
+ * written before this change already holds on disk.
364
+ */
365
+ async resolvePresentation(gateway, appSlug) {
366
+ try {
367
+ const page = await gateway.listSources(appSlug);
368
+ const match = page.items.find((entry) => entry.slug === appSlug);
369
+ if (match) {
370
+ return { displayName: match.name, imgSrc: match.imgSrc };
371
+ }
372
+ }
373
+ catch (error) {
374
+ // Logged, never swallowed silently: if this degrades in production the
375
+ // symptom is a row that says "google_calendar", and a bare catch would
376
+ // make that indistinguishable from an aggregator that simply has no
377
+ // catalogue entry.
378
+ this.logger.warn({ err: error, appSlug }, "Catalogue lookup failed; falling back to slug");
379
+ }
380
+ return { displayName: appSlug, imgSrc: "" };
381
+ }
382
+ /**
383
+ * Forget a source and every filter bound to it.
384
+ *
385
+ * LOCAL ONLY. The aggregator keeps the grant, so this is "paseo stops
386
+ * watching", not "the provider forgot you" - and the confirm copy must say
387
+ * that, because promising a revoke paseo does not perform is the same class
388
+ * of lie as the connect sheet's old "it updates on its own".
389
+ *
390
+ * Filters CASCADE rather than being orphaned. A filter whose `sourceId` no
391
+ * longer resolves is not inert: it resolves to `SOURCE_MISSING` and shows up
392
+ * as a broken row forever, so leaving them would trade one piece of
393
+ * unremovable state for another.
394
+ *
395
+ * The in-flight connect poll is cancelled FIRST. It writes health on a timer,
396
+ * so deleting the record underneath a live poll would let it recreate state
397
+ * for a source the user just removed.
398
+ */
399
+ async disconnect(sourceId) {
400
+ const existing = await this.store.get(sourceId);
401
+ if (existing === null) {
402
+ return { removed: false, removedFilterIds: [] };
403
+ }
404
+ // Cancel BEFORE deleting. The poll writes health on a 2s timer, so
405
+ // removing the record underneath a live poll lets it persist state for a
406
+ // source the user just removed. `cancel()` also wakes the sleep, so the
407
+ // loop exits at its next check rather than after the full interval; the
408
+ // poll's own `finally` removes the map entry.
409
+ this.connectPolls.get(sourceId)?.cancel();
410
+ const filters = await this.filterStore.list();
411
+ const bound = filters.filter((filter) => filter.sourceId === sourceId);
412
+ for (const filter of bound) {
413
+ await this.filterStore.delete(filter.id);
414
+ }
415
+ await this.store.delete(sourceId);
416
+ this.logger.info({ sourceId, removedFilters: bound.length }, "Source disconnected and its filters removed");
417
+ return { removed: true, removedFilterIds: bound.map((filter) => filter.id) };
418
+ }
343
419
  /**
344
420
  * Field by field on purpose. A `...stored` spread would mean a field added to
345
421
  * StoredSource later reaches the wire the day it is added, with no diff on
@@ -353,6 +429,7 @@ export class IngestionService {
353
429
  displayName: source.displayName,
354
430
  imgSrc: source.imgSrc,
355
431
  externalAccountId: source.externalAccountId,
432
+ accountLabel: source.accountLabel,
356
433
  status: source.status,
357
434
  createdAt: source.createdAt,
358
435
  updatedAt: source.updatedAt,
@@ -55,6 +55,15 @@ export interface SourceConnectHandoff {
55
55
  export interface SourceAccount {
56
56
  id: string;
57
57
  status: "active" | "pending" | "inactive";
58
+ /**
59
+ * The human name of the account, when the aggregator gives one - typically
60
+ * the email for an OAuth app. Null when it does not.
61
+ *
62
+ * Both gateways already receive this on a call they already make and drop it
63
+ * on the floor, which is why a connected row could only ever say "gmail" and
64
+ * never WHICH gmail.
65
+ */
66
+ label: string | null;
58
67
  }
59
68
  export interface PipedreamConfig {
60
69
  clientId?: string | undefined;
@@ -74,5 +74,15 @@ export declare class SourceSession {
74
74
  handleIngestionFilterDeleteRequest(request: Extract<SessionInboundMessage, {
75
75
  type: "ingestion/filter/delete";
76
76
  }>): Promise<void>;
77
+ /**
78
+ * Forget a source and the filters bound to it.
79
+ *
80
+ * `removed: false` with `error: null` says the id resolved to nothing, which
81
+ * is an answer: disconnecting twice is idempotent, and reporting the second
82
+ * call as a failure would make a double-tap look like a broken daemon.
83
+ */
84
+ handleSourceDisconnectRequest(request: Extract<SessionInboundMessage, {
85
+ type: "source/disconnect";
86
+ }>): Promise<void>;
77
87
  }
78
88
  //# sourceMappingURL=source-session.d.ts.map
@@ -187,5 +187,30 @@ export class SourceSession {
187
187
  this.emitSourceRpcError(request, error);
188
188
  }
189
189
  }
190
+ /**
191
+ * Forget a source and the filters bound to it.
192
+ *
193
+ * `removed: false` with `error: null` says the id resolved to nothing, which
194
+ * is an answer: disconnecting twice is idempotent, and reporting the second
195
+ * call as a failure would make a double-tap look like a broken daemon.
196
+ */
197
+ async handleSourceDisconnectRequest(request) {
198
+ try {
199
+ const result = await this.ingestionService.disconnect(request.sourceId);
200
+ this.host.emit({
201
+ type: "source/disconnect/response",
202
+ payload: {
203
+ requestId: request.requestId,
204
+ sourceId: request.sourceId,
205
+ removed: result.removed,
206
+ removedFilterIds: result.removedFilterIds,
207
+ error: null,
208
+ },
209
+ });
210
+ }
211
+ catch (error) {
212
+ this.emitSourceRpcError(request, error);
213
+ }
214
+ }
190
215
  }
191
216
  //# sourceMappingURL=source-session.js.map
@@ -1747,6 +1747,8 @@ export class Session {
1747
1747
  return this.sourceSession.handleSourceListRequest(msg);
1748
1748
  case "source/check":
1749
1749
  return this.sourceSession.handleSourceCheckRequest(msg);
1750
+ case "source/disconnect":
1751
+ return this.sourceSession.handleSourceDisconnectRequest(msg);
1750
1752
  // Epic 7 filter authoring. Routed to SourceSession rather than
1751
1753
  // ChatIngestionSession because these need no chat context: they are
1752
1754
  // store CRUD, and SourceSession is already the source-scoped surface.
@@ -3420,9 +3422,15 @@ export class Session {
3420
3422
  if (!normalized.cwd) {
3421
3423
  throw new Error("Import requires cwd from the selected provider session");
3422
3424
  }
3423
- // An imported agent mints its own workspace; ownership is its workspaceId,
3424
- // never an existing same-cwd workspace resolved by path.
3425
- const workspace = await this.workspaceProvisioning.createWorkspaceForDirectory(normalized.cwd);
3425
+ // Look before you mint. This used to call createWorkspaceForDirectory
3426
+ // unconditionally, so importing a session whose cwd ALREADY had a workspace
3427
+ // produced a second one and the imported agent surfaced there instead of in
3428
+ // the workspace on screen. Same class as the palette (0.3.38),
3429
+ // resolveOrCreateWorkspaceIdForCreateAgent (MR !44) and
3430
+ // ensureWorkspaceForCreate (MR !80); import was the last call site still
3431
+ // minting. findOrCreateWorkspaceForDirectory keeps the never-seen-cwd case
3432
+ // minting, which is the only case where a new workspace is correct.
3433
+ const workspace = await this.workspaceProvisioning.findOrCreateWorkspaceForDirectory(normalized.cwd);
3426
3434
  const { snapshot, timelineSize } = await importProviderSession({
3427
3435
  request: normalized,
3428
3436
  workspaceId: workspace.workspaceId,
@@ -1,5 +1,5 @@
1
- __d(function(g,r,i,a,m,e,d){"use strict";Object.defineProperty(e,'__esModule',{value:!0}),e.createDesktopAttachmentBridge=function(){const l=(0,s.createDesktopPreviewUrlResolver)({reader:(0,s.createDesktopFileReader)(),objectUrls:(0,s.createBrowserObjectUrlMinter)()});return{copyFile:t.copyDesktopAttachmentFile,writeBase64:t.writeDesktopAttachmentBase64,writeBytes:t.writeDesktopAttachmentBytes,deleteFile:t.deleteDesktopAttachmentFile,garbageCollect:t.garbageCollectDesktopAttachmentFiles,readFileBase64:s.readDesktopFileBase64,resolvePreviewUrl:t=>l.resolve(t),releasePreviewUrl:t=>l.release(t)}};var t=r(d[0]),s=r(d[1])},4921,[4926,4927]);
2
- __d(function(g,r,i,a,m,e,d){"use strict";Object.defineProperty(e,'__esModule',{value:!0}),e.writeDesktopAttachmentBase64=async function(n){return await(0,t.invokeDesktopCommand)("write_attachment_base64",{attachmentId:n.attachmentId,base64:n.base64,extension:n.extension??null})},e.writeDesktopAttachmentBytes=async function(n){return await(0,t.invokeDesktopCommand)("write_attachment_bytes",{attachmentId:n.attachmentId,bytes:n.bytes,extension:n.extension??null})},e.copyDesktopAttachmentFile=async function(n){return await(0,t.invokeDesktopCommand)("copy_attachment_file",{attachmentId:n.attachmentId,sourcePath:n.sourcePath,extension:n.extension??null})},e.deleteDesktopAttachmentFile=async function(n){return await(0,t.invokeDesktopCommand)("delete_attachment_file",{path:n.path})},e.garbageCollectDesktopAttachmentFiles=async function(n){return await(0,t.invokeDesktopCommand)("garbage_collect_attachment_files",{referencedIds:[...n.referencedIds]})};var t=r(d[0])},4926,[3419]);
3
- __d(function(g,r,i,a,m,e,d){"use strict";Object.defineProperty(e,'__esModule',{value:!0}),e.readDesktopFileBase64=s,e.createDesktopFileReader=function(){return{readFileBase64:s}},e.createBrowserObjectUrlMinter=function(){return{tryCreate({mimeType:t,base64:n}){if("undefined"==typeof URL||"function"!=typeof URL.createObjectURL)return null;const o=c(n),s=new ArrayBuffer(o.byteLength);new Uint8Array(s).set(o);const u=new Blob([s],{type:t});return URL.createObjectURL(u)},revoke(t){"undefined"!=typeof URL&&"function"==typeof URL.revokeObjectURL&&URL.revokeObjectURL(t)}}},e.createDesktopPreviewUrlResolver=function(t){const n=new Set;return{async resolve(o){const s=await t.reader.readFileBase64(o.storageKey),c=t.objectUrls.tryCreate({mimeType:o.mimeType,base64:s});return null===c?`data:${o.mimeType};base64,${s}`:(n.add(c),c)},async release({url:o}){n.has(o)&&(n.delete(o),t.objectUrls.revoke(o))}}};var t=r(d[0]),n=r(d[1]),o=r(d[2]);async function s(o){return await(0,n.invokeDesktopCommand)("read_file_base64",{path:(0,t.fileUriToPath)(o)})}function c(t){return new Uint8Array(o.Buffer.from(t,"base64"))}},4927,[4593,3419,52]);
4
- //# sourceMappingURL=/_expo/static/js/web/desktop-attachment-bridge-67f19cbfce758da6aa23c38c2dbd6a33.js.map
5
- //# debugId=c3a25a89-bf01-4243-ac6e-d215e65a50ef
1
+ __d(function(g,r,i,a,m,e,d){"use strict";Object.defineProperty(e,'__esModule',{value:!0}),e.createDesktopAttachmentBridge=function(){const l=(0,s.createDesktopPreviewUrlResolver)({reader:(0,s.createDesktopFileReader)(),objectUrls:(0,s.createBrowserObjectUrlMinter)()});return{copyFile:t.copyDesktopAttachmentFile,writeBase64:t.writeDesktopAttachmentBase64,writeBytes:t.writeDesktopAttachmentBytes,deleteFile:t.deleteDesktopAttachmentFile,garbageCollect:t.garbageCollectDesktopAttachmentFiles,readFileBase64:s.readDesktopFileBase64,resolvePreviewUrl:t=>l.resolve(t),releasePreviewUrl:t=>l.release(t)}};var t=r(d[0]),s=r(d[1])},4922,[4927,4928]);
2
+ __d(function(g,r,i,a,m,e,d){"use strict";Object.defineProperty(e,'__esModule',{value:!0}),e.writeDesktopAttachmentBase64=async function(n){return await(0,t.invokeDesktopCommand)("write_attachment_base64",{attachmentId:n.attachmentId,base64:n.base64,extension:n.extension??null})},e.writeDesktopAttachmentBytes=async function(n){return await(0,t.invokeDesktopCommand)("write_attachment_bytes",{attachmentId:n.attachmentId,bytes:n.bytes,extension:n.extension??null})},e.copyDesktopAttachmentFile=async function(n){return await(0,t.invokeDesktopCommand)("copy_attachment_file",{attachmentId:n.attachmentId,sourcePath:n.sourcePath,extension:n.extension??null})},e.deleteDesktopAttachmentFile=async function(n){return await(0,t.invokeDesktopCommand)("delete_attachment_file",{path:n.path})},e.garbageCollectDesktopAttachmentFiles=async function(n){return await(0,t.invokeDesktopCommand)("garbage_collect_attachment_files",{referencedIds:[...n.referencedIds]})};var t=r(d[0])},4927,[3419]);
3
+ __d(function(g,r,i,a,m,e,d){"use strict";Object.defineProperty(e,'__esModule',{value:!0}),e.readDesktopFileBase64=s,e.createDesktopFileReader=function(){return{readFileBase64:s}},e.createBrowserObjectUrlMinter=function(){return{tryCreate({mimeType:t,base64:n}){if("undefined"==typeof URL||"function"!=typeof URL.createObjectURL)return null;const o=c(n),s=new ArrayBuffer(o.byteLength);new Uint8Array(s).set(o);const u=new Blob([s],{type:t});return URL.createObjectURL(u)},revoke(t){"undefined"!=typeof URL&&"function"==typeof URL.revokeObjectURL&&URL.revokeObjectURL(t)}}},e.createDesktopPreviewUrlResolver=function(t){const n=new Set;return{async resolve(o){const s=await t.reader.readFileBase64(o.storageKey),c=t.objectUrls.tryCreate({mimeType:o.mimeType,base64:s});return null===c?`data:${o.mimeType};base64,${s}`:(n.add(c),c)},async release({url:o}){n.has(o)&&(n.delete(o),t.objectUrls.revoke(o))}}};var t=r(d[0]),n=r(d[1]),o=r(d[2]);async function s(o){return await(0,n.invokeDesktopCommand)("read_file_base64",{path:(0,t.fileUriToPath)(o)})}function c(t){return new Uint8Array(o.Buffer.from(t,"base64"))}},4928,[4593,3419,52]);
4
+ //# sourceMappingURL=/_expo/static/js/web/desktop-attachment-bridge-6beae08a69e097c7f552119696c67413.js.map
5
+ //# debugId=8d0f2f2e-6216-48e2-87c5-51b8c02d5b57
@@ -1,3 +1,3 @@
1
- __d(function(g,r,i,a,m,e,d){"use strict";Object.defineProperty(e,'__esModule',{value:!0}),e.createDesktopAttachmentStore=function(n){return{storageType:"desktop-file",async save(s){const o=s.id??(0,t.generateAttachmentId)(),l=s.fileName??null;if("file_uri"===s.source.kind)return await c(n,{id:o,uri:s.source.uri,mimeType:s.mimeType,fileName:l});if("data_url"===s.source.kind){const c=(0,t.parseDataUrl)(s.source.dataUrl),p=(0,t.normalizeMimeType)(s.mimeType??c.mimeType);return await y(n,{id:o,base64:c.base64,mimeType:p,fileName:l})}if("bytes"===s.source.kind){const c=(0,t.normalizeMimeType)(s.mimeType);return await p(n,{id:o,bytes:s.source.bytes,mimeType:c,fileName:l})}const f=(0,t.normalizeMimeType)(s.mimeType??s.source.blob.type),u=await(0,t.blobToBase64)(s.source.blob);return await y(n,{id:o,base64:u,mimeType:f,fileName:l})},encodeBase64:async({attachment:t})=>(f(t),await n.readFileBase64(t.storageKey)),resolvePreviewUrl:async({attachment:t})=>(f(t),await n.resolvePreviewUrl(t)),async releasePreviewUrl({attachment:t,url:s}){f(t),await n.releasePreviewUrl({url:s})},async delete({attachment:t}){f(t),await n.deleteFile({path:t.storageKey})},async garbageCollect({referencedIds:t}){await n.garbageCollect({referencedIds:Array.from(t)})}}};var t=r(d[0]);const n={"image/png":".png","image/jpeg":".jpg","image/jpg":".jpg","image/gif":".gif","image/webp":".webp","image/avif":".avif","image/heic":".heic","image/heif":".heif","image/tiff":".tiff","image/bmp":".bmp","image/svg+xml":".svg"};function s(t){const n=t.replace(/\\/g,"/").split("/"),s=n[n.length-1];return s&&s.length>0?s:null}function o(s){const o=(0,t.getFileExtensionFromName)(s.fileName);if(o)return o;const l=(0,t.getFileExtensionFromName)(s.sourcePath);return l||(n[s.mimeType]??".img")}function l(t){return{id:t.id,mimeType:t.mimeType,storageType:"desktop-file",storageKey:t.storagePath,fileName:t.fileName??null,byteSize:t.byteSize,createdAt:Date.now()}}async function c(n,c){const y=(0,t.fileUriToPath)(c.uri),p=c.fileName??s(y),f=(0,t.normalizeMimeType)(c.mimeType),u=o({fileName:p,sourcePath:y,mimeType:f}),T=await n.copyFile({attachmentId:c.id,sourcePath:y,extension:u});return l({id:c.id,mimeType:f,storagePath:T.path,byteSize:T.byteSize,fileName:p})}async function y(t,n){const s=o({fileName:n.fileName,mimeType:n.mimeType}),c=await t.writeBase64({attachmentId:n.id,base64:n.base64,extension:s});return l({id:n.id,mimeType:n.mimeType,storagePath:c.path,byteSize:c.byteSize,fileName:n.fileName})}async function p(t,n){const s=o({fileName:n.fileName,mimeType:n.mimeType}),c=await t.writeBytes({attachmentId:n.id,bytes:n.bytes,extension:s});return l({id:n.id,mimeType:n.mimeType,storagePath:c.path,byteSize:c.byteSize,fileName:n.fileName})}function f(t){if("desktop-file"!==t.storageType)throw new Error(`Unsupported desktop attachment storage type '${t.storageType}'.`)}},4920,[4593]);
2
- //# sourceMappingURL=/_expo/static/js/web/desktop-attachment-store-6888615a6b700f975c1f78501ad8577c.js.map
3
- //# debugId=991ff69a-0e82-495a-90bd-ab4e5ff58a77
1
+ __d(function(g,r,i,a,m,e,d){"use strict";Object.defineProperty(e,'__esModule',{value:!0}),e.createDesktopAttachmentStore=function(n){return{storageType:"desktop-file",async save(s){const o=s.id??(0,t.generateAttachmentId)(),l=s.fileName??null;if("file_uri"===s.source.kind)return await c(n,{id:o,uri:s.source.uri,mimeType:s.mimeType,fileName:l});if("data_url"===s.source.kind){const c=(0,t.parseDataUrl)(s.source.dataUrl),p=(0,t.normalizeMimeType)(s.mimeType??c.mimeType);return await y(n,{id:o,base64:c.base64,mimeType:p,fileName:l})}if("bytes"===s.source.kind){const c=(0,t.normalizeMimeType)(s.mimeType);return await p(n,{id:o,bytes:s.source.bytes,mimeType:c,fileName:l})}const f=(0,t.normalizeMimeType)(s.mimeType??s.source.blob.type),u=await(0,t.blobToBase64)(s.source.blob);return await y(n,{id:o,base64:u,mimeType:f,fileName:l})},encodeBase64:async({attachment:t})=>(f(t),await n.readFileBase64(t.storageKey)),resolvePreviewUrl:async({attachment:t})=>(f(t),await n.resolvePreviewUrl(t)),async releasePreviewUrl({attachment:t,url:s}){f(t),await n.releasePreviewUrl({url:s})},async delete({attachment:t}){f(t),await n.deleteFile({path:t.storageKey})},async garbageCollect({referencedIds:t}){await n.garbageCollect({referencedIds:Array.from(t)})}}};var t=r(d[0]);const n={"image/png":".png","image/jpeg":".jpg","image/jpg":".jpg","image/gif":".gif","image/webp":".webp","image/avif":".avif","image/heic":".heic","image/heif":".heif","image/tiff":".tiff","image/bmp":".bmp","image/svg+xml":".svg"};function s(t){const n=t.replace(/\\/g,"/").split("/"),s=n[n.length-1];return s&&s.length>0?s:null}function o(s){const o=(0,t.getFileExtensionFromName)(s.fileName);if(o)return o;const l=(0,t.getFileExtensionFromName)(s.sourcePath);return l||(n[s.mimeType]??".img")}function l(t){return{id:t.id,mimeType:t.mimeType,storageType:"desktop-file",storageKey:t.storagePath,fileName:t.fileName??null,byteSize:t.byteSize,createdAt:Date.now()}}async function c(n,c){const y=(0,t.fileUriToPath)(c.uri),p=c.fileName??s(y),f=(0,t.normalizeMimeType)(c.mimeType),u=o({fileName:p,sourcePath:y,mimeType:f}),T=await n.copyFile({attachmentId:c.id,sourcePath:y,extension:u});return l({id:c.id,mimeType:f,storagePath:T.path,byteSize:T.byteSize,fileName:p})}async function y(t,n){const s=o({fileName:n.fileName,mimeType:n.mimeType}),c=await t.writeBase64({attachmentId:n.id,base64:n.base64,extension:s});return l({id:n.id,mimeType:n.mimeType,storagePath:c.path,byteSize:c.byteSize,fileName:n.fileName})}async function p(t,n){const s=o({fileName:n.fileName,mimeType:n.mimeType}),c=await t.writeBytes({attachmentId:n.id,bytes:n.bytes,extension:s});return l({id:n.id,mimeType:n.mimeType,storagePath:c.path,byteSize:c.byteSize,fileName:n.fileName})}function f(t){if("desktop-file"!==t.storageType)throw new Error(`Unsupported desktop attachment storage type '${t.storageType}'.`)}},4921,[4593]);
2
+ //# sourceMappingURL=/_expo/static/js/web/desktop-attachment-store-7a589090b52127457319ba733fcca36f.js.map
3
+ //# debugId=950ba5c5-7992-4432-ad49-c7f52c12d7e4