neoctl 0.2.22 → 0.2.23

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/web/html.js +22 -3
  2. package/dist/web/html.js.map +1 -1
  3. package/dist/web/index.d.ts +24 -1
  4. package/dist/web/index.js +104 -19
  5. package/dist/web/index.js.map +1 -1
  6. package/package.json +1 -1
  7. package/scripts/copy-model-metadata.mjs +4 -4
  8. package/scripts/install-ripgrep.cjs +210 -210
  9. package/scripts/release-local.mjs +190 -190
  10. package/scripts/verify-ripgrep.cjs +86 -83
  11. package/vendor/ripgrep/darwin-arm64/COPYING +3 -3
  12. package/vendor/ripgrep/darwin-arm64/LICENSE-MIT +21 -21
  13. package/vendor/ripgrep/darwin-arm64/UNLICENSE +24 -24
  14. package/vendor/ripgrep/darwin-arm64/manifest.json +7 -7
  15. package/vendor/ripgrep/darwin-arm64/rg +0 -0
  16. package/vendor/ripgrep/darwin-x64/COPYING +3 -3
  17. package/vendor/ripgrep/darwin-x64/LICENSE-MIT +21 -21
  18. package/vendor/ripgrep/darwin-x64/UNLICENSE +24 -24
  19. package/vendor/ripgrep/darwin-x64/manifest.json +7 -7
  20. package/vendor/ripgrep/darwin-x64/rg +0 -0
  21. package/vendor/ripgrep/linux-arm64/COPYING +3 -3
  22. package/vendor/ripgrep/linux-arm64/LICENSE-MIT +21 -21
  23. package/vendor/ripgrep/linux-arm64/UNLICENSE +24 -24
  24. package/vendor/ripgrep/linux-arm64/manifest.json +7 -7
  25. package/vendor/ripgrep/linux-arm64/rg +0 -0
  26. package/vendor/ripgrep/linux-x64/COPYING +3 -3
  27. package/vendor/ripgrep/linux-x64/LICENSE-MIT +21 -21
  28. package/vendor/ripgrep/linux-x64/UNLICENSE +24 -24
  29. package/vendor/ripgrep/linux-x64/manifest.json +7 -7
  30. package/vendor/ripgrep/linux-x64/rg +0 -0
  31. package/vendor/ripgrep/win32-arm64/COPYING +3 -3
  32. package/vendor/ripgrep/win32-arm64/LICENSE-MIT +21 -21
  33. package/vendor/ripgrep/win32-arm64/UNLICENSE +24 -24
  34. package/vendor/ripgrep/win32-arm64/manifest.json +7 -7
  35. package/vendor/ripgrep/win32-x64/COPYING +3 -3
  36. package/vendor/ripgrep/win32-x64/LICENSE-MIT +21 -21
  37. package/vendor/ripgrep/win32-x64/UNLICENSE +24 -24
  38. package/vendor/ripgrep/win32-x64/manifest.json +7 -7
package/dist/web/html.js CHANGED
@@ -231,7 +231,7 @@ es.addEventListener('error', () => {
231
231
  connection.hidden = false;
232
232
  connection.textContent = 'reconnecting…';
233
233
  });
234
- es.addEventListener('sync', (event) => {
234
+ es.addEventListener('sync', (event) => {
235
235
  const payload = JSON.parse(event.data);
236
236
  state.lines = payload.lines || [];
237
237
  state.status = payload.status || state.status;
@@ -245,8 +245,27 @@ es.addEventListener('sync', (event) => {
245
245
  if (payload.catalog) state.catalog = payload.catalog;
246
246
  if (payload.interactive) state.interactive = payload.interactive;
247
247
  updateInputPlaceholder();
248
- scheduleRender();
249
- });
248
+ scheduleRender();
249
+ });
250
+ es.addEventListener('delta', (event) => {
251
+ const payload = JSON.parse(event.data);
252
+ for (const operation of payload.operations || []) {
253
+ if (operation.type === 'line.append') {
254
+ if (!state.lines.some((line) => String(line.id) === String(operation.line && operation.line.id))) state.lines.push(operation.line);
255
+ continue;
256
+ }
257
+ const index = state.lines.findIndex((line) => String(line.id) === String(operation.id));
258
+ if (index < 0) {
259
+ location.reload();
260
+ return;
261
+ }
262
+ const line = state.lines[index];
263
+ if (operation.type === 'line.text.append') state.lines[index] = { ...line, text: String(line.text || '') + String(operation.text || '') };
264
+ else if (operation.type === 'line.patch') state.lines[index] = { ...line, ...(operation.patch || {}) };
265
+ }
266
+ if (payload.status) state.status = payload.status;
267
+ scheduleRender();
268
+ });
250
269
 
251
270
  function scheduleRender() {
252
271
  if (renderPending) return;
@@ -1 +1 @@
1
- {"version":3,"file":"html.js","sourceRoot":"","sources":["../../src/web/html.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,QAAQ,GAAG,MAAM,CAAC,GAAG,CAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;QAq1B1B,CAAC"}
1
+ {"version":3,"file":"html.js","sourceRoot":"","sources":["../../src/web/html.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,QAAQ,GAAG,MAAM,CAAC,GAAG,CAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;QAw2B1B,CAAC"}
@@ -138,6 +138,18 @@ interface WebSetAppPromptPayload {
138
138
  source?: string;
139
139
  clear?: boolean;
140
140
  }
141
+ type WebLineOperation = {
142
+ type: "line.append";
143
+ line: UiLine;
144
+ } | {
145
+ type: "line.text.append";
146
+ id: number;
147
+ text: string;
148
+ } | {
149
+ type: "line.patch";
150
+ id: number;
151
+ patch: Partial<UiLine>;
152
+ };
141
153
  export declare function runWebServer(argv?: string[], runtimeOptions?: RunWebServerOptions): Promise<void>;
142
154
  export declare function createWebRuntime(options?: CreateWebRuntimeOptions): Promise<WebRuntime>;
143
155
  export declare class WebRuntimeRouter {
@@ -153,6 +165,10 @@ export declare function createWebRuntimeRouter(options?: WebRuntimeRouterOptions
153
165
  export declare class WebRepl {
154
166
  private runtime;
155
167
  private readonly subscribers;
168
+ private eventSequence;
169
+ private pendingDeltaOperations;
170
+ private pendingDeltaStatus;
171
+ private pendingDeltaTimer;
156
172
  private lineId;
157
173
  private assistantLineId;
158
174
  private thinkingLineId;
@@ -264,7 +280,7 @@ export declare class WebRepl {
264
280
  cancelled: boolean;
265
281
  };
266
282
  private append;
267
- private updateLine;
283
+ private appendLineText;
268
284
  private replaceLineText;
269
285
  private replaceLine;
270
286
  private setBusy;
@@ -283,6 +299,13 @@ export declare class WebRepl {
283
299
  private handleCommandOrPrompt;
284
300
  private runCompaction;
285
301
  private send;
302
+ private broadcastDelta;
303
+ private queueDeltaOperation;
304
+ private queueDeltaStatus;
305
+ private scheduleDeltaFlush;
306
+ private flushDeltaOperations;
307
+ private discardPendingDeltaOperations;
286
308
  private broadcastSync;
287
309
  }
310
+ export declare function compactLineOperations(operations: WebLineOperation[]): WebLineOperation[];
288
311
  export {};
package/dist/web/index.js CHANGED
@@ -249,6 +249,10 @@ function webRuntimeScopeKey(scope) {
249
249
  export class WebRepl {
250
250
  runtime;
251
251
  subscribers = new Set();
252
+ eventSequence = 0;
253
+ pendingDeltaOperations = [];
254
+ pendingDeltaStatus = false;
255
+ pendingDeltaTimer;
252
256
  lineId = 0;
253
257
  assistantLineId;
254
258
  thinkingLineId;
@@ -279,16 +283,17 @@ export class WebRepl {
279
283
  runtime.engine.onSessionTitleChange(() => this.broadcastSync());
280
284
  }
281
285
  subscribe(res) {
282
- this.subscribers.add(res);
286
+ const subscriber = { response: res, blocked: false, needsSync: false };
287
+ this.subscribers.add(subscriber);
283
288
  res.writeHead(200, {
284
289
  "Content-Type": "text/event-stream; charset=utf-8",
285
290
  "Cache-Control": "no-cache, no-transform",
286
291
  Connection: "keep-alive",
287
292
  "X-Accel-Buffering": "no",
288
293
  });
289
- this.send(res, "sync", this.snapshot(true));
294
+ this.send(subscriber, "sync", this.snapshot(true));
290
295
  reqKeepAlive(res);
291
- res.on("close", () => this.subscribers.delete(res));
296
+ res.on("close", () => this.subscribers.delete(subscriber));
292
297
  }
293
298
  snapshot(includeCatalog = false) {
294
299
  return {
@@ -505,15 +510,19 @@ export class WebRepl {
505
510
  this.broadcastSync();
506
511
  return { ok: true, cancelled: had };
507
512
  }
508
- append(line) {
513
+ append(line, streaming = false) {
509
514
  const id = ++this.lineId;
510
- this.lines.push({ id, ...line });
511
- this.broadcastSync();
515
+ const nextLine = { id, ...line };
516
+ this.lines.push(nextLine);
517
+ if (streaming)
518
+ this.broadcastDelta({ type: "line.append", line: nextLine });
519
+ else
520
+ this.broadcastSync();
512
521
  return id;
513
522
  }
514
- updateLine(id, updater) {
515
- this.lines = this.lines.map((line) => line.id === id ? { ...line, text: updater(line.text) } : line);
516
- this.broadcastSync();
523
+ appendLineText(id, text) {
524
+ this.lines = this.lines.map((line) => line.id === id ? { ...line, text: line.text + text } : line);
525
+ this.broadcastDelta({ type: "line.text.append", id, text });
517
526
  }
518
527
  replaceLineText(id, text) {
519
528
  this.lines = this.lines.map((line) => line.id === id ? { ...line, text } : line);
@@ -621,6 +630,7 @@ export class WebRepl {
621
630
  if (id === undefined)
622
631
  return;
623
632
  this.lines = this.lines.map((line) => line.id === id ? { ...line, live: false } : line);
633
+ this.queueDeltaOperation({ type: "line.patch", id, patch: { live: false } });
624
634
  }
625
635
  finalizeThinkingLine() {
626
636
  const id = this.thinkingLineId;
@@ -642,22 +652,26 @@ export class WebRepl {
642
652
  this.broadcastSync();
643
653
  return;
644
654
  }
645
- if (event.type === "state" || event.type === "context.metrics" || event.type === "usage" || event.type === "tool_call.delta" || event.type === "retrying") {
655
+ if (event.type === "tool_call.delta") {
656
+ this.queueDeltaStatus();
657
+ return;
658
+ }
659
+ if (event.type === "state" || event.type === "context.metrics" || event.type === "usage" || event.type === "retrying") {
646
660
  this.broadcastSync();
647
661
  return;
648
662
  }
649
663
  if (event.type === "assistant.delta") {
650
664
  this.finalizeThinkingLine();
651
- const id = this.assistantLineId ?? this.append({ kind: "assistant", text: "", live: true });
665
+ const id = this.assistantLineId ?? this.append({ kind: "assistant", text: "", live: true }, true);
652
666
  this.assistantLineId = id;
653
- this.updateLine(id, (text) => text + event.text);
667
+ this.appendLineText(id, event.text);
654
668
  return;
655
669
  }
656
670
  if (event.type === "thinking.delta") {
657
- const id = this.thinkingLineId ?? this.finalizedThinkingLineId ?? this.append(thinkingLine("", true));
671
+ const id = this.thinkingLineId ?? this.finalizedThinkingLineId ?? this.append(thinkingLine("", true), true);
658
672
  this.thinkingLineId = id;
659
673
  this.finalizedThinkingLineId = undefined;
660
- this.updateLine(id, (text) => text + event.text);
674
+ this.appendLineText(id, event.text);
661
675
  return;
662
676
  }
663
677
  if (event.type === "message") {
@@ -939,15 +953,86 @@ export class WebRepl {
939
953
  this.setStatus({ ...this.status, phase: "ready", detail: undefined, activityTick: this.status.activityTick + 1 });
940
954
  }
941
955
  }
942
- send(res, event, data) {
943
- res.write(`event: ${event}\n`);
944
- res.write(`data: ${JSON.stringify(data)}\n\n`);
956
+ send(subscriber, event, data) {
957
+ if (subscriber.blocked) {
958
+ subscriber.needsSync = true;
959
+ return;
960
+ }
961
+ const eventId = ++this.eventSequence;
962
+ const frame = `id: ${eventId}\nevent: ${event}\ndata: ${JSON.stringify(data)}\n\n`;
963
+ if (subscriber.response.write(frame))
964
+ return;
965
+ subscriber.blocked = true;
966
+ subscriber.response.once("drain", () => {
967
+ subscriber.blocked = false;
968
+ if (!subscriber.needsSync || subscriber.response.destroyed)
969
+ return;
970
+ subscriber.needsSync = false;
971
+ this.send(subscriber, "sync", this.snapshot(false));
972
+ });
973
+ }
974
+ broadcastDelta(operation) {
975
+ this.queueDeltaOperation(operation);
976
+ }
977
+ queueDeltaOperation(operation) {
978
+ this.pendingDeltaOperations.push(operation);
979
+ this.scheduleDeltaFlush();
980
+ }
981
+ queueDeltaStatus() {
982
+ this.pendingDeltaStatus = true;
983
+ this.scheduleDeltaFlush();
984
+ }
985
+ scheduleDeltaFlush() {
986
+ if (this.pendingDeltaTimer)
987
+ return;
988
+ this.pendingDeltaTimer = setTimeout(() => this.flushDeltaOperations(), 25);
989
+ this.pendingDeltaTimer.unref?.();
990
+ }
991
+ flushDeltaOperations() {
992
+ this.pendingDeltaTimer = undefined;
993
+ if (this.pendingDeltaOperations.length === 0 && !this.pendingDeltaStatus)
994
+ return;
995
+ const operations = compactLineOperations(this.pendingDeltaOperations);
996
+ this.pendingDeltaOperations = [];
997
+ this.pendingDeltaStatus = false;
998
+ const payload = {
999
+ protocolVersion: 2,
1000
+ sessionId: this.runtime.engine.snapshot().session?.sessionId,
1001
+ operations,
1002
+ status: this.status,
1003
+ };
1004
+ for (const subscriber of this.subscribers)
1005
+ this.send(subscriber, "delta", payload);
1006
+ }
1007
+ discardPendingDeltaOperations() {
1008
+ if (this.pendingDeltaTimer)
1009
+ clearTimeout(this.pendingDeltaTimer);
1010
+ this.pendingDeltaTimer = undefined;
1011
+ this.pendingDeltaOperations = [];
1012
+ this.pendingDeltaStatus = false;
945
1013
  }
946
1014
  broadcastSync() {
1015
+ this.discardPendingDeltaOperations();
947
1016
  const payload = this.snapshot(false);
948
- for (const res of this.subscribers)
949
- this.send(res, "sync", payload);
1017
+ for (const subscriber of this.subscribers)
1018
+ this.send(subscriber, "sync", payload);
1019
+ }
1020
+ }
1021
+ export function compactLineOperations(operations) {
1022
+ const compacted = [];
1023
+ for (const operation of operations) {
1024
+ const previous = compacted.at(-1);
1025
+ if (operation.type === "line.text.append" && previous?.type === "line.text.append" && previous.id === operation.id) {
1026
+ previous.text += operation.text;
1027
+ continue;
1028
+ }
1029
+ if (operation.type === "line.patch" && previous?.type === "line.patch" && previous.id === operation.id) {
1030
+ previous.patch = { ...previous.patch, ...operation.patch };
1031
+ continue;
1032
+ }
1033
+ compacted.push(operation.type === "line.patch" ? { ...operation, patch: { ...operation.patch } } : { ...operation });
950
1034
  }
1035
+ return compacted;
951
1036
  }
952
1037
  function reqKeepAlive(res) {
953
1038
  const timer = setInterval(() => res.write(": keep-alive\n\n"), 25_000);