pinomad 0.12.0 → 0.13.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (38) hide show
  1. package/dist/{chunk-np4jd070.js → chunk-4fferbxw.js} +97 -29
  2. package/dist/{chunk-ksfxqd8s.js → chunk-53xv3fny.js} +241 -48
  3. package/dist/{chunk-nppgxh6c.js → chunk-563fnad9.js} +1 -1
  4. package/dist/{chunk-41q0saz0.js → chunk-6th9xv39.js} +4 -4
  5. package/dist/{chunk-aqj9wfmb.js → chunk-90g1cg9n.js} +1 -1
  6. package/dist/{chunk-mnmqyq7d.js → chunk-aapsc9g0.js} +42 -48
  7. package/dist/{chunk-5qf1grkk.js → chunk-d4tq62yr.js} +46 -11
  8. package/dist/{chunk-gg2dcqbg.js → chunk-d9mq5d46.js} +22 -7
  9. package/dist/{chunk-47ff1d1t.js → chunk-kmzzjv53.js} +51 -4
  10. package/dist/{chunk-agq4tn9r.js → chunk-m51mq8vh.js} +4 -4
  11. package/dist/{chunk-vqkb70d7.js → chunk-maqv34cs.js} +2 -2
  12. package/dist/{chunk-vx7dy07y.js → chunk-ra86wjp5.js} +4 -4
  13. package/dist/{chunk-7wj0jh3t.js → chunk-s0h7c7da.js} +1 -1
  14. package/dist/{chunk-42nqtx5r.js → chunk-sd640dt7.js} +6 -6
  15. package/dist/{chunk-jeqsdcj1.js → chunk-t6fw0wa9.js} +4 -4
  16. package/dist/{chunk-t5abqsva.js → chunk-wd7aracm.js} +17 -5
  17. package/dist/pinomad.js +12 -12
  18. package/package.json +12 -11
  19. package/web/assets/{core-DnpzcQzs.js → core-BHm2gdHL.js} +1 -1
  20. package/web/assets/geist-mono-cyrillic-ext-wght-normal-X_5orZeX.woff2 +0 -0
  21. package/web/assets/geist-mono-cyrillic-wght-normal-DiZS0aHC.woff2 +0 -0
  22. package/web/assets/geist-mono-latin-ext-wght-normal-Bwz-egvJ.woff2 +0 -0
  23. package/web/assets/geist-mono-latin-wght-normal-XN7g48iV.woff2 +0 -0
  24. package/web/assets/geist-mono-symbols2-wght-normal-CO5SzqOn.woff2 +0 -0
  25. package/web/assets/geist-mono-vietnamese-wght-normal-DadHysG0.woff2 +0 -0
  26. package/web/assets/{highlighted-diff-Dn5ifsvK.js → highlighted-diff-DrHvSLK9.js} +2 -2
  27. package/web/assets/{highlights-DnHv6NBM.js → highlights-1aLwssz-.js} +1 -1
  28. package/web/assets/{highlights-themes-CUdrlZk3.js → highlights-themes-C1p4pFYS.js} +1 -1
  29. package/web/assets/index-A_AUJoO6.css +1 -0
  30. package/web/assets/index-BafYMKiN.js +396 -0
  31. package/web/assets/{shiki-BuPP5HCg.js → shiki-BwyCm3kZ.js} +2 -2
  32. package/web/assets/{shiki-langs-FJk0v0Ga.js → shiki-langs-CMlALLSg.js} +1 -1
  33. package/web/assets/{stream-tokenizer-Bl6bisIa.js → stream-tokenizer-BlgIhw0y.js} +1 -1
  34. package/web/assets/{theming-themes-BL_CC-Mm.js → theming-themes-DDvoqEqT.js} +1 -1
  35. package/web/assets/{xterm-view-ZsuzJb2C.js → xterm-view-BnKOnF3C.js} +1 -1
  36. package/web/index.html +2 -2
  37. package/web/assets/index-BV0ecolo.css +0 -1
  38. package/web/assets/index-DNsTTgPE.js +0 -396
@@ -3,7 +3,9 @@ import {
3
3
  MAX_ATTACHMENTS_PER_MESSAGE,
4
4
  PROTOCOL,
5
5
  RTC_DATA_CHANNEL_LABEL,
6
+ TRANSCRIPT_PAGE,
6
7
  UNAUTHORIZED_CLOSE_CODE,
8
+ addEarlier,
7
9
  checkoutOf,
8
10
  conversationStream,
9
11
  docStream,
@@ -11,11 +13,13 @@ import {
11
13
  hostStreams,
12
14
  hostSupportsCall,
13
15
  hostSupportsFeature,
16
+ isBusy,
14
17
  isRtcHello,
15
18
  organize,
16
19
  parseRtcMaxMessageSize,
17
- rtcSelectedPair
18
- } from "./chunk-47ff1d1t.js";
20
+ rtcSelectedPair,
21
+ withEarlier
22
+ } from "./chunk-kmzzjv53.js";
19
23
  import {
20
24
  SECURE_PROLOGUE,
21
25
  SecureSession,
@@ -293,12 +297,6 @@ function isTerminalsHello(value) {
293
297
  var terminalsStream = (id) => `terminals:${id}`;
294
298
  var terminalStream = (id) => `terminal:${id}`;
295
299
 
296
- // packages/protocol/src/transcript.ts
297
- function isBusy(view) {
298
- const live = view.docs?.["pi.live"];
299
- return live?.run !== undefined;
300
- }
301
-
302
300
  // packages/protocol/src/remote-durable.ts
303
301
  var DEFAULT_CANDIDATE_TIMEOUTS = {
304
302
  socketOpenMs: 5000,
@@ -396,6 +394,8 @@ class RemoteClient {
396
394
  #options;
397
395
  #listeners = new Set;
398
396
  #values = new Map;
397
+ #earlier = new Map;
398
+ #loadingEarlier = new Map;
399
399
  #wanted = new Set;
400
400
  #fresh = new Set;
401
401
  #docs = [];
@@ -1985,6 +1985,8 @@ class RemoteClient {
1985
1985
  return;
1986
1986
  }
1987
1987
  this.#values.set(frame.stream, frame.value);
1988
+ this.#earlier.delete(frame.stream);
1989
+ this.#loadingEarlier.delete(frame.stream);
1988
1990
  this.#fresh.add(frame.stream);
1989
1991
  this.#streamVersions.set(frame.stream, (this.#streamVersions.get(frame.stream) ?? 0) + 1);
1990
1992
  this.#refresh();
@@ -2012,6 +2014,8 @@ class RemoteClient {
2012
2014
  }
2013
2015
  this.#wanted.delete(frame.stream);
2014
2016
  this.#values.delete(frame.stream);
2017
+ this.#earlier.delete(frame.stream);
2018
+ this.#loadingEarlier.delete(frame.stream);
2015
2019
  this.#fresh.delete(frame.stream);
2016
2020
  const ended = new Error(`Stream ${frame.stream} ended: ${frame.reason}`);
2017
2021
  for (const waiter of this.#snapshotWaiters.get(frame.stream)?.splice(0) ?? []) {
@@ -2097,6 +2101,8 @@ class RemoteClient {
2097
2101
  continue;
2098
2102
  this.#wanted.delete(stream);
2099
2103
  this.#values.delete(stream);
2104
+ this.#earlier.delete(stream);
2105
+ this.#loadingEarlier.delete(stream);
2100
2106
  this.#fresh.delete(stream);
2101
2107
  for (const waiter of this.#snapshotWaiters.get(stream)?.splice(0) ?? [])
2102
2108
  waiter.resolve();
@@ -2106,12 +2112,50 @@ class RemoteClient {
2106
2112
  #subscribe(stream) {
2107
2113
  const refs = stream.startsWith("conversation:") && hostSupportsFeature(this.#hostMinor, "imageRefs");
2108
2114
  const since = this.#terminalPositions.get(stream);
2115
+ const window = this.#window(stream);
2109
2116
  this.#send({
2110
2117
  type: "subscribe",
2111
2118
  stream,
2112
2119
  ...refs ? { images: "ref" } : {},
2113
- ...since === undefined ? {} : { since }
2120
+ ...since === undefined ? {} : { since },
2121
+ ...window === undefined ? {} : { window }
2122
+ });
2123
+ }
2124
+ #window(stream) {
2125
+ if (!stream.startsWith("conversation:") || !hostSupportsFeature(this.#hostMinor, "transcriptPaging"))
2126
+ return;
2127
+ const from = this.#shownView(stream)?.entries[0]?.id;
2128
+ return from === undefined ? { limit: TRANSCRIPT_PAGE } : { limit: TRANSCRIPT_PAGE, from };
2129
+ }
2130
+ #shownView(stream) {
2131
+ const view = this.#values.get(stream);
2132
+ return view === undefined ? undefined : withEarlier(view, this.#earlier.get(stream));
2133
+ }
2134
+ #loadEarlier(id) {
2135
+ const stream = conversationStream(id);
2136
+ const inFlight = this.#loadingEarlier.get(stream);
2137
+ if (inFlight !== undefined)
2138
+ return inFlight;
2139
+ const requested = this.#shownView(stream)?.before;
2140
+ if (requested === undefined)
2141
+ return Promise.resolve();
2142
+ const load = this.#call("earlierEntries", { conversationId: id, before: requested, limit: TRANSCRIPT_PAGE }).then((page) => {
2143
+ if (this.#loadingEarlier.get(stream) !== load)
2144
+ return;
2145
+ const shown = this.#shownView(stream);
2146
+ if (shown === undefined)
2147
+ return;
2148
+ const earlier = addEarlier(shown, this.#earlier.get(stream), requested, page);
2149
+ if (earlier === undefined)
2150
+ return;
2151
+ this.#earlier.set(stream, earlier);
2152
+ this.#refresh();
2153
+ }).finally(() => {
2154
+ if (this.#loadingEarlier.get(stream) === load)
2155
+ this.#loadingEarlier.delete(stream);
2114
2156
  });
2157
+ this.#loadingEarlier.set(stream, load);
2158
+ return load;
2115
2159
  }
2116
2160
  #terminalsUnavailable() {
2117
2161
  if (!hostSupportsFeature(this.#hostMinor, "terminals")) {
@@ -2324,22 +2368,33 @@ class RemoteClient {
2324
2368
  record.error = undefined;
2325
2369
  this.#clearSubmissionTimer(record);
2326
2370
  }
2327
- #entriesOf(id) {
2328
- if (id === undefined)
2329
- return [];
2330
- const view = this.#values.get(conversationStream(id));
2331
- return view?.entries ?? [];
2332
- }
2333
2371
  #entryPresent(record) {
2334
- if (record.entry === undefined)
2372
+ if (record.entry === undefined || record.conversationId === undefined)
2373
+ return false;
2374
+ const shown = this.#shownView(conversationStream(record.conversationId));
2375
+ if (shown === undefined)
2335
2376
  return false;
2336
- return this.#entriesOf(record.conversationId).some((entry) => String(entry.id) === String(record.entry));
2377
+ if (shown.before !== undefined && Number(record.entry) <= Number(shown.before))
2378
+ return true;
2379
+ return shown.entries.some((entry) => String(entry.id) === String(record.entry));
2380
+ }
2381
+ #inboxOf(id) {
2382
+ if (id === undefined)
2383
+ return;
2384
+ const view = this.#values.get(conversationStream(id));
2385
+ return view?.docs?.["pi.inbox"];
2337
2386
  }
2338
2387
  #inboxHas(record) {
2339
- if (record.conversationId === undefined || record.submissionId === undefined)
2388
+ if (record.submissionId === undefined)
2340
2389
  return false;
2341
- const inbox = this.#values.get(docStream("pi.inbox", record.conversationId));
2342
- return (inbox?.items ?? []).some((item) => String(item.id) === String(record.submissionId));
2390
+ const items = this.#inboxOf(record.conversationId)?.items ?? [];
2391
+ return items.some((item) => String(item.id) === String(record.submissionId));
2392
+ }
2393
+ #markChecked(record) {
2394
+ if (record.conversationId === undefined)
2395
+ return;
2396
+ record.checkedVersion = this.#streamVersions.get(conversationStream(record.conversationId)) ?? 0;
2397
+ record.checkedInbox = this.#inboxOf(record.conversationId);
2343
2398
  }
2344
2399
  #applySubmissionRecord(record, found) {
2345
2400
  record.admitted = true;
@@ -2370,11 +2425,10 @@ class RemoteClient {
2370
2425
  this.#settleSubmission(record);
2371
2426
  continue;
2372
2427
  }
2373
- if (record.conversationId !== undefined && record.submissionId !== undefined && record.admitted && (record.entry !== undefined || !this.#inboxHas(record))) {
2428
+ if (record.conversationId !== undefined && !record.confirming && record.admitted && (record.entry !== undefined || !this.#inboxHas(record))) {
2374
2429
  const stream = conversationStream(record.conversationId);
2375
- const version = (this.#streamVersions.get(stream) ?? 0) + (this.#streamVersions.get(docStream("pi.inbox", record.conversationId)) ?? 0);
2376
- if (this.#fresh.has(stream) && record.checkedVersion !== version) {
2377
- record.checkedVersion = version;
2430
+ if (this.#fresh.has(stream) && (record.checkedVersion !== (this.#streamVersions.get(stream) ?? 0) || record.checkedInbox !== this.#inboxOf(record.conversationId))) {
2431
+ this.#markChecked(record);
2378
2432
  this.#confirmSubmission(record);
2379
2433
  }
2380
2434
  }
@@ -2408,6 +2462,8 @@ class RemoteClient {
2408
2462
  } catch {} finally {
2409
2463
  record.confirming = false;
2410
2464
  }
2465
+ if (!this.#closed && !this.#submissionSettled(record))
2466
+ this.#reconcileSubmissions();
2411
2467
  }
2412
2468
  #submissionArgs(record) {
2413
2469
  const conversationId = record.conversationId;
@@ -2451,11 +2507,11 @@ class RemoteClient {
2451
2507
  record.phase = "inFlight";
2452
2508
  if (this.#entryPresent(record))
2453
2509
  this.#settleSubmission(record);
2510
+ } else if (this.#inboxHas(record)) {
2511
+ this.#settleSubmission(record);
2454
2512
  } else {
2455
2513
  record.phase = "inFlight";
2456
- if (record.conversationId !== undefined) {
2457
- record.checkedVersion = (this.#streamVersions.get(conversationStream(record.conversationId)) ?? 0) + (this.#streamVersions.get(docStream("pi.inbox", record.conversationId)) ?? 0);
2458
- }
2514
+ this.#markChecked(record);
2459
2515
  this.#confirmSubmission(record);
2460
2516
  }
2461
2517
  this.#touchSubmissions();
@@ -2701,7 +2757,7 @@ class RemoteClient {
2701
2757
  this.#reconcileSubmissions();
2702
2758
  const current = this.#current;
2703
2759
  const side = this.#side;
2704
- const conversation = current === undefined ? undefined : this.#values.get(conversationStream(current));
2760
+ const conversation = current === undefined ? undefined : this.#shownView(conversationStream(current));
2705
2761
  const summaries = this.#host("conversations") ?? [];
2706
2762
  const index = this.#host("index") ?? { projects: [], conversations: [] };
2707
2763
  const devices = this.#host("devices")?.devices ?? [];
@@ -2717,7 +2773,7 @@ class RemoteClient {
2717
2773
  submissions: this.#activeSubmissions(),
2718
2774
  side: side === undefined ? undefined : {
2719
2775
  id: side,
2720
- conversation: this.#values.get(conversationStream(side)),
2776
+ conversation: this.#shownView(conversationStream(side)),
2721
2777
  docs: this.#docsOf(side)
2722
2778
  },
2723
2779
  devices,
@@ -2949,6 +3005,17 @@ class RemoteClient {
2949
3005
  });
2950
3006
  return outcome;
2951
3007
  }),
3008
+ reorderQueued: (submissionId, before, target) => this.#request(async () => {
3009
+ if (!hostSupportsCall(this.#hostMinor, "reorderQueued")) {
3010
+ throw new Error("The host is too old for this (needs protocol 5.29); run `pinomad upgrade` on the host");
3011
+ }
3012
+ const { outcome } = await this.#call("reorderQueued", {
3013
+ conversationId: target ?? conversationId(),
3014
+ submissionId,
3015
+ ...before === undefined ? {} : { before }
3016
+ });
3017
+ return outcome;
3018
+ }),
2952
3019
  setThinkingLevel: (level) => this.#command(() => this.#call("setThinkingLevel", { conversationId: conversationId(), level })),
2953
3020
  setModel: (model) => this.#command(() => this.#call("setModel", { conversationId: conversationId(), model })),
2954
3021
  setAgent: (agent) => this.#command(() => {
@@ -3017,6 +3084,7 @@ class RemoteClient {
3017
3084
  }
3018
3085
  return this.#call("listSkills", { scope });
3019
3086
  },
3087
+ loadEarlier: (id) => this.#loadEarlier(id),
3020
3088
  listCommands: (id) => {
3021
3089
  if (!hostSupportsCall(this.#hostMinor, "listCommands")) {
3022
3090
  return Promise.reject(new Error("The host is too old for this (needs protocol 5.17); run `pinomad upgrade` on the host"));