@ai-ecoverse/slicc-spectrum 1.91.0 → 1.93.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.
@@ -5,8 +5,26 @@ import {
5
5
  } from "./chunk-XQHRTHDQ.js";
6
6
  import {
7
7
  DummySettings,
8
- clock
9
- } from "./chunk-VRFAMBWK.js";
8
+ accounts,
9
+ agents,
10
+ clock,
11
+ conversations,
12
+ defaults,
13
+ directories,
14
+ files,
15
+ laterModels,
16
+ models,
17
+ mountPoint,
18
+ mounted,
19
+ pending,
20
+ providerAccount,
21
+ providerAccounts,
22
+ providerFixtures,
23
+ queues,
24
+ skillEdit,
25
+ tabs,
26
+ terminals
27
+ } from "./chunk-RYA3OPGE.js";
10
28
  import {
11
29
  Emitter
12
30
  } from "./chunk-T5NHW4KC.js";
@@ -196,23 +214,23 @@ function session(now2) {
196
214
  const harbor2 = { tabId: "tab-preview", agentId: "cone-harbor" };
197
215
  return Array.from({ length: 170 }, (_, i) => {
198
216
  const city = cities[i % cities.length];
199
- const at3 = now2 - 286 * second + i * 960;
217
+ const at = now2 - 286 * second + i * 960;
200
218
  switch (i % 5) {
201
219
  case 0:
202
220
  return {
203
221
  ...harbor2,
204
222
  kind: "goto",
205
223
  value: `http://localhost:8787/forecast?city=${city}&days=${i % 7 + 1}&units=metric&compare=tides,wind,swell&session=run-${i}`,
206
- at: at3
224
+ at
207
225
  };
208
226
  case 1:
209
- return { ...harbor2, kind: "snapshot", at: at3 };
227
+ return { ...harbor2, kind: "snapshot", at };
210
228
  case 2:
211
- return { ...harbor2, kind: "click", target: `button "Day ${i % 7 + 1}"`, at: at3 };
229
+ return { ...harbor2, kind: "click", target: `button "Day ${i % 7 + 1}"`, at };
212
230
  case 3:
213
- return { ...harbor2, kind: "scroll", at: at3 };
231
+ return { ...harbor2, kind: "scroll", at };
214
232
  default:
215
- return { ...harbor2, kind: "screenshot", at: at3 };
233
+ return { ...harbor2, kind: "screenshot", at };
216
234
  }
217
235
  });
218
236
  }
@@ -327,9 +345,9 @@ var DummyBrowser = class extends Emitter {
327
345
  this.emit("action", { ...action });
328
346
  }
329
347
  async run(script2) {
330
- for (const [index2, draft] of script2.entries()) {
348
+ for (const [index, draft] of script2.entries()) {
331
349
  const id = this.record(draft);
332
- if (index2 === script2.length - 1) return;
350
+ if (index === script2.length - 1) return;
333
351
  await this.#clock.sleep(20);
334
352
  this.finish(id);
335
353
  await this.#clock.sleep(10);
@@ -405,11 +423,11 @@ var DummyBrowser = class extends Emitter {
405
423
  this.#load(id);
406
424
  }
407
425
  close(id) {
408
- const index2 = this.#tabs.findIndex((tab) => tab.id === id);
409
- if (index2 < 0) return;
410
- this.#tabs.splice(index2, 1);
426
+ const index = this.#tabs.findIndex((tab) => tab.id === id);
427
+ if (index < 0) return;
428
+ this.#tabs.splice(index, 1);
411
429
  if (this.#active === id)
412
- this.#active = this.#tabs[Math.min(index2, this.#tabs.length - 1)]?.id ?? null;
430
+ this.#active = this.#tabs[Math.min(index, this.#tabs.length - 1)]?.id ?? null;
413
431
  this.#changed();
414
432
  }
415
433
  async screenshot(id) {
@@ -513,1537 +531,6 @@ var DummyFollow = class extends Emitter {
513
531
  }
514
532
  };
515
533
 
516
- // src/dummy/showcase.ts
517
- var start = Date.UTC(2026, 9, 4, 16, 0);
518
- var at = (minutes2) => start + minutes2 * 6e4;
519
- function picture(label2, from, to, width = 640, height = 400) {
520
- const svg = `<svg xmlns="http://www.w3.org/2000/svg" width="${width}" height="${height}" viewBox="0 0 ${width} ${height}"><defs><linearGradient id="g" x1="0" y1="0" x2="1" y2="1"><stop offset="0" stop-color="${from}"/><stop offset="1" stop-color="${to}"/></linearGradient></defs><rect width="${width}" height="${height}" fill="url(#g)"/><text x="50%" y="50%" font-family="sans-serif" font-size="${Math.round(height / 9)}" fill="#ffffff" text-anchor="middle" dominant-baseline="middle">${label2}</text></svg>`;
521
- return `data:image/svg+xml;charset=utf-8,${encodeURIComponent(svg)}`;
522
- }
523
- function tone(seconds = 0.6, frequency = 440, rate = 8e3) {
524
- const samples = Math.round(seconds * rate);
525
- const bytes = new Uint8Array(44 + samples);
526
- const view = new DataView(bytes.buffer);
527
- const text = (offset, value) => {
528
- for (let i = 0; i < value.length; i++) bytes[offset + i] = value.charCodeAt(i);
529
- };
530
- text(0, "RIFF");
531
- view.setUint32(4, 36 + samples, true);
532
- text(8, "WAVEfmt ");
533
- view.setUint32(16, 16, true);
534
- view.setUint16(20, 1, true);
535
- view.setUint16(22, 1, true);
536
- view.setUint32(24, rate, true);
537
- view.setUint32(28, rate, true);
538
- view.setUint16(32, 1, true);
539
- view.setUint16(34, 8, true);
540
- text(36, "data");
541
- view.setUint32(40, samples, true);
542
- for (let i = 0; i < samples; i++) {
543
- const fade = Math.min(1, (samples - i) / (rate / 10));
544
- bytes[44 + i] = 128 + Math.round(60 * fade * Math.sin(2 * Math.PI * frequency * i / rate));
545
- }
546
- let binary = "";
547
- for (const byte of bytes) binary += String.fromCharCode(byte);
548
- return `data:audio/wav;base64,${btoa(binary)}`;
549
- }
550
- function tool(id, name2, title, input, output, extra = {}) {
551
- return { id, name: name2, title, input, output, status: "done", paths: [], ...extra };
552
- }
553
- var markdown = [
554
- "## The forecast API in one page",
555
- "",
556
- "harbor answers `GET /forecast?city=\u2026` with the day\u2019s **high**, **low** and a *short summary*, and caches per city for an hour. ~~XML output~~ is gone.",
557
- "",
558
- "### How a request flows",
559
- "",
560
- "1. The worker parses the city.",
561
- "2. The cache answers if it has a fresh entry:",
562
- " - same UTC day",
563
- " - younger than one hour",
564
- "3. Otherwise the upstream call runs, with three retries.",
565
- "",
566
- "> Upstream is slow at the top of the hour. Retries back off at 250, 500 and 1000 ms.",
567
- "",
568
- "```ts",
569
- "export async function forecast(city: string): Promise<Forecast> {",
570
- " const cached = cache.get(city);",
571
- " if (cached) return cached;",
572
- " return cache.set(city, await retry(() => upstream(city)));",
573
- "}",
574
- "```",
575
- "",
576
- "| Route | Cache | Typical latency |",
577
- "| --- | --- | ---: |",
578
- "| `/forecast` | 1 hour, per city | 38 ms |",
579
- "| `/health` | none | 2 ms |",
580
- "| `/forecast` (miss) | \u2014 | 410 ms |",
581
- "",
582
- "- [x] TTL fix merged",
583
- "- [ ] Move the cache to KV",
584
- "",
585
- "Details are in the [API reference](https://api.example.com/docs/v2/forecast). A long path that must wrap: `/workspace/harbor/node_modules/.cache/wrangler/state/v3/cache/miniflare-CacheObject/7c1f0e3b9a5d4e2f8b6a1c0d9e8f7a6b5c4d3e2f1a0b9c8d7e6f5a4b3c2d1e0f.sqlite`."
586
- ].join("\n");
587
- var toolShapes = [
588
- tool("k-t1", "bash", "Count the routes", "rg -c 'pathname ===' src", "src/index.ts:2"),
589
- tool(
590
- "k-t2",
591
- "read_file",
592
- "Read the router",
593
- "/workspace/harbor/src/index.ts",
594
- "import { forecast } from './routes/forecast.ts';\n\u2026",
595
- {
596
- paths: ["/workspace/harbor/src/index.ts"]
597
- }
598
- ),
599
- tool(
600
- "k-t3",
601
- "write_file",
602
- "Create the KV binding notes",
603
- "/workspace/harbor/docs/kv.md",
604
- "Wrote 18 lines",
605
- {
606
- paths: ["/workspace/harbor/docs/kv.md"]
607
- }
608
- ),
609
- tool(
610
- "k-t4",
611
- "edit_file",
612
- "Rename the cache key",
613
- "/workspace/harbor/src/lib/cache.ts",
614
- 'No match for "cityKey(" in src/lib/cache.ts',
615
- {
616
- status: "error",
617
- paths: ["/workspace/harbor/src/lib/cache.ts"]
618
- }
619
- ),
620
- tool(
621
- "k-t5",
622
- "grep",
623
- "Find TODOs",
624
- 'TODO --glob "src/**"',
625
- "src/routes/forecast.ts:14: TODO: cache negative results\nsrc/lib/units.ts:3: TODO: round half to even"
626
- ),
627
- tool(
628
- "k-t6",
629
- "web_fetch",
630
- "Fetch the API changelog",
631
- "https://api.example.com/changelog.json",
632
- '{ "latest": "2.4.1", "breaking": false }'
633
- ),
634
- tool(
635
- "k-t7",
636
- "browser",
637
- "Screenshot the preview",
638
- "screenshot http://localhost:8787/",
639
- "Captured 1280\xD7800",
640
- {
641
- image: picture("localhost:8787", "#3b63fb", "#0a7a43", 640, 400)
642
- }
643
- ),
644
- tool(
645
- "k-t8",
646
- "scoop_scoop",
647
- "Start a scoop for the docs",
648
- "name: docs-pass\ntask: Update the forecast page to Celsius",
649
- "Scoop docs-pass is running"
650
- ),
651
- tool(
652
- "k-t9",
653
- "feed_scoop",
654
- "Hand the screenshots to docs-pass",
655
- "scoop_name: docs-pass\nmessage: Use the new screenshots in /tmp/shots",
656
- "Delivered"
657
- ),
658
- tool(
659
- "k-t10",
660
- "send_message",
661
- "Tell quiet-otter the tests pass",
662
- "to: quiet-otter\nmessage: CI is green, merge when ready",
663
- "Delivered"
664
- ),
665
- tool(
666
- "k-t11",
667
- "drop_scoop",
668
- "Wrap up amber-heron",
669
- "scoop_name: amber-heron",
670
- "Dropped amber-heron; its notes are in /shared/notes"
671
- ),
672
- tool(
673
- "k-t12",
674
- "update_global_memory",
675
- "Remember the cache rule",
676
- "Cache keys are per city and per UTC day.",
677
- "Memory updated (3 sections, 412 characters)"
678
- ),
679
- tool(
680
- "k-mcp",
681
- "mcp__docs__search",
682
- "docs \xB7 search",
683
- '{\n "query": "forecast units"\n}',
684
- "2 pages: /forecast, /units"
685
- ),
686
- tool("k-t13", "bash", "Deploy to staging", "wrangler deploy --env staging", "Stopped", {
687
- status: "cancelled"
688
- }),
689
- tool("k-t14", "bash", "Watch the logs", "wrangler tail --env staging", "", { status: "running" }),
690
- tool(
691
- "k-t16",
692
- "bash",
693
- "Check the staging routes",
694
- "wrangler routes list --env staging",
695
- "ROUTE ZONE WORKER ENV\nforecast.harbor.example/v2/forecast/* harbor.example harbor-forecast-v2 staging\nerror: the route forecast.harbor.example/v2/units/* belongs to another account; ask its owner to release it first",
696
- {
697
- status: "error",
698
- notes: [
699
- { severity: "error", text: "Exited with code 5" },
700
- {
701
- severity: "warn",
702
- text: "Output truncated: 12 lines and 1,840 bytes dropped from the start"
703
- },
704
- { severity: "info", text: "Full output in /tmp/pi-bash-7f3a.log" }
705
- ]
706
- }
707
- )
708
- ];
709
- var licks = [
710
- [
711
- "webhook",
712
- "GitHub \xB7 pull_request.opened",
713
- "example/harbor#58 Add retries for upstream timeouts",
714
- '{\n "action": "opened",\n "number": 58,\n "repository": { "full_name": "example/harbor" }\n}',
715
- {}
716
- ],
717
- [
718
- "cron",
719
- "Every weekday 09:00",
720
- "Morning summary for the harbor cone",
721
- void 0,
722
- { count: 3 }
723
- ],
724
- [
725
- "sprinkle",
726
- "Release board",
727
- "Button \u201CShip 1.9.0\u201D clicked",
728
- '{ "button": "ship", "version": "1.9.0" }',
729
- {}
730
- ],
731
- [
732
- "fswatch",
733
- "/workspace/harbor/src",
734
- "2 files changed",
735
- "modified /workspace/harbor/src/lib/cache.ts\ncreated /workspace/harbor/src/lib/retry.ts",
736
- {}
737
- ],
738
- [
739
- "session-reload",
740
- "Session restored",
741
- "The page reloaded; 4 cones resumed from storage",
742
- void 0,
743
- {}
744
- ],
745
- [
746
- "navigate",
747
- "api.example.com",
748
- "A page offered a SLICC handoff: open the forecast docs",
749
- '{ "verb": "open", "target": "https://api.example.com/docs/v2/forecast" }',
750
- {}
751
- ],
752
- [
753
- "discovery",
754
- "api.example.com",
755
- "Found an ai-catalog.json with 3 tools",
756
- "https://api.example.com/.well-known/ai-catalog.json",
757
- {}
758
- ],
759
- ["upgrade", "SLICC updated", "6.4.0 \u2192 6.5.0", void 0, {}],
760
- [
761
- "workflow",
762
- "release-notes",
763
- "Step 2 of 4 finished: collect merged pull requests",
764
- void 0,
765
- {}
766
- ],
767
- ["bash", "Job 3", "npm run build exited with status 0 after 41 s", void 0, {}],
768
- ["jshd", "collect.jsh", "Script finished: 12 pull requests since v1.8.0", void 0, {}],
769
- ["preview", "Preview bridge", "Connected from localhost:8787", void 0, {}],
770
- [
771
- "cherry",
772
- "Host page",
773
- "Event \u201Ccart-updated\u201D from shop.example.com",
774
- '{ "items": 3, "total": 42.5 }',
775
- {}
776
- ],
777
- ["scoop-notify", "docs-pass", "Finished: the forecast page now shows Celsius", void 0, {}],
778
- ["scoop-idle", "amber-heron", "Idle for 30 minutes", void 0, {}],
779
- ["scoop-wait", "quiet-otter", "The wait for CI resolved: all checks passed", void 0, {}],
780
- [
781
- "sudo-request",
782
- "docs-pass",
783
- "Wants to push to example/harbor (branch docs/celsius)",
784
- "git push origin docs/celsius",
785
- { state: "pending", expiresAt: Date.now() + 10 * 6e4 }
786
- ],
787
- [
788
- "sudo-request",
789
- "quiet-otter",
790
- "Wants to read secrets: UPSTREAM_TOKEN",
791
- void 0,
792
- { state: "confirmed" }
793
- ],
794
- [
795
- "sudo-request",
796
- "amber-heron",
797
- "Wants to run: rm -rf /workspace/harbor/node_modules",
798
- void 0,
799
- { state: "dismissed" }
800
- ]
801
- ];
802
- var attachmentsMessage = {
803
- id: "k-u2",
804
- role: "user",
805
- text: "Here is the mockup, my notes and the old spec.",
806
- createdAt: at(4),
807
- attachments: [
808
- {
809
- id: "k-a1",
810
- name: "forecast-card.png",
811
- kind: "image",
812
- mimeType: "image/png",
813
- size: 48211,
814
- url: picture("Mockup", "#f5a623", "#d0021b", 480, 320)
815
- },
816
- {
817
- id: "k-a2",
818
- name: "notes.txt",
819
- kind: "text",
820
- mimeType: "text/plain",
821
- size: 214,
822
- text: "Show \xB0C first.\nRound to whole degrees.\nKeep the summary under 60 characters."
823
- },
824
- {
825
- id: "k-a3",
826
- name: "spec-v1.pdf",
827
- kind: "file",
828
- mimeType: "application/pdf",
829
- size: 1204331,
830
- path: "/home/user/downloads/spec-v1.pdf"
831
- },
832
- {
833
- id: "k-a4",
834
- name: "UPSTREAM_TOKEN",
835
- kind: "secret",
836
- mimeType: "application/octet-stream",
837
- size: 0
838
- },
839
- {
840
- id: "k-a5",
841
- name: "recording.mov",
842
- kind: "file",
843
- mimeType: "video/quicktime",
844
- size: 98304e3,
845
- error: "Too large: attachments are limited to 25 MB"
846
- }
847
- ]
848
- };
849
- var showcaseAgent = {
850
- id: "cone-kitchen",
851
- name: "kitchen-sink",
852
- kind: "cone",
853
- parentId: null,
854
- status: "idle",
855
- model: "claude-opus-5-5",
856
- contextFill: 0.47,
857
- unread: 0
858
- };
859
- function opening() {
860
- return [
861
- {
862
- id: "k-u1",
863
- role: "user",
864
- text: "Give me the full tour of harbor, everything you can show.",
865
- createdAt: at(0)
866
- },
867
- {
868
- id: "k-m1",
869
- role: "assistant",
870
- status: "done",
871
- createdAt: at(1),
872
- model: "claude-sonnet-5-5",
873
- usage: { input: 18204, output: 912, cost: 0.31 },
874
- parts: [
875
- {
876
- type: "thinking",
877
- text: "Start with the shape of the API, then show the pieces one kind at a time."
878
- },
879
- { type: "text", text: markdown }
880
- ]
881
- },
882
- attachmentsMessage,
883
- {
884
- id: "k-m2",
885
- role: "assistant",
886
- status: "done",
887
- createdAt: at(5),
888
- model: "claude-sonnet-5-5",
889
- parts: [
890
- {
891
- type: "text",
892
- text: "Mockup, notes and spec received. The recording was too large to attach. Here are the current screens and the alert sound:"
893
- },
894
- {
895
- type: "media",
896
- items: [
897
- {
898
- kind: "image",
899
- src: picture("Forecast card", "#3b63fb", "#7a5af8"),
900
- alt: "The forecast card in light mode"
901
- },
902
- {
903
- kind: "image",
904
- src: picture("Dark card", "#1d1d1d", "#3b63fb"),
905
- alt: "The forecast card in dark mode"
906
- },
907
- {
908
- kind: "image",
909
- src: picture("Phone", "#0a7a43", "#12b886", 360, 640),
910
- alt: "The forecast card on a phone"
911
- },
912
- {
913
- kind: "video",
914
- src: "",
915
- poster: picture("\u25B6 Walkthrough", "#292929", "#717171"),
916
- alt: "A walkthrough of the forecast page"
917
- },
918
- { kind: "audio", src: tone(), alt: "The storm alert sound" }
919
- ]
920
- }
921
- ]
922
- },
923
- { id: "k-u3", role: "user", text: "Show me every tool you used.", createdAt: at(8) },
924
- {
925
- id: "k-m3",
926
- role: "assistant",
927
- status: "done",
928
- createdAt: at(9),
929
- model: "claude-sonnet-5-5",
930
- parts: [
931
- { type: "text", text: "Every tool from today\u2019s run, in order:" },
932
- ...toolShapes.map((call) => ({ type: "tool", tool: call }))
933
- ]
934
- },
935
- {
936
- id: "k-tool1",
937
- role: "tool",
938
- createdAt: at(12),
939
- tool: tool(
940
- "k-t15",
941
- "bash",
942
- "You ran a command",
943
- "git log --oneline -3",
944
- "a1b2c3d fix: expire entries from the previous day\ne4f5a6b feat: retry upstream timeouts\n0c9d8e7 chore: update wrangler"
945
- )
946
- }
947
- ];
948
- }
949
- function runs() {
950
- return [
951
- {
952
- id: "k-u6",
953
- role: "user",
954
- text: "Get the forecast docs ready for the Celsius release.",
955
- createdAt: at(13)
956
- },
957
- {
958
- id: "k-m8",
959
- role: "assistant",
960
- status: "done",
961
- createdAt: at(13.1),
962
- model: "claude-sonnet-5-5",
963
- parts: [
964
- { type: "text", text: "Checking what the docs and the API say today." },
965
- ...[
966
- tool(
967
- "k-r1",
968
- "bash",
969
- "Ask the API for Lisbon",
970
- "curl -s https://api.example.com/v2/forecast?city=Lisbon",
971
- '{ "city": "Lisbon", "high": 71, "low": 58, "unit": "F" }'
972
- ),
973
- tool(
974
- "k-r2",
975
- "bash",
976
- "Read the forecast page",
977
- "cat /workspace/harbor/docs/forecast.md",
978
- "# Forecast\n\nTemperatures are in Fahrenheit."
979
- ),
980
- tool("k-r3", "bash", "See what changed", "git status --short", " M src/lib/units.ts"),
981
- tool(
982
- "k-r4",
983
- "read_file",
984
- "Read the units helper",
985
- "/workspace/harbor/src/lib/units.ts",
986
- "export function toCelsius(f: number): number {\u2026}",
987
- { paths: ["/workspace/harbor/src/lib/units.ts"] }
988
- )
989
- ].map((call) => ({ type: "tool", tool: call })),
990
- {
991
- type: "text",
992
- text: "The page still says Fahrenheit. Updating it, then building and testing."
993
- },
994
- ...[
995
- tool(
996
- "k-r5",
997
- "edit_file",
998
- "Switch the page to Celsius",
999
- "/workspace/harbor/docs/forecast.md",
1000
- "Edited 1 line",
1001
- {
1002
- paths: ["/workspace/harbor/docs/forecast.md"],
1003
- diff: {
1004
- before: "# Forecast\n\nTemperatures are in Fahrenheit.\n",
1005
- after: "# Forecast\n\nTemperatures are in Celsius.\n"
1006
- }
1007
- }
1008
- ),
1009
- tool("k-r6", "bash", "Build the site", "npm run build", "Built 14 pages in 2.1s", {
1010
- meta: "timeout 120s"
1011
- }),
1012
- tool(
1013
- "k-r7",
1014
- "bash",
1015
- "Run the unit tests",
1016
- "npx vitest run src/lib/units.test.ts",
1017
- "FAIL src/lib/units.test.ts > rounds half to even\nExpected 22, received 21",
1018
- {
1019
- status: "error",
1020
- notes: [{ severity: "error", text: "Exited with code 1" }]
1021
- }
1022
- ),
1023
- tool(
1024
- "k-r8",
1025
- "bash",
1026
- "Open the release pull request",
1027
- 'gh pr create --repo https://git.example.com/example/harbor --title "Celsius docs"',
1028
- "Stopped before the tests pass",
1029
- { status: "cancelled" }
1030
- ),
1031
- tool("k-r9", "bash", "Watch the preview logs", "wrangler tail --env preview", "", {
1032
- status: "running"
1033
- })
1034
- ].map((call) => ({ type: "tool", tool: call })),
1035
- {
1036
- type: "text",
1037
- text: "One test fails on rounding, so the pull request waits for the fix."
1038
- }
1039
- ]
1040
- },
1041
- {
1042
- id: "k-tool2",
1043
- role: "tool",
1044
- createdAt: at(13.5),
1045
- tool: tool(
1046
- "k-r10",
1047
- "bash",
1048
- "Check the preview port",
1049
- "lsof -i :8787",
1050
- "workerd 4120 harbor 12u IPv4 TCP localhost:8787 (LISTEN)"
1051
- )
1052
- }
1053
- ];
1054
- }
1055
- function work() {
1056
- return [
1057
- {
1058
- id: "k-m4",
1059
- role: "assistant",
1060
- status: "done",
1061
- createdAt: at(14),
1062
- model: "claude-sonnet-5-5",
1063
- parts: [
1064
- { type: "text", text: "Here is where things stand." },
1065
- { type: "sprinkle", sprinkle: "status" },
1066
- {
1067
- type: "delegation",
1068
- kind: "scoop",
1069
- scoop: "docs-pass",
1070
- text: "Started a scoop to update the docs"
1071
- },
1072
- {
1073
- type: "delegation",
1074
- kind: "feed",
1075
- scoop: "docs-pass",
1076
- text: "Handed over the new screenshots"
1077
- },
1078
- {
1079
- type: "delegation",
1080
- kind: "sprinkle",
1081
- scoop: "suggestions",
1082
- text: "Opened the suggestions sprinkle"
1083
- },
1084
- { type: "delegation", kind: "drop", scoop: "amber-heron", text: "Wrapped up amber-heron" }
1085
- ]
1086
- },
1087
- {
1088
- id: "k-m5",
1089
- role: "assistant",
1090
- status: "done",
1091
- createdAt: at(18),
1092
- model: "claude-sonnet-5-5",
1093
- parts: [
1094
- { type: "text", text: "Three decisions from earlier:" },
1095
- {
1096
- type: "question",
1097
- question: {
1098
- id: "k-q1",
1099
- kind: "yes-no",
1100
- question: "Tag 1.9.0 after the merge?",
1101
- options: [],
1102
- state: "answered",
1103
- answer: "Yes"
1104
- }
1105
- },
1106
- {
1107
- type: "question",
1108
- question: {
1109
- id: "k-q2",
1110
- kind: "text",
1111
- question: "What should the release be called?",
1112
- options: [],
1113
- state: "inert"
1114
- }
1115
- },
1116
- {
1117
- type: "question",
1118
- question: {
1119
- id: "k-q3",
1120
- kind: "choice",
1121
- question: "Where should the cache live?",
1122
- options: ["Keep it in memory", "Move it to KV", "Decide after the load test"],
1123
- state: "open"
1124
- }
1125
- }
1126
- ]
1127
- }
1128
- ];
1129
- }
1130
- function events() {
1131
- return [
1132
- {
1133
- id: "k-s1",
1134
- role: "system",
1135
- kind: "compaction",
1136
- title: "Context compacted",
1137
- text: "58 earlier messages were summarized.",
1138
- trigger: "threshold",
1139
- state: "summarized",
1140
- createdAt: at(1440)
1141
- },
1142
- {
1143
- id: "k-s2",
1144
- role: "system",
1145
- kind: "compaction",
1146
- title: "Compaction failed, transcript truncated",
1147
- text: "The summary failed, so the oldest 20 messages were dropped instead.",
1148
- trigger: "overflow",
1149
- state: "fallback",
1150
- createdAt: at(1441)
1151
- },
1152
- ...licks.map(
1153
- ([channel, title, text, body, extra], index2) => ({
1154
- id: `k-l${index2 + 1}`,
1155
- role: "lick",
1156
- channel,
1157
- title,
1158
- text,
1159
- createdAt: at(1445 + index2),
1160
- ...body ? { body } : {},
1161
- ...extra
1162
- })
1163
- ),
1164
- {
1165
- id: "k-u4",
1166
- role: "user",
1167
- text: "Actually, stop the deploy, staging is frozen today.",
1168
- mode: "steer",
1169
- createdAt: at(1470)
1170
- },
1171
- {
1172
- id: "k-m6",
1173
- role: "assistant",
1174
- status: "stopped",
1175
- createdAt: at(1470),
1176
- model: "claude-haiku-4-5",
1177
- parts: [{ type: "text", text: "Stopping the staging deploy and leaving" }]
1178
- },
1179
- {
1180
- id: "k-u5",
1181
- role: "user",
1182
- text: "Update the forecast page to Celsius and use the new screenshots.",
1183
- from: "harbor",
1184
- createdAt: at(1472)
1185
- },
1186
- {
1187
- id: "k-m7",
1188
- role: "assistant",
1189
- status: "error",
1190
- createdAt: at(1475),
1191
- model: "claude-haiku-4-5",
1192
- parts: [
1193
- {
1194
- type: "thinking",
1195
- text: "The model rejected the request because the context is too large."
1196
- },
1197
- {
1198
- type: "error",
1199
- message: "The request is too large for this model.",
1200
- detail: "The model returned 413: the request is larger than its context window.",
1201
- action: "change-model"
1202
- }
1203
- ]
1204
- },
1205
- {
1206
- id: "k-s3",
1207
- role: "system",
1208
- kind: "error",
1209
- title: "docs-pass failed",
1210
- text: "The Adobe session expired. Log in again to continue.",
1211
- action: "login",
1212
- account: "ai-adobe",
1213
- createdAt: at(1476)
1214
- },
1215
- {
1216
- id: "k-s4",
1217
- role: "system",
1218
- kind: "error",
1219
- title: "Rate limited",
1220
- text: "Anthropic answered 429. Retrying in 30 seconds.",
1221
- action: "retry",
1222
- createdAt: at(1477)
1223
- },
1224
- {
1225
- id: "k-s5",
1226
- role: "system",
1227
- kind: "notice",
1228
- title: "Model changed",
1229
- text: "to Claude Opus 5.5 (Anthropic)",
1230
- createdAt: at(1478)
1231
- }
1232
- ];
1233
- }
1234
- function showcase() {
1235
- return [...opening(), ...runs(), ...work(), ...events()];
1236
- }
1237
- function showcaseQueue() {
1238
- return [
1239
- {
1240
- id: "k-q-1",
1241
- role: "user",
1242
- text: "Then open a pull request for the docs.",
1243
- createdAt: at(1480),
1244
- queued: true,
1245
- mode: "queue"
1246
- },
1247
- {
1248
- id: "k-q-2",
1249
- role: "user",
1250
- text: "And post the link in the release channel.",
1251
- createdAt: at(1481),
1252
- queued: true,
1253
- mode: "queue"
1254
- }
1255
- ];
1256
- }
1257
-
1258
- // src/dummy/fixtures.ts
1259
- var cacheBefore = `export interface Entry<T> {
1260
- value: T;
1261
- storedAt: number;
1262
- }
1263
-
1264
- const TTL = 60 * 60 * 1000;
1265
-
1266
- export class ForecastCache<T> {
1267
- #entries = new Map<string, Entry<T>>();
1268
-
1269
- get(key: string, now = Date.now()): T | undefined {
1270
- const entry = this.#entries.get(key);
1271
- if (!entry) return undefined;
1272
- const day = new Date(entry.storedAt).getDate();
1273
- if (day !== new Date(now).getDate()) return entry.value;
1274
- if (now - entry.storedAt > TTL) return undefined;
1275
- return entry.value;
1276
- }
1277
-
1278
- set(key: string, value: T, now = Date.now()): void {
1279
- this.#entries.set(key, { value, storedAt: now });
1280
- }
1281
- }
1282
- `;
1283
- var cacheAfter = `export interface Entry<T> {
1284
- value: T;
1285
- storedAt: number;
1286
- }
1287
-
1288
- const TTL = 60 * 60 * 1000;
1289
-
1290
- export class ForecastCache<T> {
1291
- #entries = new Map<string, Entry<T>>();
1292
-
1293
- get(key: string, now = Date.now()): T | undefined {
1294
- const entry = this.#entries.get(key);
1295
- if (!entry) return undefined;
1296
- if (dayOf(entry.storedAt) !== dayOf(now)) {
1297
- this.#entries.delete(key);
1298
- return undefined;
1299
- }
1300
- if (now - entry.storedAt > TTL) return undefined;
1301
- return entry.value;
1302
- }
1303
-
1304
- set(key: string, value: T, now = Date.now()): void {
1305
- this.#entries.set(key, { value, storedAt: now });
1306
- }
1307
- }
1308
-
1309
- function dayOf(time: number): string {
1310
- return new Date(time).toISOString().slice(0, 10);
1311
- }
1312
- `;
1313
- var retry = `export async function retry<T>(task: () => Promise<T>, attempts = 3, wait = 250): Promise<T> {
1314
- let last: unknown;
1315
- for (let attempt = 0; attempt < attempts; attempt++) {
1316
- try {
1317
- return await task();
1318
- } catch (error) {
1319
- last = error;
1320
- await new Promise((resolve) => setTimeout(resolve, wait * 2 ** attempt));
1321
- }
1322
- }
1323
- throw last;
1324
- }
1325
- `;
1326
- var legacyXml = `export function toXml(forecast: { city: string; high: number; low: number }): string {
1327
- return \`<forecast city="\${forecast.city}"><high>\${forecast.high}</high><low>\${forecast.low}</low></forecast>\`;
1328
- }
1329
- `;
1330
- var forecastBefore = `import { ForecastCache } from '../lib/cache.ts';
1331
- import { toCelsius } from '../lib/units.ts';
1332
-
1333
- const cache = new ForecastCache<Forecast>();
1334
-
1335
- export interface Forecast {
1336
- city: string;
1337
- high: number;
1338
- low: number;
1339
- summary: string;
1340
- }
1341
-
1342
- export async function forecast(city: string, upstream: typeof fetch = fetch): Promise<Forecast> {
1343
- const cached = cache.get(city);
1344
- if (cached) return cached;
1345
- const response = await upstream(\`https://api.example.com/v2/forecast?city=\${encodeURIComponent(city)}\`);
1346
- const body = await response.json();
1347
- const result = {
1348
- city,
1349
- high: toCelsius(body.daily.max),
1350
- low: toCelsius(body.daily.min),
1351
- summary: body.daily.summary,
1352
- };
1353
- cache.set(city, result);
1354
- return result;
1355
- }
1356
- `;
1357
- var forecastAfter = forecastBefore.replace(
1358
- "import { toCelsius } from '../lib/units.ts';",
1359
- "import { retry } from '../lib/retry.ts';\nimport { toCelsius } from '../lib/units.ts';"
1360
- ).replace("const response = await upstream(", "const response = await retry(() =>\n upstream(").replace("(city)}`);", "(city)}`)\n );");
1361
- var units = `export function toCelsius(fahrenheit: number): number {
1362
- return Math.round(((fahrenheit - 32) * 5) / 9);
1363
- }
1364
-
1365
- export function toFahrenheit(celsius: number): number {
1366
- return Math.round((celsius * 9) / 5 + 32);
1367
- }
1368
- `;
1369
- var unitsTest = `import assert from 'node:assert/strict';
1370
- import { test } from 'node:test';
1371
- import { toCelsius, toFahrenheit } from '../src/lib/units.ts';
1372
-
1373
- test('converts both ways', () => {
1374
- assert.equal(toCelsius(212), 100);
1375
- assert.equal(toFahrenheit(0), 32);
1376
- });
1377
- `;
1378
- var index = `import { forecast } from './routes/forecast.ts';
1379
-
1380
- export default {
1381
- async fetch(request: Request): Promise<Response> {
1382
- const url = new URL(request.url);
1383
- if (url.pathname === '/health') return new Response('ok');
1384
- const city = url.searchParams.get('city');
1385
- if (!city) return Response.json({ error: 'city is required' }, { status: 400 });
1386
- return Response.json(await forecast(city));
1387
- },
1388
- };
1389
- `;
1390
- var readme = `# harbor
1391
-
1392
- A small forecast API that sits in front of the upstream weather service and caches per city.
1393
-
1394
- ## Development
1395
-
1396
- \`\`\`sh
1397
- npm install
1398
- npm test
1399
- npm run dev
1400
- \`\`\`
1401
-
1402
- The worker listens on \`http://localhost:8787\`. Try \`/forecast?city=Lisbon\`.
1403
- `;
1404
- var pkg = `{
1405
- "name": "harbor",
1406
- "private": true,
1407
- "type": "module",
1408
- "scripts": {
1409
- "dev": "wrangler dev",
1410
- "test": "node --test test/"
1411
- },
1412
- "devDependencies": {
1413
- "wrangler": "4.40.0"
1414
- }
1415
- }
1416
- `;
1417
- var skill = `---
1418
- name: release-notes
1419
- description: Draft release notes from merged pull requests since the last tag.
1420
- ---
1421
-
1422
- 1. Run \`collect.jsh\` with the repository and the previous tag.
1423
- 2. Group the pull requests by label: features, fixes, chores.
1424
- 3. Write one sentence per change, in the past tense, without ticket numbers.
1425
- `;
1426
- var collect = `const [repo, since] = process.argv.slice(2);
1427
- const pulls = await gh(\`repos/\${repo}/pulls?state=closed&per_page=100\`);
1428
- for (const pull of pulls.filter((p) => p.merged_at > since)) {
1429
- console.log(\`\${pull.number}\\t\${pull.labels.map((l) => l.name).join(',')}\\t\${pull.title}\`);
1430
- }
1431
- `;
1432
- var memory = `# Shared memory
1433
-
1434
- ## Preferences
1435
- - Keep replies short. Lead with the result, then the evidence.
1436
- - Run the tests before saying something is fixed.
1437
-
1438
- ## Projects
1439
- - harbor: forecast API, deployed as a worker. Cache bugs show up around midnight UTC.
1440
- - release-notes: drafted every Friday from merged pull requests.
1441
- `;
1442
- var standup = `# Standup, 4 October
1443
-
1444
- - harbor: retries for upstream timeouts are in review.
1445
- - Docs: the forecast endpoint page still shows Fahrenheit examples.
1446
- - Next: move the cache to KV once the TTL fix lands.
1447
- `;
1448
- var sample = `{
1449
- "city": "Lisbon",
1450
- "daily": { "max": 77, "min": 61, "summary": "Clear, light wind from the north" }
1451
- }
1452
- `;
1453
- var bashrc = `export PS1='\\u@slicc:\\w\\$ '
1454
- alias ll='ls -la'
1455
- `;
1456
- var suggestions = `${JSON.stringify(
1457
- [
1458
- {
1459
- id: "sug-units",
1460
- kind: "skill",
1461
- title: "Unit conversions",
1462
- body: "You converted Fahrenheit to Celsius by hand in three chats this week. A skill can do it for you.",
1463
- skill: "unit-converter",
1464
- install: "unit-converter from raw.githubusercontent.com/example/skills/main/unit-converter/SKILL.md"
1465
- },
1466
- {
1467
- id: "sug-notes",
1468
- kind: "use-case",
1469
- title: "Release notes from the week",
1470
- body: "You write release notes for harbor every Friday. Let the cone draft them from the commits.",
1471
- prompt: "Draft release notes for harbor from the commits since last Friday."
1472
- },
1473
- {
1474
- id: "sug-cache",
1475
- kind: "tip",
1476
- title: "Name your cache keys",
1477
- body: "Forecast cache keys mix the city and the units. Splitting them makes stale entries easier to find."
1478
- }
1479
- ],
1480
- null,
1481
- 2
1482
- )}
1483
- `;
1484
- var files = {
1485
- "/workspace/harbor/README.md": readme,
1486
- "/workspace/harbor/package.json": pkg,
1487
- "/workspace/harbor/wrangler.toml": 'name = "harbor"\nmain = "src/index.ts"\ncompatibility_date = "2026-09-01"\n',
1488
- "/workspace/harbor/.gitignore": "node_modules/\n.wrangler/\n",
1489
- "/workspace/harbor/src/index.ts": index,
1490
- "/workspace/harbor/src/routes/forecast.ts": forecastBefore,
1491
- "/workspace/harbor/src/lib/cache.ts": cacheBefore,
1492
- "/workspace/harbor/src/lib/units.ts": units,
1493
- "/workspace/harbor/src/legacy/xml.ts": legacyXml,
1494
- "/workspace/harbor/static/radar.png": "\x89PNG\r\n\n",
1495
- "/workspace/harbor/test/units.test.ts": unitsTest,
1496
- "/workspace/skills/release-notes/SKILL.md": skill,
1497
- "/workspace/skills/release-notes/scripts/collect.jsh": collect,
1498
- "/shared/MEMORY.md": memory,
1499
- "/shared/notes/2026-10-04-standup.md": standup,
1500
- "/home/user/.bashrc": bashrc,
1501
- "/home/.gelatiere/suggestions.json": suggestions,
1502
- "/tmp/forecast-sample.json": sample
1503
- };
1504
- var directories = ["/sessions", "/home/user/downloads"];
1505
- var mountPoint = "/mnt/photos";
1506
- var mounted = {
1507
- "README.md": "# Photos\n\nHarbor shots for the forecast pages, one album per season.\n",
1508
- "albums/autumn.json": '{ "title": "Autumn", "shots": ["breakwater-fog", "pier-at-dusk"] }\n',
1509
- "albums/winter.json": '{ "title": "Winter", "shots": ["ice-on-the-buoys"] }\n',
1510
- "captions.txt": "breakwater-fog: low cloud over the outer wall\npier-at-dusk: lamps on, tide out\n"
1511
- };
1512
- var pending = [
1513
- {
1514
- path: "/workspace/harbor/src/lib/cache.ts",
1515
- status: "modified",
1516
- before: cacheBefore,
1517
- after: cacheAfter,
1518
- agentId: "cone-harbor"
1519
- },
1520
- {
1521
- path: "/workspace/harbor/src/lib/retry.ts",
1522
- status: "added",
1523
- before: null,
1524
- after: retry,
1525
- agentId: "scoop-otter"
1526
- },
1527
- {
1528
- path: "/workspace/harbor/src/routes/forecast.ts",
1529
- status: "modified",
1530
- before: forecastBefore,
1531
- after: forecastAfter,
1532
- agentId: "scoop-otter"
1533
- },
1534
- {
1535
- path: "/workspace/harbor/src/legacy/xml.ts",
1536
- status: "deleted",
1537
- before: legacyXml,
1538
- after: null,
1539
- agentId: "cone-harbor"
1540
- },
1541
- {
1542
- path: "/workspace/harbor/static/radar.png",
1543
- status: "modified",
1544
- before: null,
1545
- after: null,
1546
- agentId: "scoop-otter"
1547
- }
1548
- ];
1549
- var skillEdit = {
1550
- path: "/workspace/skills/release-notes/SKILL.md",
1551
- status: "modified",
1552
- before: skill,
1553
- after: `${skill}4. Link each change to its pull request.
1554
- `,
1555
- agentId: null
1556
- };
1557
- var models = [
1558
- { id: "claude-opus-5-5", label: "Claude Opus 5.5", provider: "Anthropic", images: true },
1559
- { id: "claude-sonnet-5-5", label: "Claude Sonnet 5.5", provider: "Anthropic", images: true },
1560
- { id: "claude-haiku-4-5", label: "Claude Haiku 4.5", provider: "Anthropic", images: true },
1561
- { id: "local-small", label: "Local (ort-llama)", provider: "This browser", images: false },
1562
- { id: "local-guard", label: "Local guard", provider: "This browser", kind: "classifier" },
1563
- { id: "local-tiny", label: "Local tiny (no tools)", provider: "This browser", tools: false }
1564
- ];
1565
- var laterModels = [
1566
- { id: "gpt-6", label: "GPT-6", provider: "OpenAI", images: true },
1567
- { id: "gpt-6-mini", label: "GPT-6 mini", provider: "OpenAI", images: true, default: true }
1568
- ];
1569
- var defaults = {
1570
- color: "system",
1571
- model: "claude-sonnet-5-5",
1572
- thinking: "medium",
1573
- sendOnEnter: true,
1574
- pushToTalk: false,
1575
- showThinking: true,
1576
- diffStyle: "unified"
1577
- };
1578
- var accounts = [
1579
- { id: "anthropic", provider: "Anthropic", identity: "API key ending 3f2a", status: "connected" },
1580
- { id: "github", provider: "GitHub", identity: "@example-dev", status: "connected" },
1581
- { id: "adobe", provider: "Adobe", identity: "dev@example.com", status: "expired" },
1582
- {
1583
- id: "ai-adobe",
1584
- provider: "Adobe AI",
1585
- identity: "harbor-ops@example.com",
1586
- status: "expired",
1587
- auth: "oauth"
1588
- },
1589
- { id: "openai", provider: "OpenAI", identity: "", status: "disconnected", auth: "api-key" },
1590
- {
1591
- id: "mcp:docs",
1592
- provider: "docs",
1593
- identity: "docs.example",
1594
- status: "connected",
1595
- auth: "api-key",
1596
- group: "mcp",
1597
- secret: "token"
1598
- },
1599
- {
1600
- id: "mcp:tickets",
1601
- provider: "tickets",
1602
- identity: "tickets.example",
1603
- status: "expired",
1604
- auth: "api-key",
1605
- group: "mcp",
1606
- secret: "token"
1607
- },
1608
- {
1609
- id: "mcp:design",
1610
- provider: "design",
1611
- identity: "design.example",
1612
- status: "disconnected",
1613
- auth: "oauth",
1614
- group: "mcp"
1615
- }
1616
- ];
1617
- var agents = [
1618
- {
1619
- id: "cone-sliccy",
1620
- name: "sliccy",
1621
- kind: "cone",
1622
- parentId: null,
1623
- status: "idle",
1624
- model: "claude-sonnet-5-5",
1625
- contextFill: 0.21,
1626
- unread: 0
1627
- },
1628
- showcaseAgent,
1629
- {
1630
- id: "cone-harbor",
1631
- name: "harbor",
1632
- kind: "cone",
1633
- parentId: null,
1634
- status: "idle",
1635
- model: "claude-opus-5-5",
1636
- contextFill: 0.38,
1637
- unread: 0
1638
- },
1639
- {
1640
- id: "scoop-otter",
1641
- name: "quiet-otter",
1642
- kind: "scoop",
1643
- parentId: "cone-harbor",
1644
- status: "working",
1645
- model: "claude-haiku-4-5",
1646
- contextFill: 0.12,
1647
- unread: 0
1648
- },
1649
- {
1650
- id: "scoop-heron",
1651
- name: "amber-heron",
1652
- kind: "scoop",
1653
- parentId: "cone-harbor",
1654
- status: "idle",
1655
- model: "claude-haiku-4-5",
1656
- contextFill: 0.04,
1657
- unread: 0
1658
- },
1659
- {
1660
- id: "cone-release",
1661
- name: "release-notes",
1662
- kind: "cone",
1663
- parentId: null,
1664
- status: "idle",
1665
- model: "claude-sonnet-5-5",
1666
- contextFill: 0.7,
1667
- unread: 1
1668
- },
1669
- {
1670
- id: "cone-triage",
1671
- name: "inbox-triage",
1672
- kind: "cone",
1673
- parentId: null,
1674
- status: "waiting",
1675
- model: "claude-sonnet-5-5",
1676
- contextFill: 0.95,
1677
- unread: 2
1678
- },
1679
- {
1680
- id: "scoop-wren",
1681
- name: "tidal-wren",
1682
- kind: "scoop",
1683
- parentId: "cone-sliccy",
1684
- status: "idle",
1685
- model: "claude-haiku-4-5",
1686
- contextFill: 0.02,
1687
- unread: 0
1688
- },
1689
- {
1690
- id: "cone-tides",
1691
- name: "tide-tables",
1692
- kind: "cone",
1693
- parentId: null,
1694
- status: "idle",
1695
- model: "claude-sonnet-5-5",
1696
- contextFill: 0.31,
1697
- unread: 0,
1698
- frozen: true
1699
- }
1700
- ];
1701
- var start2 = Date.UTC(2026, 9, 5, 8, 30);
1702
- var at2 = (minutes2) => start2 + minutes2 * 6e4;
1703
- var queues = { "cone-kitchen": showcaseQueue() };
1704
- var conversations = {
1705
- "cone-kitchen": showcase(),
1706
- "cone-sliccy": [
1707
- {
1708
- id: "m-s0",
1709
- role: "assistant",
1710
- status: "done",
1711
- createdAt: at2(-24 * 60),
1712
- parts: [
1713
- {
1714
- type: "text",
1715
- text: "Hi, I am sliccy. Tell me a little about yourself, and I will set things up for you."
1716
- },
1717
- { type: "sprinkle", sprinkle: "welcome" }
1718
- ]
1719
- },
1720
- {
1721
- id: "m-s1",
1722
- role: "user",
1723
- text: "What is on my plate today?",
1724
- createdAt: at2(0)
1725
- },
1726
- {
1727
- id: "m-s2",
1728
- role: "assistant",
1729
- status: "done",
1730
- createdAt: at2(1),
1731
- parts: [
1732
- {
1733
- type: "tool",
1734
- tool: {
1735
- id: "t-s1",
1736
- name: "read_file",
1737
- title: "Read the standup notes",
1738
- input: "/shared/notes/2026-10-04-standup.md",
1739
- output: standup,
1740
- status: "done",
1741
- paths: ["/shared/notes/2026-10-04-standup.md"]
1742
- }
1743
- },
1744
- {
1745
- type: "text",
1746
- text: "Three things carry over from yesterday:\n\n1. **harbor**: the retry change is in review, and the midnight cache bug is still open.\n2. **Docs**: the forecast page still shows Fahrenheit examples.\n3. **release-notes** has a draft waiting for you.\n\nThe `harbor` cone is the one to start with."
1747
- }
1748
- ]
1749
- }
1750
- ],
1751
- "cone-harbor": [
1752
- {
1753
- id: "m-h1",
1754
- role: "lick",
1755
- channel: "webhook",
1756
- title: "GitHub \xB7 issue opened",
1757
- text: "example/harbor#57: Forecast stays on yesterday after midnight UTC",
1758
- createdAt: at2(2)
1759
- },
1760
- {
1761
- id: "m-h2",
1762
- role: "user",
1763
- text: "The forecast endpoint serves stale data after midnight UTC. Find out why and fix it.",
1764
- createdAt: at2(3)
1765
- },
1766
- {
1767
- id: "m-h3",
1768
- role: "assistant",
1769
- status: "done",
1770
- createdAt: at2(4),
1771
- parts: [
1772
- {
1773
- type: "thinking",
1774
- text: "Stale after midnight points at the cache expiry. Check how the cache compares days."
1775
- },
1776
- {
1777
- type: "tool",
1778
- tool: {
1779
- id: "t-h1",
1780
- name: "bash",
1781
- title: "Search for the cache expiry",
1782
- input: 'rg -n "getDate|TTL" src',
1783
- output: "src/lib/cache.ts:6:const TTL = 60 * 60 * 1000;\nsrc/lib/cache.ts:14: const day = new Date(entry.storedAt).getDate();\nsrc/lib/cache.ts:16: if (now - entry.storedAt > TTL) return undefined;",
1784
- status: "done",
1785
- paths: ["/workspace/harbor/src/lib/cache.ts"]
1786
- }
1787
- },
1788
- {
1789
- type: "tool",
1790
- tool: {
1791
- id: "t-h2",
1792
- name: "read_file",
1793
- title: "Read the cache",
1794
- input: "/workspace/harbor/src/lib/cache.ts",
1795
- output: cacheBefore,
1796
- status: "done",
1797
- paths: ["/workspace/harbor/src/lib/cache.ts"]
1798
- }
1799
- },
1800
- {
1801
- type: "tool",
1802
- tool: {
1803
- id: "t-h3",
1804
- name: "edit_file",
1805
- title: "Expire entries from the previous day",
1806
- input: "/workspace/harbor/src/lib/cache.ts",
1807
- output: "Replaced 1 block (4 lines \u2192 7 lines), added dayOf()",
1808
- status: "done",
1809
- paths: ["/workspace/harbor/src/lib/cache.ts"],
1810
- diff: { before: cacheBefore, after: cacheAfter }
1811
- }
1812
- },
1813
- {
1814
- type: "tool",
1815
- tool: {
1816
- id: "t-h4",
1817
- name: "bash",
1818
- title: "Run the tests",
1819
- input: "npm test",
1820
- meta: "timeout 120s",
1821
- output: "> harbor@0.0.0 test\n> node --test test/\n\n\u2714 converts both ways (0.6ms)\n\u2714 expires entries from the previous day (0.4ms)\n\u2139 tests 2\n\u2139 pass 2\n\u2139 fail 0",
1822
- status: "done",
1823
- paths: []
1824
- }
1825
- },
1826
- {
1827
- type: "text",
1828
- text: "Found it. `ForecastCache.get` compared **local** calendar days, and when the day changed it returned the old entry instead of dropping it:\n\n```ts\nif (day !== new Date(now).getDate()) return entry.value;\n```\n\nI changed it to compare UTC dates and delete the entry, so the first request after midnight goes upstream. The tests pass.\n\n| | Before | After |\n| --- | --- | --- |\n| Day compared | local `getDate()` | UTC `toISOString()` |\n| On a new day | returns stale entry | deletes and refetches |\n\nquiet-otter is adding retries for upstream timeouts in a scoop."
1829
- },
1830
- {
1831
- type: "delegation",
1832
- kind: "scoop",
1833
- scoop: "quiet-otter",
1834
- text: "Started a scoop to add retries around the upstream fetch"
1835
- }
1836
- ]
1837
- },
1838
- {
1839
- id: "m-h4",
1840
- role: "lick",
1841
- channel: "scoop-notify",
1842
- title: "quiet-otter",
1843
- text: "Started: add retries with backoff around the upstream fetch",
1844
- createdAt: at2(9)
1845
- }
1846
- ],
1847
- "scoop-otter": [
1848
- {
1849
- id: "m-o1",
1850
- role: "user",
1851
- origin: "agent",
1852
- from: "harbor",
1853
- text: "Wrap the upstream fetch in src/routes/forecast.ts with three retries and exponential backoff.",
1854
- createdAt: at2(9)
1855
- },
1856
- {
1857
- id: "m-o2",
1858
- role: "assistant",
1859
- status: "done",
1860
- createdAt: at2(10),
1861
- parts: [
1862
- {
1863
- type: "tool",
1864
- tool: {
1865
- id: "t-o1",
1866
- name: "write_file",
1867
- title: "Add retry()",
1868
- input: "/workspace/harbor/src/lib/retry.ts",
1869
- output: "Wrote 12 lines",
1870
- status: "done",
1871
- paths: ["/workspace/harbor/src/lib/retry.ts"]
1872
- }
1873
- },
1874
- {
1875
- type: "tool",
1876
- tool: {
1877
- id: "t-o2",
1878
- name: "edit_file",
1879
- title: "Use retry() for the upstream call",
1880
- input: "/workspace/harbor/src/routes/forecast.ts",
1881
- output: "Replaced 1 block",
1882
- status: "done",
1883
- paths: ["/workspace/harbor/src/routes/forecast.ts"]
1884
- }
1885
- },
1886
- { type: "text", text: "Both edits are in. Running the tests next." }
1887
- ]
1888
- }
1889
- ],
1890
- "scoop-heron": [],
1891
- "scoop-wren": [],
1892
- "cone-tides": [
1893
- {
1894
- id: "m-f1",
1895
- role: "user",
1896
- text: "Add a tide table endpoint next to the forecast, with high and low water per day.",
1897
- createdAt: at2(-2900)
1898
- },
1899
- {
1900
- id: "m-f2",
1901
- role: "assistant",
1902
- status: "done",
1903
- createdAt: at2(-2898),
1904
- parts: [
1905
- {
1906
- type: "text",
1907
- text: "Added `/v1/tides?city=` with the next seven days of high and low water. It reads from the same upstream as the forecast and shares its cache."
1908
- }
1909
- ]
1910
- }
1911
- ],
1912
- "cone-release": [
1913
- {
1914
- id: "m-r1",
1915
- role: "lick",
1916
- channel: "cron",
1917
- title: "Every Friday 09:00",
1918
- text: "Draft the release notes for example/harbor",
1919
- createdAt: at2(-1440)
1920
- },
1921
- {
1922
- id: "m-r2",
1923
- role: "assistant",
1924
- status: "done",
1925
- createdAt: at2(-1438),
1926
- parts: [
1927
- {
1928
- type: "tool",
1929
- tool: {
1930
- id: "t-r1",
1931
- name: "bash",
1932
- title: "Collect merged pull requests",
1933
- input: "collect.jsh example/harbor v1.8.0",
1934
- output: "41 fix Return 400 when the city is missing\n43 feature Add /health\n44 chore Update wrangler to 4.40.0",
1935
- status: "done",
1936
- paths: ["/workspace/skills/release-notes/scripts/collect.jsh"]
1937
- }
1938
- },
1939
- {
1940
- type: "text",
1941
- text: "## harbor 1.9.0\n\n**Features**\n- Added a `/health` endpoint.\n\n**Fixes**\n- Requests without a city now get a 400 instead of a 500.\n\n**Chores**\n- Updated wrangler to 4.40.0."
1942
- }
1943
- ]
1944
- },
1945
- {
1946
- id: "m-r3",
1947
- role: "lick",
1948
- channel: "cron",
1949
- severity: "error",
1950
- title: "Crontab",
1951
- text: "Crontab line 3 is invalid",
1952
- body: "30 25 * * * sweep-drafts\nThe hour is 25. It must be 0 to 23.",
1953
- createdAt: at2(-1430)
1954
- },
1955
- {
1956
- id: "m-r4",
1957
- role: "lick",
1958
- channel: "fswatch",
1959
- severity: "warn",
1960
- title: "/workspace/notes",
1961
- text: "File watch on /workspace/notes stopped; retrying",
1962
- createdAt: at2(-1429)
1963
- },
1964
- {
1965
- id: "m-r5",
1966
- role: "lick",
1967
- channel: "workflow",
1968
- title: "Release report",
1969
- text: "The weekly release report is ready",
1970
- body: "Summary: harbor 1.9.0 shipped three changes this week, the /health endpoint, a 400 for requests without a city and a wrangler update, with no failed deploys, no rollbacks and two flaky test runs in the forecast suite that passed on retry, so the next release can go out on Friday as planned once the docs pass lands.",
1971
- createdAt: at2(-1428)
1972
- }
1973
- ],
1974
- "cone-triage": [
1975
- {
1976
- id: "m-t1",
1977
- role: "system",
1978
- kind: "compaction",
1979
- trigger: "threshold",
1980
- state: "summarized",
1981
- title: "Context compacted",
1982
- text: "41 earlier messages were summarized to stay under the context limit.",
1983
- createdAt: at2(-30)
1984
- },
1985
- {
1986
- id: "m-t2",
1987
- role: "assistant",
1988
- status: "done",
1989
- createdAt: at2(-20),
1990
- parts: [
1991
- {
1992
- type: "text",
1993
- text: "Two messages need a decision from you:\n\n- A vendor asks to move Thursday\u2019s call to Friday.\n- The staging certificate expires in 6 days. Should I open a ticket?"
1994
- }
1995
- ]
1996
- },
1997
- {
1998
- id: "m-t3",
1999
- role: "system",
2000
- kind: "error",
2001
- action: "login",
2002
- title: "Mail connector",
2003
- text: "The connector returned 401. Reconnect the account in Settings.",
2004
- createdAt: at2(-19)
2005
- },
2006
- {
2007
- id: "m-t4",
2008
- role: "system",
2009
- kind: "error",
2010
- action: "login",
2011
- account: "mcp:tickets",
2012
- title: "Tickets connector",
2013
- text: "The tickets server rejected its token.",
2014
- createdAt: at2(-18)
2015
- }
2016
- ]
2017
- };
2018
- var tabs = [
2019
- {
2020
- id: "tab-preview",
2021
- title: "harbor \xB7 localhost",
2022
- url: "http://localhost:8787/forecast?city=Lisbon",
2023
- status: "complete",
2024
- agentId: "cone-harbor"
2025
- },
2026
- {
2027
- id: "tab-docs",
2028
- title: "Forecast API reference",
2029
- url: "https://api.example.com/docs/v2/forecast",
2030
- status: "complete",
2031
- agentId: null,
2032
- favicon: `data:image/svg+xml;charset=utf-8,${encodeURIComponent('<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><rect width="16" height="16" rx="3" fill="#7a5af8"/><text x="8" y="12" font-family="sans-serif" font-size="11" font-weight="700" fill="#ffffff" text-anchor="middle">A</text></svg>')}`
2033
- },
2034
- {
2035
- id: "tab-pull",
2036
- title: "Add retries for upstream timeouts \xB7 Pull request #58",
2037
- url: "https://git.example.com/example/harbor/pull/58",
2038
- status: "complete",
2039
- agentId: "scoop-otter",
2040
- favicon: `data:image/svg+xml;charset=utf-8,${encodeURIComponent('<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><rect width="16" height="16" rx="3" fill="#0a7a43"/><text x="8" y="12" font-family="sans-serif" font-size="11" font-weight="700" fill="#ffffff" text-anchor="middle">G</text></svg>')}`
2041
- }
2042
- ];
2043
- var terminals = [
2044
- { id: "term-1", title: "bash", cwd: "/workspace/harbor", agentId: null }
2045
- ];
2046
-
2047
534
  // src/dummy/guest.ts
2048
535
  var guestOnly = "a guest can only watch and send messages";
2049
536
  var guestReview = "Messages from guests need a review, and this agent can't review them yet.";
@@ -2075,13 +562,13 @@ var forecastSprinkle = {
2075
562
  html: "<style>body { font-family: var(--s2-font-family); color: var(--s2-content-default); padding: var(--s2-spacing-200) var(--s2-spacing-300); } table { border-collapse: collapse; } td { padding: 4px 12px 4px 0; }</style><table><tr><td>Fri</td><td>21\xB0</td><td>Sunny</td></tr><tr><td>Sat</td><td>19\xB0</td><td>Cloudy</td></tr><tr><td>Sun</td><td>18\xB0</td><td>Showers</td></tr></table><script>window.slicc.lick({ action: 'viewed', data: { rows: 3 } });<\/script>"
2076
563
  };
2077
564
  function guestTranscript(now2 = Date.now(), twin = false) {
2078
- const at3 = (minutes2) => now2 - minutes2 * minute;
565
+ const at = (minutes2) => now2 - minutes2 * minute;
2079
566
  const namesake = twin ? [
2080
567
  {
2081
568
  id: "g-9",
2082
569
  role: "user",
2083
570
  text: "Same name, another seat.",
2084
- createdAt: at3(8),
571
+ createdAt: at(8),
2085
572
  origin: "guest",
2086
573
  from: guestLabel,
2087
574
  seat: "seat-mara-2",
@@ -2093,13 +580,13 @@ function guestTranscript(now2 = Date.now(), twin = false) {
2093
580
  id: "g-1",
2094
581
  role: "user",
2095
582
  text: "Check the Porto forecast endpoint before Mara joins.",
2096
- createdAt: at3(42)
583
+ createdAt: at(42)
2097
584
  },
2098
585
  {
2099
586
  id: "g-2",
2100
587
  role: "assistant",
2101
588
  status: "done",
2102
- createdAt: at3(41),
589
+ createdAt: at(41),
2103
590
  model: "claude-sonnet-5-5",
2104
591
  parts: [
2105
592
  { type: "text", text: "I read the handler and ran its tests." },
@@ -2134,7 +621,7 @@ function guestTranscript(now2 = Date.now(), twin = false) {
2134
621
  id: "g-3",
2135
622
  role: "user",
2136
623
  text: "Hi! Could you add the weekend to the forecast table?",
2137
- createdAt: at3(30),
624
+ createdAt: at(30),
2138
625
  origin: "guest",
2139
626
  from: guestLabel,
2140
627
  seat: "seat-mara",
@@ -2144,7 +631,7 @@ function guestTranscript(now2 = Date.now(), twin = false) {
2144
631
  id: "g-4",
2145
632
  role: "assistant",
2146
633
  status: "done",
2147
- createdAt: at3(29),
634
+ createdAt: at(29),
2148
635
  model: "claude-sonnet-5-5",
2149
636
  parts: [
2150
637
  {
@@ -2166,7 +653,7 @@ function guestTranscript(now2 = Date.now(), twin = false) {
2166
653
  id: "g-5",
2167
654
  role: "user",
2168
655
  text: "Does it cover Lisbon too?",
2169
- createdAt: at3(12),
656
+ createdAt: at(12),
2170
657
  origin: "guest",
2171
658
  from: otherGuest,
2172
659
  seat: "seat-jonas",
@@ -2176,7 +663,7 @@ function guestTranscript(now2 = Date.now(), twin = false) {
2176
663
  id: "g-6",
2177
664
  role: "assistant",
2178
665
  status: "done",
2179
- createdAt: at3(11),
666
+ createdAt: at(11),
2180
667
  model: "claude-sonnet-5-5",
2181
668
  parts: [
2182
669
  { type: "text", text: "Not yet. I can add it." },
@@ -2200,7 +687,7 @@ function guestTranscript(now2 = Date.now(), twin = false) {
2200
687
  text: "wants to fetch the Lisbon forecast",
2201
688
  body: "curl -s https://api.example.com/forecast?city=lisbon",
2202
689
  state: "pending",
2203
- createdAt: at3(10),
690
+ createdAt: at(10),
2204
691
  expiresAt: now2 + 20 * minute
2205
692
  },
2206
693
  {
@@ -2210,7 +697,7 @@ function guestTranscript(now2 = Date.now(), twin = false) {
2210
697
  title: "The model is busy",
2211
698
  text: "The provider asked to slow down.",
2212
699
  action: "retry",
2213
- createdAt: at3(9)
700
+ createdAt: at(9)
2214
701
  },
2215
702
  ...namesake
2216
703
  ];
@@ -2609,14 +1096,14 @@ var importCones = [
2609
1096
  }
2610
1097
  ];
2611
1098
  var idle = { phase: "idle", done: 0, total: 0, text: "" };
2612
- function conversation(id, title, at3) {
1099
+ function conversation(id, title, at) {
2613
1100
  return [
2614
- { id: `${id}-1`, role: "user", text: title, createdAt: at3 },
1101
+ { id: `${id}-1`, role: "user", text: title, createdAt: at },
2615
1102
  {
2616
1103
  id: `${id}-2`,
2617
1104
  role: "assistant",
2618
1105
  status: "done",
2619
- createdAt: at3 + 6e4,
1106
+ createdAt: at + 6e4,
2620
1107
  parts: [
2621
1108
  { type: "text", text: "Imported from SLICC 6. The earlier turns are in the report." }
2622
1109
  ]
@@ -2702,7 +1189,7 @@ var DummyImport = class {
2702
1189
  };
2703
1190
 
2704
1191
  // src/dummy/script.ts
2705
- var units2 = "/workspace/harbor/src/lib/units.ts";
1192
+ var units = "/workspace/harbor/src/lib/units.ts";
2706
1193
  var kelvin = `
2707
1194
  export function toKelvin(celsius: number): number {
2708
1195
  return Math.round((celsius + 273.15) * 100) / 100;
@@ -2749,29 +1236,29 @@ function edit() {
2749
1236
  type: "tool",
2750
1237
  name: "read_file",
2751
1238
  title: "Read the unit helpers",
2752
- input: units2,
1239
+ input: units,
2753
1240
  output: "export function toCelsius(fahrenheit: number): number { \u2026 }\nexport function toFahrenheit(celsius: number): number { \u2026 }",
2754
- paths: [units2],
1241
+ paths: [units],
2755
1242
  ticks: 10
2756
1243
  },
2757
1244
  {
2758
1245
  type: "tool",
2759
1246
  name: "edit_file",
2760
1247
  title: "Add toKelvin()",
2761
- input: units2,
1248
+ input: units,
2762
1249
  output: "Appended 4 lines",
2763
- paths: [units2],
1250
+ paths: [units],
2764
1251
  ticks: 20,
2765
1252
  effect: async ({ files: files3, agentId }) => {
2766
- const before = await files3.read(units2);
2767
- await files3.write(units2, before + kelvin, agentId);
1253
+ const before = await files3.read(units);
1254
+ await files3.write(units, before + kelvin, agentId);
2768
1255
  }
2769
1256
  },
2770
1257
  {
2771
1258
  type: "part",
2772
1259
  part: {
2773
1260
  type: "diff",
2774
- path: units2,
1261
+ path: units,
2775
1262
  before: "export function toFahrenheit(celsius: number): number {\n return Math.round((celsius * 9) / 5 + 32);\n}\n",
2776
1263
  after: `export function toFahrenheit(celsius: number): number {
2777
1264
  return Math.round((celsius * 9) / 5 + 32);
@@ -2952,7 +1439,7 @@ function look(attachments) {
2952
1439
  }
2953
1440
  ];
2954
1441
  }
2955
- var suggestions2 = [
1442
+ var suggestions = [
2956
1443
  [/\b(debug|investigate)\b/, "Add the unit to the cache key"],
2957
1444
  [/\btests?\b/, "Open a pull request with the fix"],
2958
1445
  [/\b(fix|edit|add|change)\b/, "Run the tests"],
@@ -2961,7 +1448,7 @@ var suggestions2 = [
2961
1448
  ];
2962
1449
  function script(prompt, attachments = []) {
2963
1450
  const text = prompt.toLowerCase();
2964
- const suggestion = suggestions2.find(([pattern]) => pattern.test(text))?.[1] ?? "Run the tests";
1451
+ const suggestion = suggestions.find(([pattern]) => pattern.test(text))?.[1] ?? "Run the tests";
2965
1452
  if (attachments.length > 0) return { steps: look(attachments), suggestion };
2966
1453
  if (/\bforbidden\b/.test(text)) return { steps: filtered(), suggestion };
2967
1454
  if (/\b(ask|choose|decide)\b/.test(text)) return { steps: ask(), suggestion };
@@ -3118,7 +1605,7 @@ var DummyAgent = class extends Emitter {
3118
1605
  }
3119
1606
  async #tool(agentId, reply, step, run) {
3120
1607
  this.#status(agentId, "working");
3121
- const tool2 = {
1608
+ const tool = {
3122
1609
  id: this.#id("t"),
3123
1610
  name: step.name,
3124
1611
  title: step.title,
@@ -3127,12 +1614,12 @@ var DummyAgent = class extends Emitter {
3127
1614
  status: "running",
3128
1615
  paths: step.paths
3129
1616
  };
3130
- reply.parts.push({ type: "tool", tool: tool2 });
1617
+ reply.parts.push({ type: "tool", tool });
3131
1618
  this.emit("message", { agentId, message: reply });
3132
1619
  await this.#clock.sleep(step.ticks * run.pace);
3133
1620
  const done = run.stopped ? { status: "cancelled", output: "Stopped" } : { status: "done", output: step.output };
3134
1621
  if (!run.stopped) await step.effect?.({ ...this.#effects, agentId });
3135
- Object.assign(tool2, done);
1622
+ Object.assign(tool, done);
3136
1623
  this.emit("message", { agentId, message: reply });
3137
1624
  }
3138
1625
  async #step(agentId, reply, step, run) {
@@ -3316,9 +1803,9 @@ var DummyAgent = class extends Emitter {
3316
1803
  }
3317
1804
  async rewind(agentId, messageId) {
3318
1805
  const messages = this.#messages.get(agentId);
3319
- const at3 = messages?.findIndex((message) => message.id === messageId) ?? -1;
3320
- if (!messages || at3 < 0) return null;
3321
- const turn = messages.slice(0, at3).findLastIndex((message) => message.role === "user");
1806
+ const at = messages?.findIndex((message) => message.id === messageId) ?? -1;
1807
+ if (!messages || at < 0) return null;
1808
+ const turn = messages.slice(0, at).findLastIndex((message) => message.role === "user");
3322
1809
  if (turn < 0) return null;
3323
1810
  const user = messages[turn];
3324
1811
  const turns = messages.splice(turn).filter((message) => message.role === "user").length;
@@ -4985,17 +3472,17 @@ var DummyFiles = class extends Emitter {
4985
3472
  if (mount.scenario === "fail") throw new Error("The folder couldn\u2019t be mounted.");
4986
3473
  if (point !== void 0 && !this.#needs.has(point))
4987
3474
  throw new Error(`Nothing is waiting for a folder at ${point}.`);
4988
- const at3 = point ?? mount.point;
3475
+ const at = point ?? mount.point;
4989
3476
  const files3 = [];
4990
3477
  for (const [path, text] of Object.entries(mount.files)) {
4991
- const file = `${at3}/${path}`;
3478
+ const file = `${at}/${path}`;
4992
3479
  this.#put(file, text, Date.now());
4993
3480
  files3.push(file);
4994
3481
  }
4995
- this.#mounted.add(at3);
4996
- this.#needs.delete(at3);
3482
+ this.#mounted.add(at);
3483
+ this.#needs.delete(at);
4997
3484
  this.#remount(files3);
4998
- return at3;
3485
+ return at;
4999
3486
  }
5000
3487
  async #eject(path) {
5001
3488
  await this.#clock.sleep();
@@ -5025,29 +3512,29 @@ var DummyMemory = class extends Emitter {
5025
3512
  #next = 1;
5026
3513
  constructor(memories2, scopes = () => [{ id: "global", label: "Everyone" }]) {
5027
3514
  super();
5028
- this.#memories = memories2.map((memory2) => ({ ...memory2 }));
3515
+ this.#memories = memories2.map((memory) => ({ ...memory }));
5029
3516
  this.#scopes = scopes;
5030
3517
  }
5031
3518
  scopes() {
5032
3519
  return this.#scopes();
5033
3520
  }
5034
3521
  list() {
5035
- return this.#memories.map((memory2) => ({ ...memory2 }));
3522
+ return this.#memories.map((memory) => ({ ...memory }));
5036
3523
  }
5037
3524
  save(draft) {
5038
- const memory2 = {
3525
+ const memory = {
5039
3526
  ...draft,
5040
3527
  id: draft.id ?? `mem-new-${this.#next++}`,
5041
3528
  updatedAt: Date.now()
5042
3529
  };
5043
- const index2 = this.#memories.findIndex((candidate) => candidate.id === memory2.id);
5044
- if (index2 < 0) this.#memories.push(memory2);
5045
- else this.#memories[index2] = memory2;
3530
+ const index = this.#memories.findIndex((candidate) => candidate.id === memory.id);
3531
+ if (index < 0) this.#memories.push(memory);
3532
+ else this.#memories[index] = memory;
5046
3533
  this.emit("memories", this.list());
5047
- return { ...memory2 };
3534
+ return { ...memory };
5048
3535
  }
5049
3536
  remove(id) {
5050
- this.#memories = this.#memories.filter((memory2) => memory2.id !== id);
3537
+ this.#memories = this.#memories.filter((memory) => memory.id !== id);
5051
3538
  this.emit("memories", this.list());
5052
3539
  }
5053
3540
  };
@@ -5825,8 +4312,8 @@ var DummyNetwork = class extends Emitter {
5825
4312
  ...device,
5826
4313
  folders: device.folders.map((folder) => {
5827
4314
  const { mounted: _, ...rest } = folder;
5828
- const at3 = mounted2(folder);
5829
- return at3 ? { ...rest, mounted: at3 } : rest;
4315
+ const at = mounted2(folder);
4316
+ return at ? { ...rest, mounted: at } : rest;
5830
4317
  })
5831
4318
  } : device
5832
4319
  );
@@ -6547,9 +5034,9 @@ function packageFixtures(scenario) {
6547
5034
  79e5
6548
5035
  )
6549
5036
  ];
6550
- const at3 = (id) => items.findIndex((item) => item.id === id);
5037
+ const at = (id) => items.findIndex((item) => item.id === id);
6551
5038
  const patch = (id, change) => {
6552
- items[at3(id)] = { ...items[at3(id)], ...change };
5039
+ items[at(id)] = { ...items[at(id)], ...change };
6553
5040
  };
6554
5041
  patch("python", {
6555
5042
  state: "installed",
@@ -7215,6 +5702,8 @@ var DummyVault = class extends Emitter {
7215
5702
  #serial = 0;
7216
5703
  buttons = [];
7217
5704
  puts = [];
5705
+ endpointChanges = [];
5706
+ #refuses;
7218
5707
  cancelled = [];
7219
5708
  imports = [];
7220
5709
  exported = 0;
@@ -7226,6 +5715,16 @@ var DummyVault = class extends Emitter {
7226
5715
  this.#list = { ...list, secrets: [...list.secrets, ...records] };
7227
5716
  this.#time = time;
7228
5717
  this.#available = scenario === "waiting" ? "waiting" : "ready";
5718
+ this.#refuses = scenario === "endpoints-fail";
5719
+ }
5720
+ async endpoints(change) {
5721
+ await this.#time.sleep(5);
5722
+ if (this.#refuses)
5723
+ throw vaultFailure(
5724
+ "EINVAL",
5725
+ "The vault refused that endpoint. Check the address and try again."
5726
+ );
5727
+ this.endpointChanges.push(change);
7229
5728
  }
7230
5729
  status() {
7231
5730
  return this.#available === "waiting" ? null : this.#status;
@@ -7454,6 +5953,13 @@ function vaultAccounts(accounts2) {
7454
5953
  (account) => account.auth === "api-key" || account.id === "github" ? { ...account, store: "vault" } : account
7455
5954
  );
7456
5955
  }
5956
+ function settingsAccounts(accounts2, providers) {
5957
+ const all = accounts2 === "vault" ? vaultAccounts(accounts) : accounts;
5958
+ if (providers === "all") return providerAccounts(all);
5959
+ return all.map(
5960
+ (account) => providers === "none" && account.group !== "mcp" ? { ...account, status: "disconnected", identity: "" } : account
5961
+ );
5962
+ }
7457
5963
  function guestsPort(guests, time) {
7458
5964
  return guests === "off" ? {} : { guests: new DummyGuests(guests, time) };
7459
5965
  }
@@ -7530,14 +6036,13 @@ function createDummyModel({
7530
6036
  settings: new DummySettings(
7531
6037
  defaults,
7532
6038
  providers === "none" ? [...models, ...laterModels] : models,
7533
- (accounts2 === "vault" ? vaultAccounts(accounts) : accounts).map(
7534
- (account) => providers === "none" && account.group !== "mcp" ? { ...account, status: "disconnected", identity: "" } : account
7535
- ),
6039
+ settingsAccounts(accounts2, providers),
7536
6040
  storage,
7537
6041
  time,
7538
6042
  void 0,
7539
6043
  providers === "none",
7540
- login
6044
+ login,
6045
+ providers === "all" ? providerFixtures : void 0
7541
6046
  ),
7542
6047
  memory: new DummyMemory(memories, () => [
7543
6048
  { id: "global", label: "Everyone" },
@@ -7625,6 +6130,9 @@ export {
7625
6130
  pairingCode,
7626
6131
  pairingRefused,
7627
6132
  pairingStopped,
6133
+ providerAccount,
6134
+ providerAccounts,
6135
+ providerFixtures,
7628
6136
  tabsFixtures,
7629
6137
  tailnetFixtures,
7630
6138
  updateFixtures,